From 56fd7e065854ad86ed4846c160e09b5912ec4aaa Mon Sep 17 00:00:00 2001 From: Jordi Date: Sun, 14 Jun 2020 19:18:20 +0200 Subject: [PATCH] Make SonataEasyExtends optional --- UPGRADE-3.x.md | 12 +- composer.json | 21 +- docs/reference/advanced_configuration.rst | 34 +-- docs/reference/installation.rst | 288 ++++++++++++------ src/Admin/ContextAwareAdmin.php | 2 +- src/DependencyInjection/Configuration.php | 8 +- .../SonataClassificationExtension.php | 83 ++++- tests/Admin/Filter/CategoryFilterTest.php | 6 +- .../AbstractCategoriesBlockServiceTest.php | 12 +- .../AbstractCollectionsBlockServiceTest.php | 12 +- .../Service/AbstractTagsBlockServiceTest.php | 12 +- .../CategoryAdminControllerTest.php | 88 +----- .../DependencyInjection/ConfigurationTest.php | 74 +++++ .../SonataClassificationExtensionTest.php | 124 ++++++++ tests/Fixtures/configuration.yaml | 0 tests/Resources/XliffTest.php | 1 + 16 files changed, 557 insertions(+), 220 deletions(-) create mode 100644 tests/DependencyInjection/ConfigurationTest.php create mode 100644 tests/DependencyInjection/SonataClassificationExtensionTest.php create mode 100644 tests/Fixtures/configuration.yaml diff --git a/UPGRADE-3.x.md b/UPGRADE-3.x.md index 8b3ee4bc..eff85e14 100644 --- a/UPGRADE-3.x.md +++ b/UPGRADE-3.x.md @@ -1,6 +1,14 @@ UPGRADE 3.x =========== +UPGRADE FROM 3.x to 3.x +======================= + +### SonataEasyExtends is deprecated + +Registering `SonataEasyExtendsBundle` bundle is deprecated, it SHOULD NOT be registered. +Register `SonataDoctrineBundle` bundle instead. + UPGRADE FROM 3.1 to 3.2 ======================= @@ -12,6 +20,6 @@ and should be done by overriding `getFormBuilder` instead. ### Tests -All files under the ``Tests`` directory are now correctly handled as internal test classes. -You can't extend them anymore, because they are only loaded when running internal tests. +All files under the ``Tests`` directory are now correctly handled as internal test classes. +You can't extend them anymore, because they are only loaded when running internal tests. More information can be found in the [composer docs](https://getcomposer.org/doc/04-schema.md#autoload-dev). diff --git a/composer.json b/composer.json index 0f91dda0..761811b8 100644 --- a/composer.json +++ b/composer.json @@ -22,10 +22,9 @@ ], "require": { "php": "^7.2", - "cocur/slugify": "^2.0 || ^3.0 || ^4.0", + "cocur/slugify": "^3.0 || ^4.0", "sonata-project/datagrid-bundle": "^2.3 || ^3.0", - "sonata-project/doctrine-extensions": "^1.6.0", - "sonata-project/easy-extends-bundle": "^2.5", + "sonata-project/doctrine-extensions": "^1.8", "sonata-project/form-extensions": "^0.1.1 || ^1.4", "symfony/config": "^4.4", "symfony/console": "^4.4", @@ -39,18 +38,20 @@ "conflict": { "friendsofsymfony/rest-bundle": "<2.1 || >=3.0", "jms/serializer": "<0.13", - "sonata-project/admin-bundle": "<3.59", - "sonata-project/block-bundle": "<3.14 || >=4.0", + "sonata-project/admin-bundle": "<3.68", + "sonata-project/block-bundle": "<3.19 || >=4.0", "sonata-project/core-bundle": "<3.20", - "sonata-project/doctrine-orm-admin-bundle": "<3.4", - "sonata-project/media-bundle": "<3.17 || >=4.0" + "sonata-project/doctrine-orm-admin-bundle": "<3.16", + "sonata-project/media-bundle": "<3.20 || >=4.0" }, "require-dev": { "friendsofsymfony/rest-bundle": "^2.3", "jms/serializer-bundle": "^2.0 || ^3.0", - "sonata-project/admin-bundle": "^3.59", - "sonata-project/block-bundle": "^3.18", - "sonata-project/doctrine-orm-admin-bundle": "^3.4", + "matthiasnoback/symfony-config-test": "^4.0", + "matthiasnoback/symfony-dependency-injection-test": "^4.0", + "sonata-project/admin-bundle": "^3.68", + "sonata-project/block-bundle": "^3.19", + "sonata-project/doctrine-orm-admin-bundle": "^3.16", "sonata-project/media-bundle": "^3.20", "symfony/phpunit-bridge": "^5.1" }, diff --git a/docs/reference/advanced_configuration.rst b/docs/reference/advanced_configuration.rst index 4846f7dc..c45f52dd 100644 --- a/docs/reference/advanced_configuration.rst +++ b/docs/reference/advanced_configuration.rst @@ -10,26 +10,26 @@ Advanced Configuration sonata_classification: class: - tag: Application\Sonata\ClassificationBundle\Entity\Tag - category: Application\Sonata\ClassificationBundle\Entity\Category - collection: Application\Sonata\ClassificationBundle\Entity\Collection - media: Application\Sonata\MediaBundle\Entity\Media - context: Application\Sonata\ClassificationBundle\Entity\Context + tag: App\Entity\SonataClassificationTag + category: App\Entity\SonataClassificationCategory + collection: App\Entity\SonataClassificationCollection + media: App\Entity\SonataMediaMedia + context: App\Entity\SonataClassificationContext admin: tag: - class: Sonata\ClassificationBundle\Admin\TagAdmin - controller: SonataAdminBundle:CRUD - translation: SonataClassificationBundle + class: Sonata\ClassificationBundle\Admin\TagAdmin + controller: SonataAdminBundle:CRUD + translation: SonataClassificationBundle category: - class: Sonata\ClassificationBundle\Admin\CategoryAdmin - controller: SonataClassificationBundle:CategoryAdmin - translation: SonataClassificationBundle + class: Sonata\ClassificationBundle\Admin\CategoryAdmin + controller: SonataClassificationBundle:CategoryAdmin + translation: SonataClassificationBundle collection: - class: Sonata\ClassificationBundle\Admin\CollectionAdmin - controller: SonataAdminBundle:CRUD - translation: SonataClassificationBundle + class: Sonata\ClassificationBundle\Admin\CollectionAdmin + controller: SonataAdminBundle:CRUD + translation: SonataClassificationBundle context: - class: Sonata\ClassificationBundle\Admin\ContextAdmin - controller: SonataAdminBundle:CRUD - translation: SonataClassificationBundle + class: Sonata\ClassificationBundle\Admin\ContextAdmin + controller: SonataAdminBundle:CRUD + translation: SonataClassificationBundle diff --git a/docs/reference/installation.rst b/docs/reference/installation.rst index 2ba7b64d..0ccb01ba 100644 --- a/docs/reference/installation.rst +++ b/docs/reference/installation.rst @@ -1,6 +1,6 @@ .. index:: - single: Introduction - single: AppKernel + single: Installation + single: Configuration Installation ============ @@ -8,19 +8,41 @@ Installation Prerequisites ------------- -PHP 7.1 and Symfony >=3.4 or >= 4.2 are needed to make this bundle work, there are -also some Sonata dependencies that need to be installed and configured beforehand: +PHP ^7.2 and Symfony ^4.4 are needed to make this bundle work, there are +also some Sonata dependencies that need to be installed and configured beforehand. -* `SonataEasyExtendsBundle `_ +Optional dependencies: -Add ``SonataClassificationBundle`` via composer: +* `SonataAdminBundle `_ +* `SonataBlockBundle `_ +* `SonataMediaBundle `_ -.. code-block:: bash +And the persistence bundle (choose one): - composer require sonata-project/classification-bundle +* `SonataDoctrineOrmAdminBundle `_ +* `SonataDoctrineMongoDBAdminBundle `_ -Now, add the new ``SonataClassificationBundle`` to ``bundles.php`` file:: +Follow also their configuration step; you will find everything you need in +their own installation chapter. +.. note:: + + If a dependency is already installed somewhere in your project or in + another dependency, you won't need to install it again. + +Enable the Bundle +----------------- + +Add ``SonataClassificationBundle`` via composer:: + + composer require sonata-project/classification-bundle + +If you want to use the REST API, you also need ``friendsofsymfony/rest-bundle`` and ``nelmio/api-doc-bundle``:: + + composer require friendsofsymfony/rest-bundle nelmio/api-doc-bundle + +Next, be sure to enable the bundles in your ``config/bundles.php`` file if they +are not already enabled:: // config/bundles.php @@ -29,31 +51,27 @@ Now, add the new ``SonataClassificationBundle`` to ``bundles.php`` file:: Sonata\ClassificationBundle\SonataClassificationBundle::class => ['all' => true], ]; -.. note:: - - If you are not using Symfony Flex, you should enable bundles in your - ``AppKernel.php``. +Configuration +============= -.. code-block:: php +SonataClassificationBundle Configuration +---------------------------------------- - // app/AppKernel.php +.. code-block:: yaml - public function registerBundles() - { - return [ - new Sonata\ClassificationBundle\SonataClassificationBundle(), - // ... - ]; - } + # config/packages/sonata_classification.yaml -Configuration -------------- + sonata_classification: + class: + tag: App\Entity\SonataClassificationTag + category: App\Entity\SonataClassificationCategory + collection: App\Entity\SonataClassificationCollection + context: App\Entity\SonataClassificationContext -Doctrine Configuration -~~~~~~~~~~~~~~~~~~~~~~ -Add these bundles in the config mapping definition (or enable `auto_mapping`_): +Doctrine ORM Configuration +-------------------------- -.. code-block:: yaml +Add these bundles in the config mapping definition (or enable `auto_mapping`_):: # config/packages/doctrine.yaml @@ -62,95 +80,193 @@ Add these bundles in the config mapping definition (or enable `auto_mapping`_): entity_managers: default: mappings: - ApplicationSonataClassificationBundle: ~ SonataClassificationBundle: ~ -.. note:: +And then create the corresponding entities, ``src/Entity/SonataClassificationTag``:: - If you are not using Symfony Flex, this configuration should be added - to ``app/config/config.yml``. + // src/Entity/SonataClassificationTag.php -Extending the Bundle --------------------- -At this point, the bundle is functional, but not quite ready yet. You need to -generate the correct entities for the media: + use Doctrine\ORM\Mapping as ORM; + use Sonata\ClassificationBundle\Entity\BaseTag; -.. code-block:: bash + /** + * @ORM\Entity + * @ORM\Table(name="classification__tag") + */ + class SonataClassificationTag extends BaseTag + { + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + protected $id; + } - bin/console sonata:easy-extends:generate SonataClassificationBundle --dest=src --namespace_prefix=App +``src/Entity/SonataClassificationCategory``:: -.. note:: + // src/Entity/SonataClassificationCategory.php - If you are not using Symfony Flex, use command without ``--namespace_prefix=App``. + use Doctrine\ORM\Mapping as ORM; + use Sonata\ClassificationBundle\Entity\BaseCategory; -With provided parameters, the files are generated in ``src/Application/Sonata/ClassificationBundle``. + /** + * @ORM\Entity + * @ORM\Table(name="classification__category") + */ + class SonataClassificationCategory extends BaseCategory + { + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + protected $id; + } -.. note:: +``src/Entity/SonataClassificationCollection``:: - The command will generate domain objects in ``App\Application`` namespace. - So you can point entities' associations to a global and common namespace. - This will make Entities sharing easier as your models will allow to - point to a global namespace. For instance the tag will be - ``App\Application\Sonata\ClassificationBundle\Entity\Tag``. + // src/Entity/SonataClassificationCollection.php -.. note:: + use Doctrine\ORM\Mapping as ORM; + use Sonata\ClassificationBundle\Entity\BaseCollection; - If you are not using Symfony Flex, the namespace will be ``Application\Sonata\ClassificationBundle\Entity``. + /** + * @ORM\Entity + * @ORM\Table(name="classification__collection") + */ + class SonataClassificationCollection extends BaseCollection + { + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + protected $id; + } -Now, add the new ``Application`` Bundle into the ``bundles.php``:: +and ``src/Entity/SonataClassificationContext``:: - // config/bundles.php + // src/Entity/SonataClassificationContext.php - return [ - // ... - App\Application\Sonata\ClassificationBundle\ApplicationSonataClassificationBundle::class => ['all' => true], - ]; + use Doctrine\ORM\Mapping as ORM; + use Sonata\ClassificationBundle\Entity\BaseContext; -.. note:: + /** + * @ORM\Entity + * @ORM\Table(name="classification__context") + */ + class SonataClassificationContext extends BaseContext + { + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + protected $id; + } + +The only thing left is to update your schema:: + + bin/console doctrine:schema:update --force - If you are not using Symfony Flex, add the new ``Application`` Bundle into your - ``AppKernel.php``. +Doctrine MongoDB Configuration +------------------------------ -.. code-block:: php +You have to create the corresponding documents, ``src/Document/SonataClassificationTag``:: - // app/AppKernel.php + // src/Document/SonataClassificationTag.php - class AppKernel { + use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; + use Sonata\ClassificationBundle\Document\BaseTag; - public function registerBundles() - { - return [ - // Application Bundles - // ... - new Application\Sonata\ClassificationBundle\ApplicationSonataClassificationBundle(), - // ... - ]; - } + /** + * @MongoDB\Document + */ + class SonataClassificationTag extends BaseTag + { + /** + * @MongoDB\Id + */ + protected $id; } -And configure ``ClassificationBundle`` to use the newly generated classes: +``src/Document/SonataClassificationCategory``:: -.. code-block:: yaml + // src/Document/SonataClassificationCategory.php - # config/packages/sonata.yaml + use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; + use Sonata\ClassificationBundle\Document\BaseCategory; - sonata_classification: - class: - tag: App\Application\Sonata\ClassificationBundle\Entity\Tag - category: App\Application\Sonata\ClassificationBundle\Entity\Category - collection: App\Application\Sonata\ClassificationBundle\Entity\Collection - context: App\Application\Sonata\ClassificationBundle\Entity\Context + /** + * @MongoDB\Document + */ + class SonataClassificationCategory extends BaseCategory + { + /** + * @MongoDB\Id + */ + protected $id; + } +``src/Document/SonataClassificationCollection``:: -.. note:: + // src/Document/SonataClassificationCollection.php - If you are not using Symfony Flex, add classes without the ``App\`` - part and this configuration should be added to ``app/config/config.yml`` + use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; + use Sonata\ClassificationBundle\Document\BaseCollection; -The only thing left is to update your schema: + /** + * @MongoDB\Document + */ + class SonataClassificationCollection extends BaseCollection + { + /** + * @MongoDB\Id + */ + protected $id; + } -.. code-block:: bash +and ``src/Document/SonataClassificationContext``:: - bin/console doctrine:schema:update --force + // src/Document/SonataClassificationContext.php + + use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB; + use Sonata\ClassificationBundle\Document\BaseContext; + + /** + * @MongoDB\Document + */ + class SonataClassificationContext extends BaseContext + { + /** + * @MongoDB\Id + */ + protected $id; + } + +And then configure ``ClassificationBundle`` to use the newly generated classes:: + + # config/packages/sonata_classification.yaml + + sonata_classification: + class: + tag: App\Document\SonataClassificationTag + category: App\Document\SonataClassificationCategory + collection: App\Document\SonataClassificationCollection + context: App\Document\SonataClassificationContext + +Next Steps +---------- + +At this point, your Symfony installation should be fully functional, without errors +showing up from SonataClassificationBundle. If, at this point or during the installation, +you come across any errors, don't panic: + + - Read the error message carefully. Try to find out exactly which bundle is causing the error. + Is it SonataClassificationBundle or one of the dependencies? + - Make sure you followed all the instructions correctly, for both SonataClassificationBundle and its dependencies. + - Still no luck? Try checking the project's `open issues on GitHub`_. -.. _`auto_mapping`: http://symfony.com/doc/2.0/reference/configuration/doctrine.html#configuration-overview +.. _`open issues on GitHub`: https://github.com/sonata-project/SonataClassificationBundle/issues +.. _`auto_mapping`: http://symfony.com/doc/4.4/reference/configuration/doctrine.html#configuration-overviews diff --git a/src/Admin/ContextAwareAdmin.php b/src/Admin/ContextAwareAdmin.php index dbbde6d9..9d1fd47c 100644 --- a/src/Admin/ContextAwareAdmin.php +++ b/src/Admin/ContextAwareAdmin.php @@ -70,7 +70,7 @@ public function getPersistentParameters() ] ); - if ($this->getSubject()) { + if ($this->hasSubject()) { $parameters['context'] = $this->getSubject()->getContext() ? $this->getSubject()->getContext()->getId() : ''; return $parameters; diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 390b204d..b3e8fc05 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -26,13 +26,7 @@ class Configuration implements ConfigurationInterface public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder('sonata_classification'); - - // Keep compatibility with symfony/config < 4.2 - if (!method_exists($treeBuilder, 'getRootNode')) { - $rootNode = $treeBuilder->root('sonata_classification'); - } else { - $rootNode = $treeBuilder->getRootNode(); - } + $rootNode = $treeBuilder->getRootNode(); $rootNode ->children() diff --git a/src/DependencyInjection/SonataClassificationExtension.php b/src/DependencyInjection/SonataClassificationExtension.php index 4983a745..7dbfe859 100644 --- a/src/DependencyInjection/SonataClassificationExtension.php +++ b/src/DependencyInjection/SonataClassificationExtension.php @@ -13,7 +13,9 @@ namespace Sonata\ClassificationBundle\DependencyInjection; -use Sonata\EasyExtendsBundle\Mapper\DoctrineCollector; +use Sonata\Doctrine\Mapper\Builder\OptionsBuilder; +use Sonata\Doctrine\Mapper\DoctrineCollector; +use Sonata\EasyExtendsBundle\Mapper\DoctrineCollector as DeprecatedDoctrineCollector; use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -52,7 +54,13 @@ public function load(array $configs, ContainerBuilder $container) $loader->load('admin.xml'); } - $this->registerDoctrineMapping($config); + if (isset($bundles['SonataDoctrineBundle'])) { + $this->registerSonataDoctrineMapping($config); + } else { + // NEXT MAJOR: Remove next line and throw error when not registering SonataDoctrineBundle + $this->registerDoctrineMapping($config); + } + $this->configureClass($config, $container); $this->configureAdmin($config, $container); } @@ -97,15 +105,23 @@ public function configureAdmin($config, ContainerBuilder $container) $container->setParameter('sonata.classification.admin.context.translation_domain', $config['admin']['context']['translation']); } + /** + * NEXT_MAJOR: Remove this method. + */ public function registerDoctrineMapping(array $config) { + @trigger_error( + 'Using SonataEasyExtendsBundle is deprecated since sonata-project/classification-bundle 3.x. Please register SonataDoctrineBundle as a bundle instead.', + E_USER_DEPRECATED + ); + foreach ($config['class'] as $type => $class) { if ('media' !== $type && !class_exists($class)) { return; } } - $collector = DoctrineCollector::getInstance(); + $collector = DeprecatedDoctrineCollector::getInstance(); $collector->addAssociation($config['class']['category'], 'mapOneToMany', [ 'fieldName' => 'children', @@ -234,4 +250,65 @@ public function registerDoctrineMapping(array $config) ]); } } + + private function registerSonataDoctrineMapping(array $config): void + { + foreach ($config['class'] as $type => $class) { + if ('media' !== $type && !class_exists($class)) { + return; + } + } + + $collector = DoctrineCollector::getInstance(); + + $collector->addAssociation( + $config['class']['category'], + 'mapOneToMany', + OptionsBuilder::createOneToMany('children', $config['class']['category']) + ->cascade(['persist']) + ->mappedBy('parent') + ->orphanRemoval() + ->addOrder('position', 'ASC') + ); + + $collector->addAssociation( + $config['class']['category'], + 'mapManyToOne', + OptionsBuilder::createManyToOne('parent', $config['class']['category']) + ->cascade(['persist', 'refresh', 'merge', 'detach']) + ->inversedBy('children') + ->addJoin([ + 'name' => 'parent_id', + 'referencedColumnName' => 'id', + 'onDelete' => 'CASCADE', + ]) + ); + + $contextOptions = OptionsBuilder::createManyToOne('context', $config['class']['context']) + ->cascade(['persist']) + ->addJoin([ + 'name' => 'context', + 'referencedColumnName' => 'id', + ]); + + $collector->addAssociation($config['class']['category'], 'mapManyToOne', $contextOptions); + $collector->addAssociation($config['class']['tag'], 'mapManyToOne', $contextOptions); + $collector->addAssociation($config['class']['collection'], 'mapManyToOne', $contextOptions); + + $collector->addUnique($config['class']['tag'], 'tag_context', ['slug', 'context']); + $collector->addUnique($config['class']['collection'], 'tag_collection', ['slug', 'context']); + + if (null !== $config['class']['media']) { + $mediaOptions = OptionsBuilder::createManyToOne('media', $config['class']['media']) + ->cascade(['persist']) + ->addJoin([ + 'name' => 'media_id', + 'referencedColumnName' => 'id', + 'onDelete' => 'SET NULL', + ]); + + $collector->addAssociation($config['class']['collection'], 'mapManyToOne', $mediaOptions); + $collector->addAssociation($config['class']['category'], 'mapManyToOne', $mediaOptions); + } + } } diff --git a/tests/Admin/Filter/CategoryFilterTest.php b/tests/Admin/Filter/CategoryFilterTest.php index a4bccd3b..bb003ee3 100644 --- a/tests/Admin/Filter/CategoryFilterTest.php +++ b/tests/Admin/Filter/CategoryFilterTest.php @@ -15,19 +15,19 @@ use PHPUnit\Framework\TestCase; use Sonata\ClassificationBundle\Admin\Filter\CategoryFilter; -use Sonata\ClassificationBundle\Model\CategoryManagerInterface; +use Sonata\ClassificationBundle\Entity\CategoryManager; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; class CategoryFilterTest extends TestCase { /** - * @var MockObject&CategoryManagerInterface + * @var MockObject&CategoryManager */ private $categoryManager; protected function setUp(): void { - $this->categoryManager = $this->createStub(CategoryManagerInterface::class); + $this->categoryManager = $this->createStub(CategoryManager::class); } public function testRenderSettings(): void diff --git a/tests/Block/Service/AbstractCategoriesBlockServiceTest.php b/tests/Block/Service/AbstractCategoriesBlockServiceTest.php index 3c43bf8f..7c41484b 100644 --- a/tests/Block/Service/AbstractCategoriesBlockServiceTest.php +++ b/tests/Block/Service/AbstractCategoriesBlockServiceTest.php @@ -15,12 +15,12 @@ use Sonata\BlockBundle\Model\BlockInterface; use Sonata\BlockBundle\Test\BlockServiceTestCase; -use Sonata\BlockBundle\Test\FakeTemplating; use Sonata\ClassificationBundle\Admin\CategoryAdmin; use Sonata\ClassificationBundle\Block\Service\AbstractCategoriesBlockService; use Sonata\ClassificationBundle\Model\CategoryInterface; use Sonata\ClassificationBundle\Model\CategoryManagerInterface; use Sonata\ClassificationBundle\Model\ContextManagerInterface; +use Twig\Environment; /** * @author Christian Gripp @@ -46,7 +46,7 @@ protected function setUp(): void { parent::setUp(); - $this->templating = new FakeTemplating(); + $this->twig = $this->createMock(Environment::class); $this->contextManager = $this->createMock(ContextManagerInterface::class); $this->categoryManager = $this->createMock(CategoryManagerInterface::class); $this->categoryAdmin = $this->createMock(CategoryAdmin::class); @@ -55,7 +55,7 @@ protected function setUp(): void public function testDefaultSettings(): void { $blockService = $this->getMockForAbstractClass(AbstractCategoriesBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->categoryManager, $this->categoryAdmin, + $this->twig, $this->contextManager, $this->categoryManager, $this->categoryAdmin, ]); $blockContext = $this->getBlockContext($blockService); @@ -94,7 +94,7 @@ public function testLoad(): void ->with($this->equalTo('categoryId'), $this->equalTo($category)); $blockService = $this->getMockForAbstractClass(AbstractCategoriesBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->categoryManager, $this->categoryAdmin, + $this->twig, $this->contextManager, $this->categoryManager, $this->categoryAdmin, ]); $blockService->load($block); } @@ -117,7 +117,7 @@ public function testPrePersist(): void ->with($this->equalTo('categoryId'), $this->equalTo(23)); $blockService = $this->getMockForAbstractClass(AbstractCategoriesBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->categoryManager, $this->categoryAdmin, + $this->twig, $this->contextManager, $this->categoryManager, $this->categoryAdmin, ]); $blockService->prePersist($block); } @@ -140,7 +140,7 @@ public function testPreUpdate(): void ->with($this->equalTo('categoryId'), $this->equalTo(23)); $blockService = $this->getMockForAbstractClass(AbstractCategoriesBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->categoryManager, $this->categoryAdmin, + $this->twig, $this->contextManager, $this->categoryManager, $this->categoryAdmin, ]); $blockService->preUpdate($block); } diff --git a/tests/Block/Service/AbstractCollectionsBlockServiceTest.php b/tests/Block/Service/AbstractCollectionsBlockServiceTest.php index 73abfa40..a211dd51 100644 --- a/tests/Block/Service/AbstractCollectionsBlockServiceTest.php +++ b/tests/Block/Service/AbstractCollectionsBlockServiceTest.php @@ -15,12 +15,12 @@ use Sonata\BlockBundle\Model\BlockInterface; use Sonata\BlockBundle\Test\BlockServiceTestCase; -use Sonata\BlockBundle\Test\FakeTemplating; use Sonata\ClassificationBundle\Admin\CollectionAdmin; use Sonata\ClassificationBundle\Block\Service\AbstractCollectionsBlockService; use Sonata\ClassificationBundle\Model\CollectionInterface; use Sonata\ClassificationBundle\Model\CollectionManagerInterface; use Sonata\ClassificationBundle\Model\ContextManagerInterface; +use Twig\Environment; /** * @author Christian Gripp @@ -46,7 +46,7 @@ protected function setUp(): void { parent::setUp(); - $this->templating = new FakeTemplating(); + $this->twig = $this->createMock(Environment::class); $this->contextManager = $this->createMock(ContextManagerInterface::class); $this->collectionManager = $this->createMock(CollectionManagerInterface::class); $this->collectionAdmin = $this->createMock(CollectionAdmin::class); @@ -55,7 +55,7 @@ protected function setUp(): void public function testDefaultSettings(): void { $blockService = $this->getMockForAbstractClass(AbstractCollectionsBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->collectionManager, $this->collectionAdmin, + $this->twig, $this->contextManager, $this->collectionManager, $this->collectionAdmin, ]); $blockContext = $this->getBlockContext($blockService); @@ -94,7 +94,7 @@ public function testLoad(): void ->with($this->equalTo('collectionId'), $this->equalTo($collection)); $blockService = $this->getMockForAbstractClass(AbstractCollectionsBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->collectionManager, $this->collectionAdmin, + $this->twig, $this->contextManager, $this->collectionManager, $this->collectionAdmin, ]); $blockService->load($block); } @@ -117,7 +117,7 @@ public function testPrePersist(): void ->with($this->equalTo('collectionId'), $this->equalTo(23)); $blockService = $this->getMockForAbstractClass(AbstractCollectionsBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->collectionManager, $this->collectionAdmin, + $this->twig, $this->contextManager, $this->collectionManager, $this->collectionAdmin, ]); $blockService->prePersist($block); } @@ -140,7 +140,7 @@ public function testPreUpdate(): void ->with($this->equalTo('collectionId'), $this->equalTo(23)); $blockService = $this->getMockForAbstractClass(AbstractCollectionsBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->collectionManager, $this->collectionAdmin, + $this->twig, $this->contextManager, $this->collectionManager, $this->collectionAdmin, ]); $blockService->preUpdate($block); } diff --git a/tests/Block/Service/AbstractTagsBlockServiceTest.php b/tests/Block/Service/AbstractTagsBlockServiceTest.php index d3072c22..2bdc3721 100644 --- a/tests/Block/Service/AbstractTagsBlockServiceTest.php +++ b/tests/Block/Service/AbstractTagsBlockServiceTest.php @@ -15,12 +15,12 @@ use Sonata\BlockBundle\Model\BlockInterface; use Sonata\BlockBundle\Test\BlockServiceTestCase; -use Sonata\BlockBundle\Test\FakeTemplating; use Sonata\ClassificationBundle\Admin\TagAdmin; use Sonata\ClassificationBundle\Block\Service\AbstractTagsBlockService; use Sonata\ClassificationBundle\Model\ContextManagerInterface; use Sonata\ClassificationBundle\Model\TagInterface; use Sonata\ClassificationBundle\Model\TagManagerInterface; +use Twig\Environment; /** * @author Christian Gripp @@ -46,7 +46,7 @@ protected function setUp(): void { parent::setUp(); - $this->templating = new FakeTemplating(); + $this->twig = $this->createMock(Environment::class); $this->contextManager = $this->createMock(ContextManagerInterface::class); $this->tagManager = $this->createMock(TagManagerInterface::class); $this->tagAdmin = $this->createMock(TagAdmin::class); @@ -55,7 +55,7 @@ protected function setUp(): void public function testDefaultSettings(): void { $blockService = $this->getMockForAbstractClass(AbstractTagsBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->tagManager, $this->tagAdmin, + $this->twig, $this->contextManager, $this->tagManager, $this->tagAdmin, ]); $blockContext = $this->getBlockContext($blockService); @@ -94,7 +94,7 @@ public function testLoad(): void ->with($this->equalTo('tagId'), $this->equalTo($tag)); $blockService = $this->getMockForAbstractClass(AbstractTagsBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->tagManager, $this->tagAdmin, + $this->twig, $this->contextManager, $this->tagManager, $this->tagAdmin, ]); $blockService->load($block); } @@ -117,7 +117,7 @@ public function testPrePersist(): void ->with($this->equalTo('tagId'), $this->equalTo(23)); $blockService = $this->getMockForAbstractClass(AbstractTagsBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->tagManager, $this->tagAdmin, + $this->twig, $this->contextManager, $this->tagManager, $this->tagAdmin, ]); $blockService->prePersist($block); } @@ -140,7 +140,7 @@ public function testPreUpdate(): void ->with($this->equalTo('tagId'), $this->equalTo(23)); $blockService = $this->getMockForAbstractClass(AbstractTagsBlockService::class, [ - 'block.service', $this->templating, $this->contextManager, $this->tagManager, $this->tagAdmin, + $this->twig, $this->contextManager, $this->tagManager, $this->tagAdmin, ]); $blockService->preUpdate($block); } diff --git a/tests/Controller/CategoryAdminControllerTest.php b/tests/Controller/CategoryAdminControllerTest.php index 7a19e03c..4a0c5475 100644 --- a/tests/Controller/CategoryAdminControllerTest.php +++ b/tests/Controller/CategoryAdminControllerTest.php @@ -26,7 +26,6 @@ use Sonata\ClassificationBundle\Model\CategoryManagerInterface; use Sonata\ClassificationBundle\Model\ContextInterface; use Sonata\ClassificationBundle\Model\ContextManagerInterface; -use Symfony\Bundle\FrameworkBundle\Templating\DelegatingEngine; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormRenderer; @@ -37,6 +36,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; +use Twig\Environment; /** * @author Dariusz Markowicz @@ -104,6 +104,10 @@ class CategoryAdminControllerTest extends TestCase protected function setUp(): void { $this->container = $this->createMock(ContainerInterface::class); + $this->csrfProvider = $this->createMock(CsrfTokenManagerInterface::class); + $this->admin = $this->createMock(CategoryAdmin::class); + $this->categoryManager = $this->createMock(CategoryManager::class); + $this->contextManager = $this->createMock(ContextManager::class); $this->request = new Request(); $this->requestStack = new RequestStack(); @@ -113,51 +117,14 @@ protected function setUp(): void $this->request->attributes->set('_sonata_admin', 'foo.admin'); $this->parameters = []; $this->template = ''; - // php 5.3 BC - $params = &$this->parameters; - $template = &$this->template; - - $templating = $this->getMockBuilder(DelegatingEngine::class) - ->setMethods([]) - ->setConstructorArgs([$this->container, []]) - ->getMock(); - - $templating->expects($this->any()) - ->method('renderResponse') - ->willReturnCallback(static function ( - $view, - array $parameters = [], - ?Response $response = null - ) use ( - &$params, - &$template - ) { - $template = $view; - - if (null === $response) { - $response = new Response(); - } - - $params = $parameters; - - return $response; - }); - - // php 5.3 BC - $pool = $this->pool; - $request = $this->request; - $requestStack = $this->requestStack; - - $twig = $this->createMock(\Twig_Environment::class); + $twig = $this->createMock(Environment::class); $formRenderer = $this->createMock(FormRenderer::class); $twig->expects($this->any()) ->method('getRuntime') ->willReturn($formRenderer); - $this->csrfProvider = $this->createMock(CsrfTokenManagerInterface::class); - $this->csrfProvider->expects($this->any()) ->method('getToken') ->willReturnCallback(static function ($intention) { @@ -174,56 +141,31 @@ protected function setUp(): void return false; }); - // php 5.3 BC - $csrfProvider = $this->csrfProvider; - - $this->admin = $this->createMock(CategoryAdmin::class); - $this->admin->expects($this->any()) ->method('getCode') ->willReturn('admin_code'); - $admin = $this->admin; - - $this->categoryManager = $this->createMock(CategoryManager::class); - $categoryManager = $this->categoryManager; - - $this->contextManager = $this->createMock(ContextManager::class); - $contextManager = $this->contextManager; - $this->container->expects($this->any()) ->method('get') - ->willReturnCallback(static function ($id) use ( - $pool, - $admin, - $request, - $requestStack, - $templating, - $twig, - $csrfProvider, - $categoryManager, - $contextManager - ) { + ->willReturnCallback(function ($id) use ($twig) { switch ($id) { case 'sonata.admin.pool': - return $pool; + return $this->pool; case 'request': - return $request; + return $this->request; case 'request_stack': - return $requestStack; + return $this->requestStack; case 'foo.admin': - return $admin; - case 'templating': - return $templating; + return $this->admin; case 'twig': return $twig; case 'form.csrf_provider': case 'security.csrf.token_manager': - return $csrfProvider; + return $this->csrfProvider; case 'sonata.classification.manager.category': - return $categoryManager; + return $this->categoryManager; case 'sonata.classification.manager.context': - return $contextManager; + return $this->contextManager; case 'admin_code.template_registry': return new TemplateRegistry(); } @@ -239,7 +181,7 @@ protected function setUp(): void return true; } - if ('templating' === $id) { + if ('twig' === $id) { return true; } diff --git a/tests/DependencyInjection/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php new file mode 100644 index 00000000..22df47e6 --- /dev/null +++ b/tests/DependencyInjection/ConfigurationTest.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\ClassificationBundle\Tests\DependencyInjection; + +use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionConfigurationTestCase; +use Sonata\ClassificationBundle\Admin\CategoryAdmin; +use Sonata\ClassificationBundle\Admin\CollectionAdmin; +use Sonata\ClassificationBundle\Admin\ContextAdmin; +use Sonata\ClassificationBundle\Admin\TagAdmin; +use Sonata\ClassificationBundle\DependencyInjection\Configuration; +use Sonata\ClassificationBundle\DependencyInjection\SonataClassificationExtension; +use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; + +final class ConfigurationTest extends AbstractExtensionConfigurationTestCase +{ + public function testDefault(): void + { + $this->assertProcessedConfigurationEquals([ + 'class' => [ + 'category' => 'Application\Sonata\ClassificationBundle\Entity\Category', + 'tag' => 'Application\Sonata\ClassificationBundle\Entity\Tag', + 'media' => null, + 'collection' => 'Application\Sonata\ClassificationBundle\Entity\Collection', + 'context' => 'Application\Sonata\ClassificationBundle\Entity\Context', + ], + 'admin' => [ + 'category' => [ + 'class' => CategoryAdmin::class, + 'controller' => 'SonataClassificationBundle:CategoryAdmin', + 'translation' => 'SonataClassificationBundle', + ], + 'tag' => [ + 'class' => TagAdmin::class, + 'controller' => 'SonataAdminBundle:CRUD', + 'translation' => 'SonataClassificationBundle', + ], + 'collection' => [ + 'class' => CollectionAdmin::class, + 'controller' => 'SonataAdminBundle:CRUD', + 'translation' => 'SonataClassificationBundle', + ], + 'context' => [ + 'class' => ContextAdmin::class, + 'controller' => 'SonataAdminBundle:CRUD', + 'translation' => 'SonataClassificationBundle', + ], + ], + ], [ + __DIR__.'/../Fixtures/configuration.yaml', + ]); + } + + protected function getContainerExtension(): ExtensionInterface + { + return new SonataClassificationExtension(); + } + + protected function getConfiguration(): ConfigurationInterface + { + return new Configuration(); + } +} diff --git a/tests/DependencyInjection/SonataClassificationExtensionTest.php b/tests/DependencyInjection/SonataClassificationExtensionTest.php new file mode 100644 index 00000000..7b168915 --- /dev/null +++ b/tests/DependencyInjection/SonataClassificationExtensionTest.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Sonata\ClassificationBundle\Tests\DependencyInjection; + +use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase; +use Sonata\ClassificationBundle\Admin\CategoryAdmin; +use Sonata\ClassificationBundle\Admin\CollectionAdmin; +use Sonata\ClassificationBundle\Admin\ContextAdmin; +use Sonata\ClassificationBundle\Admin\Filter\CategoryFilter; +use Sonata\ClassificationBundle\Admin\Filter\CollectionFilter; +use Sonata\ClassificationBundle\Admin\TagAdmin; +use Sonata\ClassificationBundle\Command\FixContextCommand; +use Sonata\ClassificationBundle\Controller\Api\CategoryController; +use Sonata\ClassificationBundle\Controller\Api\CollectionController; +use Sonata\ClassificationBundle\Controller\Api\ContextController; +use Sonata\ClassificationBundle\Controller\Api\TagController; +use Sonata\ClassificationBundle\DependencyInjection\SonataClassificationExtension; +use Sonata\ClassificationBundle\Entity\CategoryManager; +use Sonata\ClassificationBundle\Entity\CollectionManager; +use Sonata\ClassificationBundle\Entity\ContextManager; +use Sonata\ClassificationBundle\Entity\TagManager; +use Sonata\ClassificationBundle\Form\Type\ApiCategoryType; +use Sonata\ClassificationBundle\Form\Type\ApiCollectionType; +use Sonata\ClassificationBundle\Form\Type\ApiContextType; +use Sonata\ClassificationBundle\Form\Type\ApiTagType; +use Sonata\ClassificationBundle\Form\Type\CategorySelectorType; +use Sonata\ClassificationBundle\Model\CategoryManagerInterface; +use Sonata\ClassificationBundle\Model\CollectionManagerInterface; +use Sonata\ClassificationBundle\Model\ContextManagerInterface; +use Sonata\ClassificationBundle\Model\TagManagerInterface; +use Sonata\ClassificationBundle\Serializer\CategorySerializerHandler; +use Sonata\ClassificationBundle\Serializer\CollectionSerializerHandler; +use Sonata\ClassificationBundle\Serializer\ContextSerializerHandler; +use Sonata\ClassificationBundle\Serializer\TagSerializerHandler; + +final class SonataClassificationExtensionTest extends AbstractExtensionTestCase +{ + protected function setUp(): void + { + parent::setUp(); + $this->container->setParameter('kernel.bundles', [ + 'SonataDoctrineBundle' => true, + 'SonataAdminBundle' => true, + 'FOSRestBundle' => true, + 'NelmioApiDocBundle' => true, + ]); + } + + public function testLoadDefault(): void + { + $this->load(); + + $this->assertContainerBuilderHasService('sonata.classification.admin.category', CategoryAdmin::class); + $this->assertContainerBuilderHasService('sonata.classification.admin.tag', TagAdmin::class); + $this->assertContainerBuilderHasService('sonata.classification.admin.collection', CollectionAdmin::class); + $this->assertContainerBuilderHasService('sonata.classification.admin.context', ContextAdmin::class); + $this->assertContainerBuilderHasService(CategoryFilter::class); + $this->assertContainerBuilderHasService(CollectionFilter::class); + $this->assertContainerBuilderHasService('sonata.classification.controller.api.category', CategoryController::class); + $this->assertContainerBuilderHasService('sonata.classification.controller.api.collection', CollectionController::class); + $this->assertContainerBuilderHasService('sonata.classification.controller.api.tag', TagController::class); + $this->assertContainerBuilderHasService('sonata.classification.controller.api.context', ContextController::class); + $this->assertContainerBuilderHasService('sonata.classification.api.form.type.category', ApiCategoryType::class); + $this->assertContainerBuilderHasService('sonata.classification.api.form.type.collection', ApiCollectionType::class); + $this->assertContainerBuilderHasService('sonata.classification.api.form.type.tag', ApiTagType::class); + $this->assertContainerBuilderHasService('sonata.classification.api.form.type.context', ApiContextType::class); + $this->assertContainerBuilderHasService(FixContextCommand::class); + $this->assertContainerBuilderHasService('sonata.classification.form.type.category_selector', CategorySelectorType::class); + $this->assertContainerBuilderHasService('sonata.classification.manager.category', CategoryManager::class); + $this->assertContainerBuilderHasService('sonata.classification.manager.tag', TagManager::class); + $this->assertContainerBuilderHasService('sonata.classification.manager.collection', CollectionManager::class); + $this->assertContainerBuilderHasService('sonata.classification.manager.context', ContextManager::class); + $this->assertContainerBuilderHasService(CategoryManagerInterface::class); + $this->assertContainerBuilderHasService(TagManagerInterface::class); + $this->assertContainerBuilderHasService(CollectionManagerInterface::class); + $this->assertContainerBuilderHasService(ContextManagerInterface::class); + $this->assertContainerBuilderHasService('sonata.classification.serializer.handler.category', CategorySerializerHandler::class); + $this->assertContainerBuilderHasService('sonata.classification.serializer.handler.collection', CollectionSerializerHandler::class); + $this->assertContainerBuilderHasService('sonata.classification.serializer.handler.tag', TagSerializerHandler::class); + $this->assertContainerBuilderHasService('sonata.classification.serializer.handler.context', ContextSerializerHandler::class); + + $this->assertContainerBuilderHasParameter('sonata.classification.admin.category.entity', 'Application\Sonata\ClassificationBundle\Entity\Category'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.category.class', CategoryAdmin::class); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.category.controller', 'SonataClassificationBundle:CategoryAdmin'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.category.translation_domain', 'SonataClassificationBundle'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.tag.entity', 'Application\Sonata\ClassificationBundle\Entity\Tag'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.tag.class', TagAdmin::class); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.tag.controller', 'SonataAdminBundle:CRUD'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.tag.translation_domain', 'SonataClassificationBundle'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.collection.entity', 'Application\Sonata\ClassificationBundle\Entity\Collection'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.collection.class', CollectionAdmin::class); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.collection.controller', 'SonataAdminBundle:CRUD'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.collection.translation_domain', 'SonataClassificationBundle'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.context.entity', 'Application\Sonata\ClassificationBundle\Entity\Context'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.context.class', ContextAdmin::class); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.context.controller', 'SonataAdminBundle:CRUD'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.context.translation_domain', 'SonataClassificationBundle'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.groupname', 'sonata_classification'); + $this->assertContainerBuilderHasParameter('sonata.classification.admin.groupicon', ""); + + $this->assertContainerBuilderHasParameter('sonata.classification.manager.category.class', CategoryManager::class); + $this->assertContainerBuilderHasParameter('sonata.classification.manager.tag.class', TagManager::class); + $this->assertContainerBuilderHasParameter('sonata.classification.manager.collection.class', CollectionManager::class); + $this->assertContainerBuilderHasParameter('sonata.classification.manager.context.class', ContextManager::class); + } + + protected function getContainerExtensions(): array + { + return [ + new SonataClassificationExtension(), + ]; + } +} diff --git a/tests/Fixtures/configuration.yaml b/tests/Fixtures/configuration.yaml new file mode 100644 index 00000000..e69de29b diff --git a/tests/Resources/XliffTest.php b/tests/Resources/XliffTest.php index e613b604..60025f04 100644 --- a/tests/Resources/XliffTest.php +++ b/tests/Resources/XliffTest.php @@ -36,6 +36,7 @@ protected function setUp(): void /** * @dataProvider getXliffPaths + * @doesNotPerformAssertions */ public function testXliff($path) {