Hemos visto en artículos anteriores cómo inicializar un proyecto Symfony 6 + Sonata 5 con multimedia y usuarios en un admin seguro. Luego, analizamos cómo gestionar las localizaciones de usuarios.
Ahora veremos cómo instalar y gestionar clasificaciones.
Procedemos con la instalación de la última versión hasta la fecha.
php8.1 composer.phar require sonata-project/classification-bundle:5.x-dev
Al parecer, tenemos un error de configuración.
Unrecognized option "media" under "sonata_classification.class". Available
!! options are "category", "collection", "context", "tag".
Eliminamos la sección de medios del archivo de configuración sonata_classification.yaml
sonata_classification:
class:
category: App\Entity\SonataClassificationCategory
collection: App\Entity\SonataClassificationCollection
context: App\Entity\SonataClassificationContext
tag: App\Entity\SonataClassificationTag
#media: App\Entity\SonataMediaMedia
Luego nos encontramos con un nuevo error.
PHP Fatal error: Type of App\Entity\SonataClassificationCategory::$children must be Doctrine\Common\Collections\Collection (as in class Sonata\ClassificationBundle\Model\Category) in /src/Entity/SonataClassificationCategory.php on line 18
No es un gran problema; configuraremos todo para que funcione a la primera.
Primero implementaremos nuestras entidades en un directorio distinto a src/app para no llenar nuestra aplicación con las sobrecargas de nuestros bundles. Al igual que con UserBundle y MediaBundle, los colocamos en src/Application/Sonata/ClassificationBundle/Entity y crearemos nuestros 4 archivos.
src/Application/Sonata/ClassificationBundle/Entity/SonataClassificationCategory.php
<?php
declare(strict_types=1);
namespace App\Application\Sonata\ClassificationBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sonata\ClassificationBundle\Entity\BaseCategory;
/**
* @ORM\Entity
* @ORM\Table(name="classification__category")
*/
class SonataClassificationCategory extends BaseCategory
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
protected $id;
public function getId(): ?int
{
return $this->id;
}
}
?>
src/Application/Sonata/ClassificationBundle/Entity/SonataClassificationCollection.php
<?php
declare(strict_types=1);
namespace App\Application\Sonata\ClassificationBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sonata\ClassificationBundle\Entity\BaseCollection;
/**
* @ORM\Entity
* @ORM\Table(name="classification__collection")
*/
class SonataClassificationCollection extends BaseCollection
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
protected $id;
public function getId(): ?int
{
return $this->id;
}
}
?>
src/Application/Sonata/ClassificationBundle/Entity/SonataClassificationContext.php
<?php
declare(strict_types=1);
namespace App\Application\Sonata\ClassificationBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sonata\ClassificationBundle\Entity\BaseContext;
/**
* @ORM\Entity
* @ORM\Table(name="classification__context")
*/
class SonataClassificationContext extends BaseContext
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="string", length=64, nullable=false)
*/
protected ?string $id = null;
public function getId(): ?string
{
return $this->id;
}
}
?>
src/Application/Sonata/ClassificationBundle/Entity/SonataClassificationTag.php
<?php
declare(strict_types=1);
namespace App\Application\Sonata\ClassificationBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sonata\ClassificationBundle\Entity\BaseTag;
/**
* @ORM\Entity
* @ORM\Table(name="classification__tag")
*/
class SonataClassificationTag extends BaseTag
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
protected $id;
public function getId(): ?int
{
return $this->id;
}
}
Luego, necesitamos proporcionar las rutas de nuestras clases en config/packages/sonata_classification.yaml
sonata_classification:
class:
category: App\Application\Sonata\ClassificationBundle\Entity\SonataClassificationCategory
collection: App\Application\Sonata\ClassificationBundle\Entity\SonataClassificationCollection
context: App\Application\Sonata\ClassificationBundle\Entity\SonataClassificationContext
tag: App\Application\Sonata\ClassificationBundle\Entity\SonataClassificationTag
También necesitamos agregar la ruta de la clase de categoría a las definiciones de multimedia en el archivo config/packages/sonata_media.yaml
sonata_media:
class:
media: App\Application\Sonata\MediaBundle\Entity\Media
gallery: App\Application\Sonata\MediaBundle\Entity\Gallery
gallery_item: App\Application\Sonata\MediaBundle\Entity\GalleryItem
category: App\Application\Sonata\ClassificationBundle\Entity\SonataClassificationCategory
Agregamos nuestro bundle en config/packages/doctrine.yaml
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# IMPORTANT: You MUST configure your server version,
# either here or in the DATABASE_URL env var (see .env file)
#server_version: '13'
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
App\Application\Sonata\UserBundle:
is_bundle: false
dir: '%kernel.project_dir%/src/Application/Sonata/UserBundle/Entity'
prefix: 'App\Application\Sonata\UserBundle\Entity'
alias: App\Application\Sonata\UserBundle
App\Application\Sonata\MediaBundle:
is_bundle: false
dir: '%kernel.project_dir%/src/Application/Sonata/MediaBundle/Entity'
prefix: 'App\Application\Sonata\MediaBundle\Entity'
alias: App\Application\Sonata\MediaBundle
App\Application\Sonata\ClassificationBundle:
is_bundle: false
dir: '%kernel.project_dir%/src/Application/Sonata/ClassificationBundle/Entity'
prefix: 'App\Application\Sonata\ClassificationBundle\Entity'
alias: App\Application\Sonata\ClassificationBundle
translatable:
type: annotation # or attribute
alias: Gedmo
prefix: Gedmo\Translatable\Entity
# make sure vendor library location is correct
dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/src/Translatable/Entity"
filters:
softdeleteable:
class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
Creamos el esquema de la base de datos.
php8.1 bin/console doctrine:schema:update --force
![Selection_280 Selection_280](/uploads/media/default/0001/01/62e995f03d27cb82bf08d050876cce2d857bab30.png)
Agregamos nuestras interfaces al admin en el archivo config/packages/sonata_admin.yaml
sonata_admin:
title: Backoffice
title_logo: /bundles/sonataadmin/images/logo_title.png
show_mosaic_button: false
security:
handler: sonata.admin.security.handler.role
options:
default_admin_route: edit
html5_validate: false
global_search:
admin_route: edit
breadcrumbs:
child_admin_route: edit
dashboard:
groups:
runroom:
# label: Base
# items:
# - Runroom\SeoBundle\Admin\MetaInformationAdmin
# - Runroom\BasicPageBundle\Admin\BasicPageAdmin
# - Runroom\TranslationBundle\Admin\TranslationAdmin
# - Runroom\RedirectionBundle\Admin\RedirectAdmin
# - label: Cookies
# route: admin_runroom_cookies_cookiespage_edit
# route_params: { id: 1 }
users:
label: Users
icon: <i class="fa fa-users"></i>
on_top: true
items:
- sonata.user.admin.user
media:
label: Media
icon: <i class="fa fa-photo"></i>
on_top: true
items:
- sonata.media.admin.media
classification:
label: Classification
icon: <i class="fa fa-tags"></i>
items:
- sonata.classification.admin.category
- sonata.classification.admin.tag
- sonata.classification.admin.collection
- sonata.classification.admin.context
Y todo debería funcionar normalmente.
![Selection_285 Selection_285](/uploads/media/default/0001/01/2b1c9cc056f284fad1d1b37f417fd7e410725bb1.png)
Ejecutamos un comando de migración para actualizar todos los elementos con el contexto predeterminado.
Al parecer, no tenemos muchos elementos para migrar en esta etapa.
php8.1 bin/console sonata:classification:fix-context
![Selection_282 Selection_282](/uploads/media/default/0001/01/966cc154e07e65f94aaeb83b3bf958cebb3ae24f.png)