├── CHANGELOG.md ├── DependencyInjection ├── Compiler │ └── ValidateExtensionConfigurationPass.php ├── Configuration.php └── StofDoctrineExtensionsExtension.php ├── Dockerfile ├── EventListener ├── BlameListener.php ├── LocaleListener.php └── LoggerListener.php ├── LICENSE ├── README.md ├── Resources ├── config │ ├── blameable.xml │ ├── loggable.xml │ ├── reference_integrity.xml │ ├── sluggable.xml │ ├── softdeleteable.xml │ ├── sortable.xml │ ├── timestampable.xml │ ├── translatable.xml │ ├── tree.xml │ └── uploadable.xml └── doc │ ├── advanced.rst │ ├── configuration.rst │ ├── index.rst │ ├── installation.rst │ ├── softdeleteable-filter.rst │ └── uploadable-extension.rst ├── StofDoctrineExtensionsBundle.php ├── Uploadable ├── MimeTypeGuesserAdapter.php ├── UploadableManager.php ├── UploadedFileInfo.php └── ValidatorConfigurator.php ├── composer.json ├── docker-compose.tests.yml └── docker-compose.yml /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.4.3 (2020-12-12) 2 | 3 | Features: 4 | 5 | * PHP 8 support 6 | * Doctrine 3 support 7 | 8 | Bugfixes: 9 | 10 | * Fixed uploadable extension 11 | 12 | ## 1.4.2 (2019-12-4) 13 | 14 | Bugfixes: 15 | 16 | * Fixed crashes in Windows on invalid directory name 17 | 18 | ## 1.4.1 (2019-11-27) 19 | 20 | Features: 21 | 22 | * Symfony 5 support 23 | * Removed PHP 5 and Symfony 2 & 3 support 24 | 25 | Bugfixes: 26 | 27 | * Deprecation fixes 28 | 29 | ## 1.4.0 (2019-08-07) 30 | 31 | Features: 32 | 33 | * Added docker 34 | 35 | Bugfixes: 36 | 37 | * Fixed deprecations by Symfony 4.2 38 | * Fixed Travis builds 39 | 40 | ## 1.3.0 (2017-12-24) 41 | 42 | Features: 43 | 44 | * Added support for Symfony 4 45 | * Added autowiring support for `Stof\DoctrineExtensionsBundle\Uploadable\UploadableManager` 46 | 47 | Bugfixes: 48 | 49 | * Fixed usage of loggable and soft-deleteable together to ensure soft-deletions are logged 50 | * Removed the logic running on bundle boot to avoid overhead 51 | 52 | Removed: 53 | 54 | * Dropped support for unmaintained versions of Symfony 55 | 56 | ## 1.2.2 (2016-01-27) 57 | 58 | * Added support for Symfony 3 59 | 60 | ## 1.2.1 (2015-08-12) 61 | 62 | * Fixed the BlameListener 63 | 64 | ## 1.2.0 (2015-08-12) 65 | 66 | Bugfixes: 67 | 68 | * Fixed the handling of the directory validation of the uploadable extension 69 | * Removed usage of APIs deprecated in Symfony 2.6+ 70 | 71 | Features: 72 | 73 | * Marked the Gedmo extensions 2.4.0 release as supported (as well as any future 2.x release thanks to semver) 74 | -------------------------------------------------------------------------------- /DependencyInjection/Compiler/ValidateExtensionConfigurationPass.php: -------------------------------------------------------------------------------- 1 | getExtension('stof_doctrine_extensions')->configValidate($container); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | getRootNode(); 19 | 20 | $rootNode 21 | ->append($this->getVendorNode('orm')) 22 | ->append($this->getVendorNode('mongodb')) 23 | ->append($this->getClassNode()) 24 | ->append($this->getUploadableNode()) 25 | ->children() 26 | ->scalarNode('default_locale') 27 | ->cannotBeEmpty() 28 | ->defaultValue('en') 29 | ->end() 30 | ->booleanNode('translation_fallback')->defaultFalse()->end() 31 | ->booleanNode('persist_default_translation')->defaultFalse()->end() 32 | ->booleanNode('skip_translation_on_load')->defaultFalse()->end() 33 | ->end() 34 | ; 35 | 36 | return $treeBuilder; 37 | } 38 | 39 | /** 40 | * @param string $name 41 | */ 42 | private function getVendorNode($name) 43 | { 44 | $treeBuilder = new TreeBuilder($name); 45 | $node = $treeBuilder->getRootNode(); 46 | 47 | $node 48 | ->useAttributeAsKey('id') 49 | ->prototype('array') 50 | ->children() 51 | ->scalarNode('translatable')->defaultFalse()->end() 52 | ->scalarNode('timestampable')->defaultFalse()->end() 53 | ->scalarNode('blameable')->defaultFalse()->end() 54 | ->scalarNode('sluggable')->defaultFalse()->end() 55 | ->scalarNode('tree')->defaultFalse()->end() 56 | ->scalarNode('loggable')->defaultFalse()->end() 57 | ->scalarNode('sortable')->defaultFalse()->end() 58 | ->scalarNode('softdeleteable')->defaultFalse()->end() 59 | ->scalarNode('uploadable')->defaultFalse()->end() 60 | ->scalarNode('reference_integrity')->defaultFalse()->end() 61 | ->end() 62 | ->end() 63 | ; 64 | 65 | return $node; 66 | } 67 | 68 | private function getClassNode() 69 | { 70 | $treeBuilder = new TreeBuilder('class'); 71 | $node = $treeBuilder->getRootNode(); 72 | 73 | $node 74 | ->addDefaultsIfNotSet() 75 | ->children() 76 | ->scalarNode('translatable') 77 | ->cannotBeEmpty() 78 | ->defaultValue('Gedmo\Translatable\TranslatableListener') 79 | ->end() 80 | ->scalarNode('timestampable') 81 | ->cannotBeEmpty() 82 | ->defaultValue('Gedmo\\Timestampable\\TimestampableListener') 83 | ->end() 84 | ->scalarNode('blameable') 85 | ->cannotBeEmpty() 86 | ->defaultValue('Gedmo\\Blameable\\BlameableListener') 87 | ->end() 88 | ->scalarNode('sluggable') 89 | ->cannotBeEmpty() 90 | ->defaultValue('Gedmo\\Sluggable\\SluggableListener') 91 | ->end() 92 | ->scalarNode('tree') 93 | ->cannotBeEmpty() 94 | ->defaultValue('Gedmo\\Tree\\TreeListener') 95 | ->end() 96 | ->scalarNode('loggable') 97 | ->cannotBeEmpty() 98 | ->defaultValue('Gedmo\Loggable\LoggableListener') 99 | ->end() 100 | ->scalarNode('sortable') 101 | ->cannotBeEmpty() 102 | ->defaultValue('Gedmo\\Sortable\\SortableListener') 103 | ->end() 104 | ->scalarNode('softdeleteable') 105 | ->cannotBeEmpty() 106 | ->defaultValue('Gedmo\\SoftDeleteable\\SoftDeleteableListener') 107 | ->end() 108 | ->scalarNode('uploadable') 109 | ->cannotBeEmpty() 110 | ->defaultValue('Gedmo\\Uploadable\\UploadableListener') 111 | ->end() 112 | ->scalarNode('reference_integrity') 113 | ->cannotBeEmpty() 114 | ->defaultValue('Gedmo\\ReferenceIntegrity\\ReferenceIntegrityListener') 115 | ->end() 116 | ->end() 117 | ; 118 | 119 | return $node; 120 | } 121 | 122 | private function getUploadableNode() 123 | { 124 | $treeBuilder = new TreeBuilder('uploadable'); 125 | $node = $treeBuilder->getRootNode(); 126 | 127 | $node 128 | ->addDefaultsIfNotSet() 129 | ->children() 130 | ->scalarNode('default_file_path') 131 | ->cannotBeEmpty() 132 | ->defaultNull() 133 | ->end() 134 | ->scalarNode('mime_type_guesser_class') 135 | ->cannotBeEmpty() 136 | ->defaultValue('Stof\\DoctrineExtensionsBundle\\Uploadable\\MimeTypeGuesserAdapter') 137 | ->end() 138 | ->scalarNode('default_file_info_class') 139 | ->cannotBeEmpty() 140 | ->defaultValue('Stof\\DoctrineExtensionsBundle\\Uploadable\\UploadedFileInfo') 141 | ->end() 142 | ->booleanNode('validate_writable_directory')->defaultTrue()->end() 143 | ->end() 144 | ; 145 | 146 | return $node; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /DependencyInjection/StofDoctrineExtensionsExtension.php: -------------------------------------------------------------------------------- 1 | processConfiguration($configuration, $configs); 23 | 24 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 25 | 26 | $loaded = array(); 27 | 28 | $this->entityManagers = $this->processObjectManagerConfigurations($config['orm'], $container, $loader, $loaded, 'doctrine.event_subscriber'); 29 | $this->documentManagers = $this->processObjectManagerConfigurations($config['mongodb'], $container, $loader, $loaded, 'doctrine_mongodb.odm.event_subscriber'); 30 | 31 | $container->setParameter('stof_doctrine_extensions.default_locale', $config['default_locale']); 32 | $container->setParameter('stof_doctrine_extensions.translation_fallback', $config['translation_fallback']); 33 | $container->setParameter('stof_doctrine_extensions.persist_default_translation', $config['persist_default_translation']); 34 | $container->setParameter('stof_doctrine_extensions.skip_translation_on_load', $config['skip_translation_on_load']); 35 | 36 | // Register the uploadable configuration if the listener is used 37 | if (isset($loaded['uploadable'])) { 38 | $uploadableConfig = $config['uploadable']; 39 | 40 | $container->setParameter('stof_doctrine_extensions.default_file_path', $uploadableConfig['default_file_path']); 41 | $container->setParameter('stof_doctrine_extensions.uploadable.default_file_info.class', $uploadableConfig['default_file_info_class']); 42 | $container->setParameter( 43 | 'stof_doctrine_extensions.uploadable.validate_writable_directory', 44 | $uploadableConfig['validate_writable_directory'] 45 | ); 46 | 47 | if ($uploadableConfig['default_file_path']) { 48 | $container->getDefinition('stof_doctrine_extensions.listener.uploadable') 49 | ->addMethodCall('setDefaultPath', array($uploadableConfig['default_file_path'])); 50 | } 51 | 52 | if ($uploadableConfig['mime_type_guesser_class']) { 53 | if (!class_exists($uploadableConfig['mime_type_guesser_class'])) { 54 | $msg = 'Class "%s" configured to use as the mime type guesser in the Uploadable extension does not exist.'; 55 | 56 | throw new \InvalidArgumentException(sprintf($msg, $uploadableConfig['mime_type_guesser_class'])); 57 | } 58 | 59 | $container->setParameter( 60 | 'stof_doctrine_extensions.uploadable.mime_type_guesser.class', 61 | $uploadableConfig['mime_type_guesser_class'] 62 | ); 63 | } 64 | } 65 | 66 | foreach ($config['class'] as $listener => $class) { 67 | $container->setParameter(sprintf('stof_doctrine_extensions.listener.%s.class', $listener), $class); 68 | } 69 | } 70 | 71 | /** 72 | * @internal 73 | */ 74 | public function configValidate(ContainerBuilder $container) 75 | { 76 | foreach ($this->entityManagers as $name) { 77 | if (!$container->hasDefinition(sprintf('doctrine.dbal.%s_connection', $name))) { 78 | throw new \InvalidArgumentException(sprintf('Invalid %s config: DBAL connection "%s" not found', $this->getAlias(), $name)); 79 | } 80 | } 81 | 82 | foreach ($this->documentManagers as $name) { 83 | if (!$container->hasDefinition(sprintf('doctrine_mongodb.odm.%s_document_manager', $name))) { 84 | throw new \InvalidArgumentException(sprintf('Invalid %s config: document manager "%s" not found', $this->getAlias(), $name)); 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * @param array $configs 91 | * @param ContainerBuilder $container 92 | * @param LoaderInterface $loader 93 | * @param array $loaded 94 | * @param string $doctrineSubscriberTag 95 | * 96 | * @return array 97 | */ 98 | private function processObjectManagerConfigurations(array $configs, ContainerBuilder $container, LoaderInterface $loader, array &$loaded, $doctrineSubscriberTag) 99 | { 100 | $usedManagers = array(); 101 | 102 | $listenerPriorities = array( 103 | 'translatable' => -10, 104 | 'loggable' => 5, 105 | 'uploadable' => -5, 106 | ); 107 | 108 | foreach ($configs as $name => $listeners) { 109 | foreach ($listeners as $ext => $enabled) { 110 | if (!$enabled) { 111 | continue; 112 | } 113 | 114 | if (!isset($loaded[$ext])) { 115 | $loader->load($ext.'.xml'); 116 | $loaded[$ext] = true; 117 | } 118 | 119 | $attributes = array('connection' => $name); 120 | 121 | if (isset($listenerPriorities[$ext])) { 122 | $attributes['priority'] = $listenerPriorities[$ext]; 123 | } 124 | 125 | $definition = $container->getDefinition(sprintf('stof_doctrine_extensions.listener.%s', $ext)); 126 | $definition->addTag($doctrineSubscriberTag, $attributes); 127 | 128 | $usedManagers[$name] = true; 129 | } 130 | } 131 | 132 | return array_keys($usedManagers); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG php_version 2 | 3 | FROM php:${php_version}-cli 4 | 5 | RUN apt-get update && apt-get install -y \ 6 | curl \ 7 | libzip-dev \ 8 | zip \ 9 | && docker-php-ext-install \ 10 | zip \ 11 | pdo_mysql \ 12 | && pecl install \ 13 | xdebug-3.0.1 \ 14 | && docker-php-ext-enable \ 15 | xdebug 16 | 17 | COPY . /var/php 18 | WORKDIR /var/php 19 | 20 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \ 21 | composer update --prefer-dist --no-interaction -------------------------------------------------------------------------------- /EventListener/BlameListener.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class BlameListener implements EventSubscriberInterface 20 | { 21 | private $authorizationChecker; 22 | private $tokenStorage; 23 | private $blameableListener; 24 | 25 | public function __construct(BlameableListener $blameableListener, TokenStorageInterface $tokenStorage = null, AuthorizationCheckerInterface $authorizationChecker = null) 26 | { 27 | $this->blameableListener = $blameableListener; 28 | $this->tokenStorage = $tokenStorage; 29 | $this->authorizationChecker = $authorizationChecker; 30 | } 31 | 32 | /** 33 | * @param RequestEvent $event 34 | * @internal 35 | */ 36 | public function onKernelRequest(RequestEvent $event) 37 | { 38 | if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { 39 | return; 40 | } 41 | 42 | if (null === $this->tokenStorage || null === $this->authorizationChecker) { 43 | return; 44 | } 45 | 46 | $token = $this->tokenStorage->getToken(); 47 | if (null !== $token && $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 48 | $this->blameableListener->setUserValue($token->getUser()); 49 | } 50 | } 51 | 52 | public static function getSubscribedEvents() 53 | { 54 | return array( 55 | KernelEvents::REQUEST => 'onKernelRequest', 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /EventListener/LocaleListener.php: -------------------------------------------------------------------------------- 1 | translatableListener = $translatableListener; 22 | } 23 | 24 | /** 25 | * @param RequestEvent $event 26 | * @internal 27 | */ 28 | public function onKernelRequest(RequestEvent $event) 29 | { 30 | $this->translatableListener->setTranslatableLocale($event->getRequest()->getLocale()); 31 | } 32 | 33 | public static function getSubscribedEvents() 34 | { 35 | return array( 36 | KernelEvents::REQUEST => 'onKernelRequest', 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /EventListener/LoggerListener.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | class LoggerListener implements EventSubscriberInterface 19 | { 20 | private $authorizationChecker; 21 | private $tokenStorage; 22 | private $loggableListener; 23 | 24 | public function __construct(LoggableListener $loggableListener, TokenStorageInterface $tokenStorage = null, AuthorizationCheckerInterface $authorizationChecker = null) 25 | { 26 | $this->loggableListener = $loggableListener; 27 | $this->tokenStorage = $tokenStorage; 28 | $this->authorizationChecker = $authorizationChecker; 29 | } 30 | 31 | /** 32 | * @param RequestEvent $event 33 | * @internal 34 | */ 35 | public function onKernelRequest(RequestEvent $event) 36 | { 37 | if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { 38 | return; 39 | } 40 | 41 | if (null === $this->tokenStorage || null === $this->authorizationChecker) { 42 | return; 43 | } 44 | 45 | $token = $this->tokenStorage->getToken(); 46 | 47 | if (null !== $token && $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 48 | $this->loggableListener->setUsername($token); 49 | } 50 | } 51 | 52 | public static function getSubscribedEvents() 53 | { 54 | return array( 55 | KernelEvents::REQUEST => 'onKernelRequest', 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Christophe Coevoet 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StofDoctrineExtensionsBundle 2 | 3 | This bundle provides integration for 4 | [DoctrineExtensions](https://github.com/Atlantic18/DoctrineExtensions) in 5 | your Symfony Project 6 | 7 | [![Total Downloads](https://poser.pugx.org/antishov/doctrine-extensions-bundle/downloads.png)](https://poser.pugx.org/antishov/doctrine-extensions-bundle/downloads) 8 | [![Latest Stable Version](https://poser.pugx.org/antishov/doctrine-extensions-bundle/v/stable.png)](https://packagist.org/packages/antishov/doctrine-extensions-bundle) 9 | [![Build Status](https://travis-ci.com/antishov/StofDoctrineExtensionsBundle.svg?branch=master)](https://travis-ci.com/antishov/StofDoctrineExtensionsBundle) 10 | 11 | ## Installation 12 | 13 | ### Applications that use Symfony Flex 14 | 15 | Open a command console, enter your project directory and execute: 16 | 17 | ```console 18 | $ composer require antishov/doctrine-extensions-bundle 19 | ``` 20 | 21 | ### Applications that don't use Symfony Flex 22 | 23 | #### Step 1: Download the Bundle 24 | 25 | Open a command console, enter your project directory and execute the 26 | following command to download the latest stable version of this bundle: 27 | 28 | ```console 29 | $ composer require antishov/doctrine-extensions-bundle 30 | ``` 31 | 32 | This command requires you to have Composer installed globally, as explained 33 | in the [installation chapter](https://getcomposer.org/doc/00-intro.md) 34 | of the Composer documentation. 35 | 36 | #### Step 2: Enable the Bundle 37 | 38 | Then, enable the bundle by adding it to the list of registered bundles 39 | in the `config/bundles.php` file of your project: 40 | 41 | ```php 42 | // config/bundles.php 43 | 44 | return [ 45 | // ... 46 | Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true], 47 | ]; 48 | ``` 49 | 50 | ## Requirements 51 | 52 | * The minimum required PHP is 7.2.5 53 | * Symfony 4.4 or greater 54 | 55 | ## Contributing 56 | 57 | Run tests in docker for an all supported versions of PHP: 58 | ``` 59 | $ docker-compose -f docker-compose.tests.yml up 60 | ``` 61 | 62 | Pull-requests and issues are welcomed. 63 | 64 | For documentation, see it [online](https://symfony.com/doc/master/bundles/StofDoctrineExtensionsBundle/index.html) 65 | 66 | > This is a fork of [stof/StofDoctrineExtensionsBundle](https://github.com/stof/StofDoctrineExtensionsBundle) which has a lot of issues and is not maintained anymore. 67 | 68 | License: [MIT](LICENSE) -------------------------------------------------------------------------------- /Resources/config/blameable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\Blameable\BlameableListener 9 | Stof\DoctrineExtensionsBundle\EventListener\BlameListener 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Resources/config/loggable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\Loggable\LoggableListener 9 | Stof\DoctrineExtensionsBundle\EventListener\LoggerListener 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Resources/config/reference_integrity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\ReferenceIntegrity\ReferenceIntegrityListener 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Resources/config/sluggable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\Sluggable\SluggableListener 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Resources/config/softdeleteable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\SoftDeleteable\SoftDeleteableListener 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Resources/config/sortable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\Sortable\SortableListener 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Resources/config/timestampable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\Timestampable\TimestampableListener 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Resources/config/translatable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\Translatable\TranslatableListener 9 | Stof\DoctrineExtensionsBundle\EventListener\LocaleListener 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | %stof_doctrine_extensions.default_locale% 18 | 19 | 20 | %stof_doctrine_extensions.default_locale% 21 | 22 | 23 | %stof_doctrine_extensions.translation_fallback% 24 | 25 | 26 | %stof_doctrine_extensions.persist_default_translation% 27 | 28 | 29 | %stof_doctrine_extensions.skip_translation_on_load% 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Resources/config/tree.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\Tree\TreeListener 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Resources/config/uploadable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Gedmo\Uploadable\UploadableListener 9 | Stof\DoctrineExtensionsBundle\Uploadable\UploadableManager 10 | Stof\DoctrineExtensionsBundle\Uploadable\MimeTypeGuesserAdapter 11 | Stof\DoctrineExtensionsBundle\Uploadable\UploadedFileInfo 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | %stof_doctrine_extensions.uploadable.default_file_info.class% 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | %stof_doctrine_extensions.uploadable.default_file_info.class% 32 | 33 | 34 | 35 | 36 | 37 | %stof_doctrine_extensions.uploadable.validate_writable_directory% 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Resources/doc/advanced.rst: -------------------------------------------------------------------------------- 1 | Advanced Usage 2 | ============== 3 | 4 | Overriding the listeners 5 | ------------------------ 6 | 7 | You can change the listeners used by extending the Gedmo listeners (or the 8 | listeners of the bundle for translations) and giving the class name in the 9 | configuration. 10 | 11 | .. configuration-block:: 12 | 13 | .. code-block:: yaml 14 | 15 | # app/config/config.yml 16 | # (or config/packages/stof_doctrine_extensions.yaml if you use Flex) 17 | stof_doctrine_extensions: 18 | class: 19 | tree: MyBundle\TreeListener 20 | timestampable: MyBundle\TimestampableListener 21 | blameable: ~ 22 | sluggable: ~ 23 | translatable: ~ 24 | loggable: ~ 25 | softdeleteable: ~ 26 | uploadable: ~ 27 | 28 | .. code-block:: xml 29 | 30 | 31 | 32 | 33 | 34 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Resources/doc/configuration.rst: -------------------------------------------------------------------------------- 1 | Configuration 2 | ============= 3 | 4 | Add the extensions to your mapping 5 | ---------------------------------- 6 | 7 | Some of the extensions use their own entities to do their work. You need 8 | to register their mapping in Doctrine when you want to use them. 9 | 10 | .. code-block:: yaml 11 | 12 | # app/config/config.yml 13 | # (or config/packages/doctrine.yaml if you use Flex) 14 | doctrine: 15 | orm: 16 | entity_managers: 17 | default: 18 | mappings: 19 | gedmo_translatable: 20 | type: annotation 21 | prefix: Gedmo\Translatable\Entity 22 | dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity" 23 | alias: GedmoTranslatable # (optional) it will default to the name set for the mapping 24 | is_bundle: false 25 | gedmo_translator: 26 | type: annotation 27 | prefix: Gedmo\Translator\Entity 28 | dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translator/Entity" 29 | alias: GedmoTranslator # (optional) it will default to the name set for the mapping 30 | is_bundle: false 31 | gedmo_loggable: 32 | type: annotation 33 | prefix: Gedmo\Loggable\Entity 34 | dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Loggable/Entity" 35 | alias: GedmoLoggable # (optional) it will default to the name set for the mapping 36 | is_bundle: false 37 | gedmo_tree: 38 | type: annotation 39 | prefix: Gedmo\Tree\Entity 40 | dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Tree/Entity" 41 | alias: GedmoTree # (optional) it will default to the name set for the mapping 42 | is_bundle: false 43 | 44 | .. note:: 45 | 46 | If you are using the short syntax for the ORM configuration, the ``mappings`` 47 | key is directly under ``orm:`` 48 | 49 | .. note:: 50 | 51 | If you are using several entity managers, take care to register the entities 52 | for the right ones. 53 | 54 | .. note:: 55 | 56 | The mapping for MongoDB is similar. The ODM documents are in the ``Document`` 57 | subnamespace of each extension instead of ``Entity``. 58 | 59 | Configure the entity managers 60 | ----------------------------- 61 | 62 | You have to activate the extensions for each entity manager for which you want 63 | to enable the extensions. The id is the id of the DBAL connection when using the 64 | ORM behaviors. It is the id of the document manager when using mongoDB. 65 | 66 | This bundle needs a default locale used if the translation does not exists in 67 | the asked language. If you don't provide it explicitly, it will default to 68 | ``en``. 69 | 70 | .. configuration-block:: 71 | 72 | .. code-block:: yaml 73 | 74 | # app/config/config.yml 75 | # (or config/packages/stof_doctrine_extensions.yaml if you use Flex) 76 | stof_doctrine_extensions: 77 | default_locale: en_US 78 | 79 | # Only used if you activated the Uploadable extension 80 | uploadable: 81 | # Default file path: This is one of the three ways you can configure the path for the Uploadable extension 82 | default_file_path: "%kernel.root_dir%/../web/uploads" 83 | 84 | # Mime type guesser class: Optional. By default, we provide an adapter for the one present in the HttpFoundation component of Symfony 85 | mime_type_guesser_class: Stof\DoctrineExtensionsBundle\Uploadable\MimeTypeGuesserAdapter 86 | 87 | # Default file info class implementing FileInfoInterface: Optional. By default we provide a class which is prepared to receive an UploadedFile instance. 88 | default_file_info_class: Stof\DoctrineExtensionsBundle\Uploadable\UploadedFileInfo 89 | orm: 90 | default: ~ 91 | mongodb: 92 | default: ~ 93 | 94 | .. code-block:: xml 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Activate the extensions you want 110 | -------------------------------- 111 | 112 | By default the bundle does not attach any listener. For each of your entity 113 | manager, declare the extensions you want to enable: 114 | 115 | .. configuration-block:: 116 | 117 | .. code-block:: yaml 118 | 119 | # app/config/config.yml 120 | # (or config/packages/stof_doctrine_extensions.yaml if you use Flex) 121 | stof_doctrine_extensions: 122 | default_locale: en_US 123 | orm: 124 | default: 125 | tree: true 126 | timestampable: false # not needed: listeners are not enabled by default 127 | other: 128 | timestampable: true 129 | 130 | .. code-block:: xml 131 | 132 | 133 | 134 | 135 | 136 | 137 | 142 | 146 | 147 | 148 | 149 | 150 | Same is available for MongoDB using ``document-manager`` in the XML files 151 | instead of ``entity-manager``. 152 | 153 | .. caution:: 154 | 155 | If you configure the listeners of an entity manager in several configuration 156 | files, the last one will be used. So you have to list all the listeners you 157 | want to detach. 158 | 159 | Use the DoctrineExtensions library 160 | ---------------------------------- 161 | 162 | All explanations about this library are available on the official 163 | `DoctrineExtensions documentation`_. 164 | 165 | .. _`DoctrineExtensions documentation`: https://github.com/Atlantic18/DoctrineExtensions/tree/v2.4.x/doc 166 | -------------------------------------------------------------------------------- /Resources/doc/index.rst: -------------------------------------------------------------------------------- 1 | StofDoctrineExtensionsBundle 2 | ============================ 3 | 4 | This bundle provides integration for `DoctrineExtensions`_ in your Symfony 5 | projects. 6 | 7 | Features 8 | -------- 9 | 10 | * **Tree** - this extension automates the tree handling process and adds some 11 | tree specific functions on repository. (``closure``, ``nestedset`` or ``materialized path``). 12 | * **Translatable** - gives you a very handy solution for translating records 13 | into different languages. Easy to setup, easier to use. 14 | * **Sluggable** - urlizes your specified fields into single unique slug 15 | * **Timestampable** - updates date fields on create, update and even property change. 16 | * **Blameable** - updates string or association fields on create, update and even 17 | property change with a user name resp. reference. 18 | * **Loggable** - helps tracking changes and history of objects, also supports 19 | version management. 20 | * **Sortable** - makes any document or entity sortable 21 | * **Translator** - explicit way to handle translations 22 | * **Softdeleteable** - allows to implicitly remove records 23 | * **Uploadable** - provides file upload handling in entity fields 24 | * **Reference Integrity** - provides reference integrity for MongoDB, supports 25 | ``nullify`` and ``restrict``. 26 | 27 | All these extensions can be nested together. And most already use only 28 | annotations without interface requirement to not to aggregate the entity itself 29 | and has implemented proper caching for metadata. 30 | 31 | See the official `official DoctrineExtensions documentation`_ for more details. 32 | 33 | .. toctree:: 34 | :maxdepth: 2 35 | 36 | installation 37 | configuration 38 | softdeletable-filter 39 | uploadable-extension 40 | advanced 41 | 42 | .. _`DoctrineExtensions`: https://github.com/Atlantic18/DoctrineExtensions 43 | .. _`official DoctrineExtensions documentation`: https://github.com/Atlantic18/DoctrineExtensions/tree/v2.4.x/doc 44 | -------------------------------------------------------------------------------- /Resources/doc/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | 4 | Installation Using Symfony Flex 5 | ------------------------------- 6 | 7 | `Symfony Flex`_ is the new way to manage dependencies on Symfony 3.4 and higher 8 | applications. If your project already uses Symfony Flex, execute this command to 9 | download, register and configure the bundle automatically: 10 | 11 | .. code-block:: terminal 12 | 13 | $ composer require stof/doctrine-extensions-bundle 14 | 15 | That's all! You can skip the rest of this article. 16 | 17 | Installation without Symfony Flex 18 | --------------------------------- 19 | 20 | Step 1: Download the Bundle 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | 23 | Open a command console, enter your project directory and execute the 24 | following command to download the latest stable version of this bundle: 25 | 26 | .. code-block:: bash 27 | 28 | $ composer require stof/doctrine-extensions-bundle 29 | 30 | This command requires you to have Composer installed globally, as explained 31 | in the `installation chapter`_ of the Composer documentation. 32 | 33 | Step 2: Enable the Bundle 34 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 35 | 36 | Then, enable the bundle by adding the following line in the ``app/AppKernel.php`` 37 | file of your project: 38 | 39 | .. code-block:: php 40 | 41 | // app/AppKernel.php 42 | 43 | class AppKernel extends Kernel 44 | { 45 | public function registerBundles() 46 | { 47 | $bundles = array( 48 | // ... 49 | 50 | new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(), 51 | ); 52 | 53 | // ... 54 | } 55 | 56 | // ... 57 | } 58 | 59 | .. _`Symfony Flex`: https://symfony.com/doc/current/setup/flex.html 60 | .. _`installation chapter`: https://getcomposer.org/doc/00-intro.md 61 | -------------------------------------------------------------------------------- /Resources/doc/softdeleteable-filter.rst: -------------------------------------------------------------------------------- 1 | SoftDeleteable Filter 2 | ===================== 3 | 4 | If you want to use the SoftDeleteable behavior, you have to enable the 5 | Doctrine filter. 6 | 7 | .. code-block:: yaml 8 | 9 | # app/config/config.yml 10 | # (or config/packages/doctrine.yaml if you use Flex) 11 | doctrine: 12 | orm: 13 | entity_managers: 14 | default: 15 | filters: 16 | softdeleteable: 17 | class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter 18 | enabled: true 19 | 20 | .. note:: 21 | 22 | If you are using the short syntax for the ORM configuration, the ``filters`` 23 | key is directly under ``orm:`` 24 | 25 | .. note:: 26 | 27 | If you are using several entity managers, take care to register the filter 28 | for the right ones. 29 | 30 | To disable the behavior, e.g. for admin users who may see deleted items, 31 | disable the filter. Here is an example:: 32 | 33 | $filters = $em->getFilters(); 34 | $filters->disable('softdeleteable'); 35 | -------------------------------------------------------------------------------- /Resources/doc/uploadable-extension.rst: -------------------------------------------------------------------------------- 1 | Uploadable extension 2 | ==================== 3 | 4 | Before using this extension, read the `official Uploadable documentation`_. Once 5 | everything is ready, use the Form component as usual. Then, after you verify the 6 | form is valid, do the following:: 7 | 8 | $document = new Document(); 9 | $form = $this->createFormBuilder($document) 10 | ->add('name') 11 | ->add('myFile') 12 | ->getForm() 13 | ; 14 | 15 | $form->handleRequest($request); 16 | 17 | if ($form->isSubmitted() && $form->isValid()) { 18 | $em = $this->getDoctrine()->getManager(); 19 | $em->persist($document); 20 | 21 | $uploadableManager = $this->get('stof_doctrine_extensions.uploadable.manager'); 22 | 23 | // Here, "getMyFile" returns the "UploadedFile" instance that the form bound in your $myFile property 24 | $uploadableManager->markEntityToUpload($document, $document->getMyFile()); 25 | 26 | $em->flush(); 27 | 28 | return $this->redirect($this->generateUrl('...')); 29 | } 30 | 31 | return $this->render('...', array('form' => $form->createView())); 32 | 33 | And that's it. The Uploadable extension handles the rest of the stuff. Remember 34 | to read its documentation! 35 | 36 | .. _`official Uploadable documentation`: https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/doc/uploadable.md 37 | -------------------------------------------------------------------------------- /StofDoctrineExtensionsBundle.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new ValidateExtensionConfigurationPass()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Uploadable/MimeTypeGuesserAdapter.php: -------------------------------------------------------------------------------- 1 | guessMimeType($filePath); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Uploadable/UploadableManager.php: -------------------------------------------------------------------------------- 1 | listener = $listener; 17 | $this->fileInfoClass = $fileInfoClass; 18 | } 19 | 20 | /** 21 | * This method marks an entity to be uploaded as soon as the "flush" method of your object manager is called. 22 | * After calling this method, the file info you passed is set for this entity in the listener. This is all it takes 23 | * to upload a file for an entity in the Uploadable extension. 24 | * 25 | * @param object $entity - The entity you are marking to "Upload" as soon as you call "flush". 26 | * @param mixed $fileInfo - The file info object or array. In Symfony, this will be typically an UploadedFile instance. 27 | */ 28 | public function markEntityToUpload($entity, $fileInfo) 29 | { 30 | if (is_object($fileInfo) && $fileInfo instanceof UploadedFile) { 31 | $fileInfoClass = $this->fileInfoClass; 32 | 33 | $fileInfo = new $fileInfoClass($fileInfo); 34 | } 35 | 36 | $this->listener->addEntityFileInfo($entity, $fileInfo); 37 | } 38 | 39 | /** 40 | * @return \Gedmo\Uploadable\UploadableListener 41 | */ 42 | public function getUploadableListener() 43 | { 44 | return $this->listener; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Uploadable/UploadedFileInfo.php: -------------------------------------------------------------------------------- 1 | uploadedFile = $uploadedFile; 15 | } 16 | 17 | public function getTmpName() 18 | { 19 | return $this->uploadedFile->getPathname(); 20 | } 21 | 22 | public function getName() 23 | { 24 | return $this->uploadedFile->getClientOriginalName(); 25 | } 26 | 27 | public function getSize() 28 | { 29 | return $this->uploadedFile->getSize(); 30 | } 31 | 32 | public function getType() 33 | { 34 | return $this->uploadedFile->getMimeType(); 35 | } 36 | 37 | public function getError() 38 | { 39 | return $this->uploadedFile->getError(); 40 | } 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | public function isUploadedFile() 46 | { 47 | return is_uploaded_file($this->uploadedFile->getPathname()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Uploadable/ValidatorConfigurator.php: -------------------------------------------------------------------------------- 1 | validateWritableDirectory = $validateWritableDirectory; 20 | } 21 | 22 | public function configure() 23 | { 24 | Validator::$validateWritableDirectory = $this->validateWritableDirectory; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "antishov/doctrine-extensions-bundle", 3 | "type": "symfony-bundle", 4 | "description": "Forked from stof/doctrine-extensions-bundle integration of the gedmo/doctrine-extensions with Symfony 4", 5 | "keywords": ["tree", "behaviors", "doctrine2", "extensions", "gedmo", "sluggable","loggable", "translatable", "nestedset", "sortable", "timestampable", "stof"], 6 | "homepage": "https://github.com/antishov/StofDoctrineExtensionsBundle", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Antishov Viktor", 11 | "email": "antishov.viktor@gmail.com" 12 | }, 13 | { 14 | "name": "Christophe Coevoet", 15 | "email": "stof@notk.org" 16 | } 17 | ], 18 | "replace": { 19 | "stof/doctrine-extensions-bundle": "self.version" 20 | }, 21 | "require": { 22 | "symfony/mime": "^4.3|^5.0", 23 | "php": "^7.2.5 || ^8.0", 24 | "symfony/framework-bundle": "^4.4|^5.0", 25 | "gedmo/doctrine-extensions": "^2.3.4 || ^3.0" 26 | }, 27 | "require-dev": { 28 | "symfony/phpunit-bridge": "^4.4|^5.0", 29 | "symfony/security-bundle": "^4.4|^5.0" 30 | }, 31 | "suggest": { 32 | "doctrine/doctrine-bundle": "to use the ORM extensions", 33 | "doctrine/mongodb-odm-bundle": "to use the MongoDB ODM extensions" 34 | }, 35 | "autoload": { 36 | "psr-4": { "Stof\\DoctrineExtensionsBundle\\": "" } 37 | }, 38 | "extra": { 39 | "branch-alias": { 40 | "dev-master": "1.0-dev" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /docker-compose.tests.yml: -------------------------------------------------------------------------------- 1 | version: "3.3" 2 | services: 3 | phpunit7.2.5: 4 | command: ./vendor/bin/simple-phpunit -v 5 | build: 6 | context: . 7 | dockerfile: Dockerfile 8 | args: 9 | php_version: 7.2.5 10 | phpunit7.3: 11 | command: ./vendor/bin/simple-phpunit -v 12 | build: 13 | context: . 14 | dockerfile: Dockerfile 15 | args: 16 | php_version: 7.3 17 | phpunit7.4: 18 | command: ./vendor/bin/simple-phpunit -v 19 | build: 20 | context: . 21 | dockerfile: Dockerfile 22 | args: 23 | php_version: 7.4 24 | phpunit8: 25 | command: ./vendor/bin/simple-phpunit -v 26 | build: 27 | context: . 28 | dockerfile: Dockerfile 29 | args: 30 | php_version: 8 -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.3" 2 | services: 3 | composer: 4 | command: composer update --prefer-lowest --no-interaction 5 | volumes: 6 | - .:/var/php 7 | build: 8 | context: . 9 | dockerfile: Dockerfile 10 | args: 11 | php_version: 7.4 --------------------------------------------------------------------------------