├── 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 | [](https://poser.pugx.org/antishov/doctrine-extensions-bundle/downloads)
8 | [](https://packagist.org/packages/antishov/doctrine-extensions-bundle)
9 | [](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
--------------------------------------------------------------------------------