├── tests ├── Fixtures │ ├── App │ │ ├── var │ │ │ └── .gitempty │ │ ├── templates │ │ │ ├── form.html.twig │ │ │ └── foo.html │ │ ├── config │ │ │ ├── twig.yaml │ │ │ ├── framework.yaml │ │ │ ├── routes │ │ │ │ ├── routes.yaml │ │ │ │ └── web_profiler.yaml │ │ │ ├── services.yaml │ │ │ ├── config.php │ │ │ ├── routing.php │ │ │ ├── web_profiler.yaml │ │ │ ├── bundles.php │ │ │ └── doctrine.yaml │ │ ├── bin │ │ │ └── console │ │ ├── Kernel.php │ │ ├── Controller │ │ │ └── TestController.php │ │ ├── Document │ │ │ ├── ReferrerDocument.php │ │ │ └── TestDocument.php │ │ └── DataFixtures │ │ │ └── PHPCR │ │ │ └── LoadData.php │ └── fixtures │ │ └── config │ │ ├── multiple.yml │ │ ├── multiple.xml │ │ ├── multiple.php │ │ ├── single.yml │ │ ├── single.php │ │ └── single.xml ├── phpcr_odm_doctrine_dbal.sh ├── Web │ └── WebProfilerTest.php ├── Functional │ ├── Initializer │ │ └── GenericInitializerTest.php │ ├── Command │ │ └── NodeDumpCommandTest.php │ ├── BaseTestCase.php │ └── Form │ │ ├── ChoiceList │ │ └── PhpcrOdmQueryBuilderLoaderTest.php │ │ └── Type │ │ └── DocumentTypeTest.php └── Unit │ ├── Form │ ├── DataTransformer │ │ ├── PHPCRNodeToUuidTransformerTest.php │ │ ├── DocumentToPathTransformerTest.php │ │ └── PHPCRNodeToPathTransformerTest.php │ └── Type │ │ ├── PathTypeTest.php │ │ └── PHPCRReferenceTypeTest.php │ ├── DependencyInjection │ └── Compiler │ │ └── InitializerPassTest.php │ ├── Initializer │ ├── GenericInitializerTest.php │ └── InitializerManagerTest.php │ └── EventListener │ └── LocaleListenerTest.php ├── src ├── Resources │ ├── meta │ │ ├── approval_LGPL-to-MIT │ │ │ ├── Stof.eml │ │ │ ├── ruian.eml │ │ │ ├── request.eml │ │ │ ├── bergie.eml │ │ │ ├── treffynnon.eml │ │ │ ├── lsmith77.eml │ │ │ └── uwej711.eml │ │ └── LICENSE │ ├── config │ │ ├── jackalope_doctrine_dbal-commands.xml │ │ ├── jackrabbit-commands.xml │ │ ├── jackalope_doctrine_dbal.xml │ │ ├── odm_multilang.xml │ │ ├── jackalope.xml │ │ ├── phpcr.xml │ │ ├── commands.xml │ │ └── odm.xml │ └── views │ │ └── Collector │ │ └── icon.svg ├── Initializer │ ├── SessionAwareInitializerInterface.php │ ├── InitializerInterface.php │ ├── GenericInitializer.php │ └── InitializerManager.php ├── Migrator │ ├── MigratorInterface.php │ └── AbstractMigrator.php ├── Mapping │ └── Driver │ │ ├── XmlDriver.php │ │ └── YamlDriver.php ├── DependencyInjection │ └── Compiler │ │ ├── MigratorPass.php │ │ └── InitializerPass.php ├── Validator │ └── Constraints │ │ ├── ValidPhpcrOdm.php │ │ └── ValidPhpcrOdmValidator.php ├── DataCollector │ └── StopWatchLogger.php ├── EventListener │ ├── JackalopeDoctrineDbalSchemaListener.php │ └── LocaleListener.php ├── ManagerRegistryInterface.php ├── Form │ ├── DoctrinePHPCRExtension.php │ ├── Type │ │ ├── PathType.php │ │ ├── DocumentType.php │ │ └── PHPCRReferenceType.php │ ├── DataTransformer │ │ ├── DocumentToPathTransformer.php │ │ ├── PHPCRNodeToPathTransformer.php │ │ └── PHPCRNodeToUuidTransformer.php │ └── ChoiceList │ │ └── PhpcrOdmQueryBuilderLoader.php ├── Command │ ├── WorkspaceListCommand.php │ ├── NodeMoveCommand.php │ ├── NodeTouchCommand.php │ ├── WorkspaceCreateCommand.php │ ├── NodeRemoveCommand.php │ ├── NodesUpdateCommand.php │ ├── NodeTypeListCommand.php │ ├── WorkspaceExportCommand.php │ ├── WorkspaceImportCommand.php │ ├── WorkspacePurgeCommand.php │ ├── WorkspaceQueryCommand.php │ ├── WorkspaceDeleteCommand.php │ ├── NodeDumpCommand.php │ ├── RepositoryInitCommand.php │ ├── NodeTypeRegisterCommand.php │ ├── DoctrineCommandHelper.php │ ├── MigratorMigrateCommand.php │ └── PhpcrShellCommand.php ├── OptionalCommand │ ├── ODM │ │ ├── DocumentMigrateClassCommand.php │ │ ├── InfoDoctrineCommand.php │ │ ├── DocumentConvertTranslationCommand.php │ │ └── VerifyUniqueNodeTypesMappingCommand.php │ └── Jackalope │ │ ├── JackrabbitCommand.php │ │ └── InitDoctrineDbalCommand.php ├── CacheWarmer │ └── UniqueNodeTypeCacheWarmer.php ├── DataFixtures │ └── PHPCRExecutor.php ├── ManagerRegistry.php └── Test │ └── RepositoryManager.php ├── .gitignore ├── doc ├── index.rst └── events.rst ├── .styleci.yml ├── .doctrine-project.json ├── .php-cs-fixer.dist.php ├── phpstan.neon.dist ├── UPGRADE-2.4.md ├── phpunit.xml.dist ├── LICENSE ├── .github └── workflows │ ├── static.yml │ └── test-application.yaml ├── README.md └── composer.json /tests/Fixtures/App/var/.gitempty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/Fixtures/App/templates/form.html.twig: -------------------------------------------------------------------------------- 1 | {{ form(form) }} 2 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | default_path: '%kernel.project_dir%/templates' 3 | -------------------------------------------------------------------------------- /src/Resources/meta/approval_LGPL-to-MIT/Stof.eml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctrine/DoctrinePHPCRBundle/HEAD/src/Resources/meta/approval_LGPL-to-MIT/Stof.eml -------------------------------------------------------------------------------- /src/Resources/meta/approval_LGPL-to-MIT/ruian.eml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctrine/DoctrinePHPCRBundle/HEAD/src/Resources/meta/approval_LGPL-to-MIT/ruian.eml -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | phpunit.xml 3 | !tests/Fixtures/App/var/.gitempty 4 | tests/Fixtures/App/var 5 | vendor 6 | .phpunit.result.cache 7 | .php-cs-fixer.cache 8 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | secret: test 3 | property_access: ~ 4 | test: ~ 5 | form: ~ 6 | router: 7 | resource: '%kernel.project_dir%/config/routing.php' 8 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/routes/routes.yaml: -------------------------------------------------------------------------------- 1 | phpcr_request: 2 | path: /phpcr_request 3 | defaults: 4 | _controller: Doctrine\Bundle\PHPCRBundle\Tests\Fixtures\App\Controller\TestController::phpcrRequest 5 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/services.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | _defaults: 3 | public: false 4 | autowire: true 5 | autoconfigure: true 6 | 7 | Doctrine\Bundle\PHPCRBundle\Tests\Fixtures\App\Controller\TestController: ~ 8 | -------------------------------------------------------------------------------- /tests/Fixtures/App/templates/foo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Foo 6 | 7 | 8 |

Foo

9 | 10 | 11 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | DoctrinePHPCRBundle 2 | =================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | introduction 8 | models 9 | events 10 | forms 11 | fixtures_initializers 12 | multilang 13 | multiple_sessions 14 | configuration 15 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/config.php: -------------------------------------------------------------------------------- 1 | import(__DIR__.'/framework.yaml'); 4 | $loader->import(__DIR__.'/doctrine.yaml'); 5 | $loader->import(__DIR__.'/twig.yaml'); 6 | $loader->import(__DIR__.'/services.yaml'); 7 | 8 | $loader->import(__DIR__.'/web_profiler.yaml'); 9 | -------------------------------------------------------------------------------- /tests/phpcr_odm_doctrine_dbal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | DIR_NAME=`dirname $0` 6 | CONSOLE_DIR=$DIR_NAME"/../tests/Fixtures/App/bin" 7 | 8 | $CONSOLE_DIR"/console" doctrine:phpcr:init:dbal --drop --force 9 | $CONSOLE_DIR"/console" doctrine:phpcr:repository:init 10 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/routes/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler_wdt: 2 | resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' 3 | prefix: /_wdt 4 | 5 | web_profiler_profiler: 6 | resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' 7 | prefix: /_profiler 8 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: symfony 2 | 3 | risky: true 4 | 5 | enabled: 6 | - combine_consecutive_unsets 7 | - no_php4_constructor 8 | - no_useless_else 9 | - ordered_use 10 | - strict 11 | - php_unit_construct 12 | 13 | disabled: 14 | - single_line_class_definition 15 | - single_line_throw 16 | -------------------------------------------------------------------------------- /.doctrine-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "active": true, 3 | "name": "Doctrine PHPCR Bundle", 4 | "slug": "phpcr-bundle", 5 | "docsSlug": "doctrine-phpcr-bundle", 6 | "versions": [ 7 | { 8 | "name": "3.x", 9 | "branchName": "3.x", 10 | "slug": "latest", 11 | "current": true 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/routing.php: -------------------------------------------------------------------------------- 1 | addCollection( 8 | $loader->import(__DIR__.'/routes/web_profiler.yaml') 9 | ); 10 | 11 | $collection->addCollection( 12 | $loader->import(__DIR__.'/routes/routes.yaml') 13 | ); 14 | 15 | return $collection; 16 | -------------------------------------------------------------------------------- /src/Initializer/SessionAwareInitializerInterface.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | interface SessionAwareInitializerInterface 11 | { 12 | public function setSessionName(string $sessionName): void; 13 | } 14 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | profiler: 3 | enabled: true 4 | collect: false # Prevents slowing down the tests. The profiler needs 5 | # to be enabled selectively for each functional test. 6 | only_exceptions: false 7 | 8 | web_profiler: 9 | toolbar: true 10 | 11 | doctrine_phpcr: 12 | session: 13 | backend: 14 | profiling: true 15 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in(__DIR__.'/src') 5 | ->in(__DIR__.'/tests') 6 | ->exclude(__DIR__.'/tests/Fixtures/App/var') 7 | ->name('*.php') 8 | ; 9 | 10 | $config = new PhpCsFixer\Config(); 11 | 12 | return $config 13 | ->setRiskyAllowed(true) 14 | ->setRules([ 15 | '@Symfony' => true, 16 | 'single_line_throw' => false, 17 | ]) 18 | ->setFinder($finder) 19 | ; 20 | -------------------------------------------------------------------------------- /src/Migrator/MigratorInterface.php: -------------------------------------------------------------------------------- 1 | ['all' => true], 5 | Doctrine\Bundle\PHPCRBundle\DoctrinePHPCRBundle::class => ['all' => true], 6 | Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], 7 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], 8 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], 9 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['all' => true], 10 | ]; 11 | -------------------------------------------------------------------------------- /src/Migrator/AbstractMigrator.php: -------------------------------------------------------------------------------- 1 | session = $session; 17 | $this->output = $output; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Resources/config/jackalope_doctrine_dbal-commands.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Resources/config/jackrabbit-commands.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | %doctrine_phpcr.jackrabbit_jar% 10 | %doctrine_phpcr.workspace_dir% 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Initializer/InitializerInterface.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | interface InitializerInterface 14 | { 15 | /** 16 | * This method should be used to establish the requisite structure needed 17 | * by the application or bundle of the content repository. 18 | */ 19 | public function init(ManagerRegistryInterface $registry): void; 20 | 21 | /** 22 | * Return a name which can be used to identify this initializer. 23 | */ 24 | public function getName(): string; 25 | } 26 | -------------------------------------------------------------------------------- /src/Mapping/Driver/XmlDriver.php: -------------------------------------------------------------------------------- 1 | 12 | * @author Benjamin Eberlei 13 | */ 14 | class XmlDriver extends BaseXmlDriver 15 | { 16 | public const DEFAULT_FILE_EXTENSION = '.phpcr.xml'; 17 | 18 | public function __construct(array $prefixes, string $fileExtension = self::DEFAULT_FILE_EXTENSION) 19 | { 20 | $locator = new SymfonyFileLocator($prefixes, $fileExtension); 21 | parent::__construct($locator, $fileExtension); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Mapping/Driver/YamlDriver.php: -------------------------------------------------------------------------------- 1 | 12 | * @author Benjamin Eberlei 13 | */ 14 | class YamlDriver extends BaseYamlDriver 15 | { 16 | public const DEFAULT_FILE_EXTENSION = '.phpcr.yml'; 17 | 18 | public function __construct(array $prefixes, string $fileExtension = self::DEFAULT_FILE_EXTENSION) 19 | { 20 | $locator = new SymfonyFileLocator($prefixes, $fileExtension); 21 | parent::__construct($locator, $fileExtension); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DependencyInjection/Compiler/MigratorPass.php: -------------------------------------------------------------------------------- 1 | findTaggedServiceIds('doctrine_phpcr.migrator') as $id => $attributes) { 17 | $alias = $attributes[0]['alias'] ?? null; 18 | $migrators[$alias] = $id; 19 | } 20 | 21 | $container->setParameter('doctrine_phpcr.migrate.migrators', $migrators); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/Fixtures/App/bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev'); 13 | $debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod'; 14 | 15 | if ($debug) { 16 | Debug::enable(); 17 | } 18 | 19 | // must be placed after setting $env, because it's used in bootstrapping the 20 | // kernel 21 | $kernel = new Kernel($env, $debug); 22 | $application = new Application($kernel); 23 | $application->run($input); 24 | -------------------------------------------------------------------------------- /src/Validator/Constraints/ValidPhpcrOdm.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | #[\Attribute(\Attribute::TARGET_CLASS)] 13 | class ValidPhpcrOdm extends Constraint 14 | { 15 | public string $message = 'This value should not be blank.'; 16 | 17 | public string $service = 'doctrine_phpcr.odm.validator.valid_phpcr_odm'; 18 | 19 | /** 20 | * The validator must be defined as a service with this name. 21 | */ 22 | public function validatedBy(): string 23 | { 24 | return $this->service; 25 | } 26 | 27 | public function getTargets(): string 28 | { 29 | return self::CLASS_CONSTRAINT; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /UPGRADE-2.4.md: -------------------------------------------------------------------------------- 1 | UPGRADE FROM 2.x to 2.3 2 | ======================= 3 | 4 | * [BC Break] In order to have compatibility with Symfony 6, return types have been added to the following methods: 5 | * `Doctrine\Bundle\PHPCRBundle\DependencyInjection\DoctrinePHPCRExtension::getMappingObjectDefaultName()` 6 | * `Doctrine\Bundle\PHPCRBundle\DependencyInjection\DoctrinePHPCRExtension::getMappingResourceConfigDirectory()` 7 | * `Doctrine\Bundle\PHPCRBundle\DependencyInjection\DoctrinePHPCRExtension::getMappingResourceExtension()` 8 | * `Doctrine\Bundle\PHPCRBundle\DependencyInjection\DoctrinePHPCRExtension::getObjectManagerElementName()` 9 | * `Doctrine\Bundle\PHPCRBundle\Form\ChoiceList\PhpcrOdmQueryBuilderLoader::getEntities` 10 | * `Doctrine\Bundle\PHPCRBundle\Form\ChoiceList\PhpcrOdmQueryBuilderLoader::getEntitiesByIds` 11 | * `Doctrine\Bundle\PHPCRBundle\Form\Type\DocumentType::getLoader` 12 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | ./tests 12 | 13 | 14 | 15 | 16 | src/ 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/Fixtures/App/config/doctrine.yaml: -------------------------------------------------------------------------------- 1 | doctrine: 2 | dbal: 3 | driver: pdo_sqlite 4 | path: "%kernel.project_dir%/var/cache/app.sqlite" 5 | charset: UTF8 6 | 7 | doctrine_phpcr: 8 | session: 9 | backend: 10 | type: doctrinedbal 11 | parameters: 12 | jackalope.check_login_on_server: false 13 | workspace: default 14 | username: admin 15 | password: admin 16 | 17 | odm: 18 | auto_mapping: true, 19 | auto_generate_proxy_classes: "%kernel.debug%" 20 | locales: 21 | en: [de, fr] 22 | de: [en, fr] 23 | fr: [en, de] 24 | mappings: 25 | test_additional: 26 | type: attribute 27 | prefix: Doctrine\Bundle\PHPCRBundle\Tests\Fixtures\App\Document 28 | dir: "%kernel.project_dir%/Document" 29 | is_bundle: false 30 | -------------------------------------------------------------------------------- /src/DataCollector/StopWatchLogger.php: -------------------------------------------------------------------------------- 1 | 10 | * @author Lukas Kahwe Smith 11 | */ 12 | final class StopWatchLogger implements LoggerInterface 13 | { 14 | public function __construct(private ?Stopwatch $stopwatch = null) 15 | { 16 | } 17 | 18 | public function startCall($method, ?array $params = null, ?array $env = null): void 19 | { 20 | if (null !== $this->stopwatch) { 21 | $this->stopwatch->start('doctrine_phpcr', 'doctrine_phpcr'); 22 | } 23 | } 24 | 25 | public function stopCall(): void 26 | { 27 | if (null !== $this->stopwatch) { 28 | $this->stopwatch->stop('doctrine_phpcr'); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/EventListener/JackalopeDoctrineDbalSchemaListener.php: -------------------------------------------------------------------------------- 1 | 16 | * @author Johannes M. Schmitt 17 | */ 18 | class JackalopeDoctrineDbalSchemaListener 19 | { 20 | public function __construct( 21 | private RepositorySchema $schema, 22 | ) { 23 | } 24 | 25 | public function postGenerateSchema(GenerateSchemaEventArgs $args): void 26 | { 27 | $schema = $args->getSchema(); 28 | $this->schema->addToSchema($schema); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ManagerRegistryInterface.php: -------------------------------------------------------------------------------- 1 | . 18 | -------------------------------------------------------------------------------- /src/Form/DoctrinePHPCRExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Doctrine\Bundle\PHPCRBundle\Form; 13 | 14 | use Doctrine\Bundle\PHPCRBundle\ManagerRegistryInterface; 15 | use Symfony\Component\Form\AbstractExtension; 16 | 17 | class DoctrinePHPCRExtension extends AbstractExtension 18 | { 19 | private ManagerRegistryInterface $registry; 20 | 21 | public function __construct(ManagerRegistryInterface $registry) 22 | { 23 | $this->registry = $registry; 24 | } 25 | 26 | protected function loadTypes(): array 27 | { 28 | return [ 29 | new Type\DocumentType($this->registry), 30 | ]; 31 | } 32 | 33 | protected function loadTypeGuesser(): PhpcrOdmTypeGuesser 34 | { 35 | return new PhpcrOdmTypeGuesser($this->registry); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Resources/config/jackalope_doctrine_dbal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Doctrine Project 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | 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 THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /tests/Fixtures/fixtures/config/multiple.yml: -------------------------------------------------------------------------------- 1 | doctrine_phpcr: 2 | session: 3 | sessions: 4 | default: 5 | backend: 6 | type: jackrabbit 7 | url: http://a 8 | workspace: default 9 | username: admin 10 | password: admin 11 | 12 | website: 13 | backend: 14 | type: jackrabbit 15 | url: http://b 16 | workspace: website 17 | username: root 18 | password: root 19 | admin_username: admin 20 | admin_password: admin 21 | odm: 22 | auto_generate_proxy_classes: true 23 | document_managers: 24 | default: 25 | session: default 26 | mappings: 27 | SandboxMainBundle: ~ 28 | 29 | website: 30 | session: website 31 | configuration_id: sandbox_magnolia.odm_configuration 32 | mappings: 33 | SandboxMagnoliaBundle: ~ 34 | -------------------------------------------------------------------------------- /tests/Fixtures/App/Kernel.php: -------------------------------------------------------------------------------- 1 | environment; 13 | } 14 | 15 | public function getLogDir(): string 16 | { 17 | return __DIR__.'/var/log'; 18 | } 19 | 20 | public function getProjectDir(): string 21 | { 22 | return __DIR__; 23 | } 24 | 25 | public function registerBundles(): iterable 26 | { 27 | $contents = require __DIR__.'/config/bundles.php'; 28 | foreach ($contents as $class => $envs) { 29 | if (isset($envs['all']) || isset($envs[$this->environment])) { 30 | yield new $class(); 31 | } 32 | } 33 | } 34 | 35 | public function registerContainerConfiguration(LoaderInterface $loader): void 36 | { 37 | $loader->load(__DIR__.'/config/config.php'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Web/WebProfilerTest.php: -------------------------------------------------------------------------------- 1 | enableProfiler(); 19 | 20 | $client->request('GET', '/phpcr_request'); 21 | $this->assertResponseSuccess($client->getResponse()); 22 | 23 | $token = $client->getProfile()->getToken(); 24 | $uri = str_replace('{token}', $token, $uri); 25 | 26 | $client->request('GET', $uri); 27 | $this->assertResponseSuccess($client->getResponse()); 28 | } 29 | 30 | public function provideWebProfilerUris(): array 31 | { 32 | return [ 33 | 'the default panel' => ['/_profiler/{token}'], 34 | 'the PHPCR panel' => ['/_profiler/{token}?panel=phpcr'], 35 | ]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Resources/config/odm_multilang.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 11 | %doctrine_phpcr.odm.locales% 12 | %doctrine_phpcr.odm.default_locale% 13 | 14 | 15 | 17 | 18 | 19 | %doctrine_phpcr.odm.allowed_locales% 20 | %doctrine_phpcr.odm.locale_fallback% 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Command/WorkspaceListCommand.php: -------------------------------------------------------------------------------- 1 | setName('doctrine:phpcr:workspace:list') 21 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 22 | ; 23 | } 24 | 25 | protected function execute(InputInterface $input, OutputInterface $output): int 26 | { 27 | DoctrineCommandHelper::setApplicationPHPCRSession( 28 | $this->getApplication(), 29 | $input->getOption('session'), 30 | true 31 | ); 32 | 33 | return parent::execute($input, $output); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Command/NodeMoveCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class NodeMoveCommand extends BaseNodeMoveCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:node:move') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session') 32 | ); 33 | 34 | return parent::execute($input, $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Command/NodeTouchCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class NodeTouchCommand extends BaseNodeTouchCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:node:touch') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session') 32 | ); 33 | 34 | return parent::execute($input, $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Command/WorkspaceCreateCommand.php: -------------------------------------------------------------------------------- 1 | setName('doctrine:phpcr:workspace:create') 21 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 22 | ; 23 | } 24 | 25 | protected function execute(InputInterface $input, OutputInterface $output): int 26 | { 27 | DoctrineCommandHelper::setApplicationPHPCRSession( 28 | $this->getApplication(), 29 | $input->getOption('session'), 30 | true 31 | ); 32 | 33 | return parent::execute($input, $output); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Command/NodeRemoveCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class NodeRemoveCommand extends BaseNodeRemoveCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:node:remove') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session') 32 | ); 33 | 34 | return parent::execute($input, $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Command/NodesUpdateCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class NodesUpdateCommand extends BaseNodesUpdateCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:nodes:update') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session') 32 | ); 33 | 34 | return parent::execute($input, $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/Fixtures/App/Controller/TestController.php: -------------------------------------------------------------------------------- 1 | registry = $registry; 17 | } 18 | 19 | /** 20 | * Do a simple PHPCR request. 21 | */ 22 | public function phpcrRequest(): Response 23 | { 24 | $dm = $this->registry->getManager(); 25 | 26 | $document = $dm->find(null, '/foo'); 27 | 28 | if (null !== $document) { 29 | $dm->remove($document); 30 | $dm->flush(); 31 | } 32 | 33 | $document = new ReferrerDocument(); 34 | $document->id = '/foo'; 35 | 36 | $dm->persist($document); 37 | $dm->flush(); 38 | 39 | return $this->render('foo.html'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Command/NodeTypeListCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class NodeTypeListCommand extends BaseTypeListCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:node-type:list') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session'), 32 | true 33 | ); 34 | 35 | return parent::execute($input, $output); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Command/WorkspaceExportCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class WorkspaceExportCommand extends BaseWorkspaceExportCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:workspace:export') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session') 32 | ); 33 | 34 | return parent::execute($input, $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Command/WorkspaceImportCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class WorkspaceImportCommand extends BaseWorkspaceImportCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:workspace:import') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session') 32 | ); 33 | 34 | return parent::execute($input, $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Command/WorkspacePurgeCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class WorkspacePurgeCommand extends BaseWorkspacePurgeCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:workspace:purge') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session') 32 | ); 33 | 34 | return parent::execute($input, $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Command/WorkspaceQueryCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class WorkspaceQueryCommand extends BaseWorkspaceQueryCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:workspace:query') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session') 32 | ); 33 | 34 | return parent::execute($input, $output); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/OptionalCommand/ODM/DocumentMigrateClassCommand.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class DocumentMigrateClassCommand extends BaseDocumentMigrateClassCommand 15 | { 16 | protected function configure(): void 17 | { 18 | parent::configure(); 19 | 20 | $this->addOption('dm', null, InputOption::VALUE_REQUIRED, 'The document manager to use for this command'); 21 | } 22 | 23 | protected function execute(InputInterface $input, OutputInterface $output): int 24 | { 25 | $dmName = $input->getOption('dm'); // defaults to null 26 | DoctrineCommandHelper::setApplicationDocumentManager( 27 | $this->getApplication(), 28 | $dmName 29 | ); 30 | 31 | return parent::execute($input, $output); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Command/WorkspaceDeleteCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class WorkspaceDeleteCommand extends BaseWorkspaceDeleteCommand 16 | { 17 | protected function configure(): void 18 | { 19 | parent::configure(); 20 | 21 | $this 22 | ->setName('doctrine:phpcr:workspace:delete') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | DoctrineCommandHelper::setApplicationPHPCRSession( 30 | $this->getApplication(), 31 | $input->getOption('session'), 32 | true 33 | ); 34 | 35 | return parent::execute($input, $output); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Resources/views/Collector/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.github/workflows/static.yml: -------------------------------------------------------------------------------- 1 | name: Static analysis 2 | 3 | on: 4 | push: 5 | branches: 6 | - '[0-9]+.x' 7 | - '[0-9]+.[0-9]+' 8 | - '[0-9]+.[0-9]+.x' 9 | pull_request: 10 | 11 | jobs: 12 | phpstan: 13 | name: PHPStan 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Setup PHP 18 | uses: shivammathur/setup-php@v2 19 | with: 20 | php-version: '8.3' 21 | extensions: "curl,dom,json,xml,dom" 22 | coverage: none 23 | 24 | - name: Checkout code 25 | uses: actions/checkout@v3 26 | 27 | # have to install phpstan ourselves here, the phpstan-ga fails at composer install with weird errors 28 | - name: Install phpstan 29 | run: | 30 | composer require --no-update jackalope/jackalope-doctrine-dbal jackalope/jackalope-jackrabbit phpstan/phpstan 31 | composer update 32 | 33 | - name: PHPStan 34 | run: vendor/bin/phpstan analyze --no-progress 35 | 36 | php-cs-fixer: 37 | name: PHP-CS-Fixer 38 | runs-on: ubuntu-latest 39 | 40 | steps: 41 | - name: Checkout code 42 | uses: actions/checkout@v3 43 | 44 | - name: PHP-CS-Fixer 45 | uses: docker://oskarstark/php-cs-fixer-ga 46 | with: 47 | args: --dry-run --diff 48 | -------------------------------------------------------------------------------- /src/DependencyInjection/Compiler/InitializerPass.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | final class InitializerPass implements CompilerPassInterface 15 | { 16 | public function process(ContainerBuilder $container): void 17 | { 18 | if (!$container->hasDefinition('doctrine_phpcr.initializer_manager')) { 19 | return; 20 | } 21 | 22 | $initializerManagerDef = $container->getDefinition('doctrine_phpcr.initializer_manager'); 23 | $services = $container->findTaggedServiceIds('doctrine_phpcr.initializer'); 24 | 25 | foreach ($services as $id => $attributes) { 26 | $priority = 0; 27 | 28 | if (isset($attributes[0]['priority'])) { 29 | $priority = $attributes[0]['priority']; 30 | } 31 | 32 | $initializerManagerDef->addMethodCall('addInitializer', [ 33 | new Reference($id), $priority, 34 | ]); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/CacheWarmer/UniqueNodeTypeCacheWarmer.php: -------------------------------------------------------------------------------- 1 | registry = $registry; 21 | } 22 | 23 | /** 24 | * This cache warmer is optional as it is just for error 25 | * checking and reporting back to the user. 26 | */ 27 | public function isOptional(): bool 28 | { 29 | return true; 30 | } 31 | 32 | public function warmUp(string $cacheDir, ?string $buildDir = null): array 33 | { 34 | $helper = new UniqueNodeTypeHelper(); 35 | 36 | foreach ($this->registry->getManagers() as $documentManager) { 37 | $helper->checkNodeTypeMappings($documentManager); 38 | } 39 | 40 | return []; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/Functional/Initializer/GenericInitializerTest.php: -------------------------------------------------------------------------------- 1 | getContainer()->get('doctrine_phpcr'); 21 | \assert($managerRegistry instanceof ManagerRegistryInterface); 22 | $dm = $managerRegistry->getManager(); 23 | 24 | // The first run should create a node. 25 | $this->assertNull($dm->find(null, '/test/path')); 26 | 27 | $initializer->init($managerRegistry); 28 | $node = $dm->find(null, '/test/path'); 29 | $this->assertNotNull($node); 30 | 31 | // The second run should not modify the existing node. 32 | $initializer->init($managerRegistry); 33 | $this->assertSame($node, $dm->find(null, '/test/path')); 34 | 35 | $managerRegistry->getConnection()->save(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Form/Type/PathType.php: -------------------------------------------------------------------------------- 1 | registry = $registry; 19 | } 20 | 21 | public function getParent(): string 22 | { 23 | return method_exists(AbstractType::class, 'getBlockPrefix') ? TextType::class : 'text'; 24 | } 25 | 26 | public function getBlockPrefix(): string 27 | { 28 | return 'phpcr_odm_path'; 29 | } 30 | 31 | public function buildForm(FormBuilderInterface $builder, array $options): void 32 | { 33 | $dm = $this->registry->getManager($options['manager_name']); 34 | $transformer = new DocumentToPathTransformer($dm); 35 | $builder->addModelTransformer($transformer); 36 | } 37 | 38 | public function configureOptions(OptionsResolver $resolver): void 39 | { 40 | $resolver->setDefaults([ 41 | 'manager_name' => null, 42 | ]); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DoctrinePHPCRBundle 2 | 3 | [![Build Status](https://github.com/doctrine/DoctrinePHPCRBundle/actions/workflows/test-application.yaml/badge.svg)](https://github.com/doctrine/DoctrinePHPCRBundle/actions) 4 | [![Latest Stable Version](https://poser.pugx.org/doctrine/phpcr-bundle/version.png)](https://packagist.org/packages/doctrine/phpcr-bundle) 5 | [![Total Downloads](https://poser.pugx.org/doctrine/phpcr-bundle/d/total.png)](https://packagist.org/packages/doctrine/phpcr-bundle) 6 | 7 | PHPCR & Doctrine PHPCR-ODM Bundle for the Symfony Framework. 8 | 9 | This bundle integrates PHP Content Repository implementations and the Doctrine PHPCR-ODM into Symfony. 10 | 11 | ## What is Doctrine PHPCR-ODM? 12 | 13 | The Doctrine Project is the home of a selected set of PHP libraries primarily focused on providing persistence 14 | services and related functionality. The PHPCR-ODM project provides an Object - Document Mapper built on top of 15 | the content repository standard PHPCR. 16 | 17 | It leverages the various features of PHPCR like references, children and parent relations and versioning and 18 | adds features of its own like multilanguage. 19 | 20 | ## Documentation 21 | 22 | For information on PHPCR-ODM, see [Doctrine Documentation](https://www.doctrine-project.org/projects/phpcr-odm.html), 23 | and [DoctrinePHPCRBundle](https://www.doctrine-project.org/projects/doctrine-phpcr-bundle.html). 24 | 25 | Read more about PHPCR, the storage layer behind PHPCR-ODM: [PHPCR documentation](https://phpcr.readthedocs.io/en/latest/). 26 | -------------------------------------------------------------------------------- /src/OptionalCommand/ODM/InfoDoctrineCommand.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class InfoDoctrineCommand extends BaseInfoDoctrineCommand 17 | { 18 | protected function configure(): void 19 | { 20 | parent::configure(); 21 | 22 | $this 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The document manager to use for this command.', null) 24 | ->setHelp($this->getHelp().<<<'EOT' 25 | 26 | If you are using multiple document managers you can pick your choice with the 27 | --session option: 28 | 29 | php app/console doctrine:phpcr:mapping:info --session=default 30 | EOT 31 | ); 32 | } 33 | 34 | protected function execute(InputInterface $input, OutputInterface $output): int 35 | { 36 | DoctrineCommandHelper::setApplicationDocumentManager( 37 | $this->getApplication(), 38 | $input->getOption('session') 39 | ); 40 | 41 | return parent::execute($input, $output); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/Fixtures/fixtures/config/multiple.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/Form/DataTransformer/DocumentToPathTransformer.php: -------------------------------------------------------------------------------- 1 | dm = $dm; 16 | } 17 | 18 | /** 19 | * Transform a document into a path. 20 | * 21 | * @param object $document 22 | */ 23 | public function transform(mixed $document): ?string 24 | { 25 | if (null === $document) { 26 | return null; 27 | } 28 | 29 | return $this->dm->getUnitOfWork()->getDocumentId($document); 30 | } 31 | 32 | /** 33 | * Transform a path to its corresponding PHPCR-ODM document. 34 | * 35 | * @param string $path phpcr path 36 | * 37 | * @return object|null returns the document or null if $path is empty 38 | */ 39 | public function reverseTransform(mixed $path): ?object 40 | { 41 | if (!$path) { 42 | return null; 43 | } 44 | 45 | $document = $this->dm->find(null, $path); 46 | 47 | if (!$document) { 48 | throw new TransformationFailedException(sprintf('Could not transform path "%s" to document. Path not found.', $path)); 49 | } 50 | 51 | return $document; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/DataFixtures/PHPCRExecutor.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | final class PHPCRExecutor extends AbstractExecutor 17 | { 18 | private BasePHPCRExecutor $wrappedExecutor; 19 | 20 | public function __construct( 21 | DocumentManagerInterface $dm, 22 | ?PHPCRPurger $purger = null, 23 | private ?InitializerManager $initializerManager = null, 24 | ) { 25 | parent::__construct($dm); 26 | $this->wrappedExecutor = new BasePHPCRExecutor($dm, $purger); 27 | } 28 | 29 | public function purge(): void 30 | { 31 | parent::purge(); 32 | 33 | if ($this->initializerManager) { 34 | $this->initializerManager->setLoggingClosure($this->logger); 35 | $this->initializerManager->initialize(); 36 | } 37 | } 38 | 39 | public function execute(array $fixtures, bool $append = false): void 40 | { 41 | $this->wrappedExecutor->execute($fixtures, $append); 42 | } 43 | 44 | public function getObjectManager(): DocumentManagerInterface 45 | { 46 | return $this->wrappedExecutor->getObjectManager(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/Fixtures/fixtures/config/multiple.php: -------------------------------------------------------------------------------- 1 | loadFromExtension('doctrine_phpcr', [ 4 | 'session' => [ 5 | 'sessions' => [ 6 | 'default' => [ 7 | 'backend' => [ 8 | 'type' => 'jackrabbit', 9 | 'url' => 'http://a', 10 | ], 11 | 'workspace' => 'default', 12 | 'username' => 'admin', 13 | 'password' => 'admin', 14 | ], 15 | 'website' => [ 16 | 'backend' => [ 17 | 'type' => 'jackrabbit', 18 | 'url' => 'http://b', 19 | 'factory' => null, 20 | ], 21 | 'workspace' => 'website', 22 | 'username' => 'root', 23 | 'password' => 'root', 24 | 'admin_username' => 'admin', 25 | 'admin_password' => 'admin', 26 | ], 27 | ], 28 | ], 29 | 'odm' => [ 30 | 'auto_generate_proxy_classes' => true, 31 | 'document_managers' => [ 32 | 'default' => [ 33 | 'session' => 'default', 34 | 'mappings' => [ 35 | 'SandboxMainBundle' => null, 36 | ], 37 | ], 38 | 'website' => [ 39 | 'session' => 'website', 40 | 'configuration_id' => 'sandbox_magnolia.odm_configuration', 41 | 'mappings' => [ 42 | 'SandboxMagnoliaBundle' => null, 43 | ], 44 | ], 45 | ], 46 | ], 47 | ]); 48 | -------------------------------------------------------------------------------- /src/OptionalCommand/ODM/DocumentConvertTranslationCommand.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class DocumentConvertTranslationCommand extends BaseDocumentConvertTranslationCommand 17 | { 18 | protected function configure(): void 19 | { 20 | parent::configure(); 21 | 22 | $this 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The document manager to use for this command.', null) 24 | ->setHelp($this->getHelp().<<<'EOT' 25 | 26 | If you are using multiple document managers you can pick your choice with the 27 | --session option: 28 | 29 | php app/console doctrine:phpcr:document:convert-translation --session=default 30 | EOT 31 | ); 32 | } 33 | 34 | protected function execute(InputInterface $input, OutputInterface $output): int 35 | { 36 | DoctrineCommandHelper::setApplicationDocumentManager( 37 | $this->getApplication(), 38 | $input->getOption('session') 39 | ); 40 | 41 | return parent::execute($input, $output); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/Fixtures/fixtures/config/single.yml: -------------------------------------------------------------------------------- 1 | doctrine_phpcr: 2 | session: 3 | backend: 4 | type: jackrabbit 5 | url: http://localhost:8080/server/ 6 | logging: true 7 | profiling: true 8 | 9 | parameters: 10 | jackalope.factory: Jackalope\Factory 11 | jackalope.check_login_on_server: false 12 | jackalope.disable_stream_wrapper: false 13 | jackalope.auto_lastmodified: true 14 | jackalope.default_header: 'X-ID: %serverid%' 15 | jackalope.jackrabbit_expect: true 16 | workspace: default 17 | username: admin 18 | password: admin 19 | options: 20 | jackalope.fetch_depth: 1 21 | odm: 22 | configuration_id: ~ 23 | auto_mapping: true 24 | mappings: 25 | test: 26 | mapping: true 27 | type: ~ 28 | dir: ~ 29 | prefix: ~ 30 | is_bundle: ~ 31 | auto_generate_proxy_classes: true 32 | proxy_dir: /doctrine/PHPCRProxies 33 | proxy_namespace: PHPCRProxies 34 | 35 | metadata_cache_driver: 36 | type: array 37 | 38 | locales: 39 | en: [de, fr] 40 | de: [en, fr] 41 | fr: [en, de] 42 | locale_fallback: hardcoded 43 | default_locale: fr 44 | 45 | jackrabbit_jar: /path/to/jackrabbit.jar 46 | dump_max_line_length: 20 47 | manager_registry_service_id: my_phpcr_registry 48 | -------------------------------------------------------------------------------- /src/OptionalCommand/ODM/VerifyUniqueNodeTypesMappingCommand.php: -------------------------------------------------------------------------------- 1 | setName('doctrine:phpcr:mapping:verify-unique-node-types') 22 | ->setDescription('Verify that documents claiming to have unique node types are truly unique') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ->setHelp(<<<'EOT' 25 | The %command.name% command checks all mapped PHPCR-ODM documents 26 | and verifies that any claiming to use unique node types are truly unique. 27 | EOT 28 | ); 29 | } 30 | 31 | protected function execute(InputInterface $input, OutputInterface $output): int 32 | { 33 | DoctrineCommandHelper::setApplicationDocumentManager( 34 | $this->getApplication(), 35 | $input->getOption('session') 36 | ); 37 | 38 | return parent::execute($input, $output); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Form/Type/DocumentType.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class JackrabbitCommand extends BaseJackrabbitCommand 15 | { 16 | private const NAME = 'doctrine:phpcr:jackrabbit'; 17 | 18 | public function __construct( 19 | private ?string $jackrabbitJar, 20 | private ?string $workspaceDir, 21 | ) { 22 | parent::__construct(self::NAME); 23 | } 24 | 25 | protected function configure(): void 26 | { 27 | parent::configure(); 28 | 29 | $this 30 | ->setName(self::NAME) 31 | ->setHelp(<<<'EOF' 32 | The doctrine:phpcr:jackrabbit command allows to have a minimal control on the Jackrabbit server from within a 33 | Symfony 2 command. 34 | 35 | If the jackrabbit_jar option is set, it will be used as the Jackrabbit server jar file. 36 | Otherwise, you will have to set the doctrine_phpcr.jackrabbit_jar config parameter to a valid Jackrabbit 37 | server jar file. 38 | EOF 39 | ) 40 | ; 41 | } 42 | 43 | protected function execute(InputInterface $input, OutputInterface $output): int 44 | { 45 | $this->setJackrabbitPath($this->jackrabbitJar); 46 | $this->setWorkspaceDir($this->workspaceDir); 47 | 48 | return parent::execute($input, $output); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/Functional/Command/NodeDumpCommandTest.php: -------------------------------------------------------------------------------- 1 | getRepositoryManager(); 17 | $repositoryManager->loadFixtures([LoadData::class]); 18 | } 19 | 20 | public function testMaxLineLengthOptionIsAppliedSuccessfully(): void 21 | { 22 | $application = new Application(self::$kernel); 23 | 24 | $command = $application->find('doctrine:phpcr:node:dump'); 25 | $commandTester = new CommandTester($command); 26 | $commandTester->execute([ 27 | 'command' => $command->getName(), 28 | '--props' => true, 29 | '--max_line_length' => 120, 30 | 'identifier' => '/test/doc-very-long', 31 | ]); 32 | 33 | $output = $commandTester->getDisplay(); 34 | $this->assertMatchesRegularExpression('/^\s+ - \s+ text \s+ = \s+ .{120} \.\.\.$/mx', $output); 35 | 36 | $commandTester->execute([ 37 | 'command' => $command->getName(), 38 | '--props' => true, 39 | '--max_line_length' => 20, 40 | 'identifier' => '/test/doc-very-long', 41 | ]); 42 | 43 | $output = $commandTester->getDisplay(); 44 | $this->assertMatchesRegularExpression('/^\s+ - \s+ text \s+ = \s+ .{20} \.\.\.$/mx', $output); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Form/DataTransformer/PHPCRNodeToPathTransformer.php: -------------------------------------------------------------------------------- 1 | session = $session; 18 | } 19 | 20 | /** 21 | * Transform a node into a path. 22 | * 23 | * @param NodeInterface|null $node 24 | * 25 | * @return string|null the path to the node or null if $node is null 26 | * 27 | * @throws UnexpectedTypeException if given value is not a NodeInterface 28 | */ 29 | public function transform($node): ?string 30 | { 31 | if (null === $node) { 32 | return null; 33 | } 34 | 35 | if (!$node instanceof NodeInterface) { 36 | throw new UnexpectedTypeException($node, NodeInterface::class); 37 | } 38 | 39 | return $node->getPath(); 40 | } 41 | 42 | /** 43 | * Transform a path to its corresponding PHPCR node. 44 | * 45 | * @param string $path phpcr path 46 | * 47 | * @return NodeInterface|null returns the node or null if $path is empty 48 | * 49 | * @throws ItemNotFoundException if node for a non-empty $path is not found 50 | */ 51 | public function reverseTransform($path): ?NodeInterface 52 | { 53 | if (!$path) { 54 | return null; 55 | } 56 | 57 | return $this->session->getNode($path); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Form/DataTransformer/PHPCRNodeToUuidTransformer.php: -------------------------------------------------------------------------------- 1 | session = $session; 18 | } 19 | 20 | /** 21 | * Transform a node into a uuid. 22 | * 23 | * @param NodeInterface|null $node 24 | * 25 | * @return string|null the uuid to the node or null if $node is null 26 | * 27 | * @throws UnexpectedTypeException if given value is not a NodeInterface 28 | */ 29 | public function transform($node): ?string 30 | { 31 | if (null === $node) { 32 | return null; 33 | } 34 | 35 | if (!$node instanceof NodeInterface) { 36 | throw new UnexpectedTypeException($node, NodeInterface::class); 37 | } 38 | 39 | return $node->getIdentifier(); 40 | } 41 | 42 | /** 43 | * Transform a uuid to its corresponding PHPCR node. 44 | * 45 | * @param string $id uuid 46 | * 47 | * @return NodeInterface|null returns the node or null if the $id is empty 48 | * 49 | * @throws ItemNotFoundException if node for a non-empty $id is not found 50 | */ 51 | public function reverseTransform($id): ?NodeInterface 52 | { 53 | if (!$id) { 54 | return null; 55 | } 56 | 57 | return $this->session->getNodeByIdentifier($id); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/Functional/BaseTestCase.php: -------------------------------------------------------------------------------- 1 | getContainer()) { 18 | self::$kernel->boot(); 19 | } 20 | $container = self::getTestContainer(); 21 | 22 | return new RepositoryManager($container->get('doctrine_phpcr'), $container->get('doctrine_phpcr.initializer_manager')); 23 | } 24 | 25 | protected function assertResponseSuccess(Response $response): void 26 | { 27 | libxml_use_internal_errors(true); 28 | 29 | $dom = new \DOMDocument(); 30 | $dom->loadHTML($response->getContent()); 31 | 32 | $xpath = new \DOMXPath($dom); 33 | $result = $xpath->query('//div[contains(@class,"text-exception")]/h1'); 34 | $exception = null; 35 | if ($result->length) { 36 | $exception = $result->item(0)->nodeValue; 37 | } 38 | 39 | $this->assertEquals(200, $response->getStatusCode(), $exception ? 'Exception: "'.$exception.'"' : ''); 40 | } 41 | 42 | protected static function getTestContainer(): ContainerInterface 43 | { 44 | if (!self::$kernel) { 45 | self::bootKernel(); 46 | } 47 | if (!self::$kernel->getContainer()) { 48 | self::$kernel->boot(); 49 | } 50 | 51 | return self::getContainer(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/OptionalCommand/Jackalope/InitDoctrineDbalCommand.php: -------------------------------------------------------------------------------- 1 | setName('doctrine:phpcr:init:dbal') 23 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 24 | ; 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | $application = $this->getApplication(); 30 | if (!$application instanceof Application) { 31 | throw new \InvalidArgumentException('Expected to find '.Application::class.' but got '. 32 | ($application ? \get_class($application) : null)); 33 | } 34 | 35 | $sessionName = $input->getOption('session'); 36 | if (empty($sessionName)) { 37 | $container = $application->getKernel()->getContainer(); 38 | $sessionName = $container->getParameter('doctrine_phpcr.default_session'); 39 | } 40 | 41 | DoctrineCommandHelper::setApplicationConnection($application, $sessionName); 42 | 43 | return parent::execute($input, $output); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Resources/meta/approval_LGPL-to-MIT/request.eml: -------------------------------------------------------------------------------- 1 | Message-ID: <4FFD76C2.3040806@liip.ch> 2 | Date: Wed, 11 Jul 2012 14:51:14 +0200 3 | From: David Buchmann 4 | User-Agent: Mozilla/5.0 (X11; Linux i686; rv:13.0) Gecko/20120615 Thunderbird/13.0.1 5 | MIME-Version: 1.0 6 | To: Christophe Coevoet , 7 | Florent Cailhol , 8 | Henri Bergius , 9 | Julien 'ruian' Galenski , 10 | Lukas Kahwe Smith , 11 | Simon Holywell , 12 | =?ISO-8859-15?Q?Uwe_J=E4ger?= 13 | Subject: please confirm doctrine phpcr bundle license change to MIT 14 | X-Enigmail-Version: 1.4.2 15 | Content-Type: text/plain; charset=ISO-8859-15 16 | Content-Transfer-Encoding: 7bit 17 | 18 | -----BEGIN PGP SIGNED MESSAGE----- 19 | Hash: SHA1 20 | 21 | hi, 22 | 23 | as the doctrine phpcr bundle was not covered in the switch of doctrine 24 | to MIT [1] i wanted to ask all of you as the contributers to the 25 | bundle if you are ok with switching the bundle license to MIT as well. 26 | 27 | please just reply to this email if it is ok. 28 | 29 | you can see your contributions on the github page 30 | https://github.com/doctrine/DoctrinePHPCRBundle/graphs/contributors 31 | 32 | @stof: github does not show you because the only commit you have was a 33 | merge commit. i still include you for completeness and because i am 34 | not a lawyer :-) 35 | 36 | cheers,david 37 | 38 | [1] http://dlm.beberlei.de/licenses/projects 39 | - -- 40 | Liip AG // Agile Web Development // T +41 26 422 25 11 41 | CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch 42 | 43 | -----BEGIN PGP SIGNATURE----- 44 | Version: GnuPG v1.4.11 (GNU/Linux) 45 | Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ 46 | 47 | iEYEARECAAYFAk/9dr0ACgkQqBnXnqWBgIuNoQCfVOaJ1KAV+9uBM1OCo3Dh/LwD 48 | ILQAn0IZ8C++sO40auTEZfGOUTa5stxV 49 | =h+Mh 50 | -----END PGP SIGNATURE----- 51 | -------------------------------------------------------------------------------- /tests/Unit/Form/DataTransformer/PHPCRNodeToUuidTransformerTest.php: -------------------------------------------------------------------------------- 1 | session = $this->createMock(SessionInterface::class); 31 | $this->transformer = new PHPCRNodeToUuidTransformer($this->session); 32 | $this->node = $this->createMock(Node::class); 33 | } 34 | 35 | public function testTransform(): void 36 | { 37 | $this->node->expects($this->once()) 38 | ->method('getIdentifier') 39 | ->willReturn('/asd'); 40 | $res = $this->transformer->transform($this->node); 41 | $this->assertEquals('/asd', $res); 42 | } 43 | 44 | public function testReverseTransform(): void 45 | { 46 | $this->session->expects($this->once()) 47 | ->method('getNodeByIdentifier') 48 | ->with('/asd') 49 | ->willReturn($this->node); 50 | 51 | $res = $this->transformer->reverseTransform('/asd'); 52 | $this->assertSame($this->node, $res); 53 | } 54 | 55 | public function testReverseTransformEmpty(): void 56 | { 57 | $this->session->expects($this->never()) 58 | ->method('getNodeByIdentifier'); 59 | $res = $this->transformer->reverseTransform(''); 60 | $this->assertNull($res); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/Fixtures/App/Document/ReferrerDocument.php: -------------------------------------------------------------------------------- 1 | documents = new ArrayCollection(); 39 | $this->testDocuments = new ArrayCollection(); 40 | } 41 | 42 | public function addDocument($doc): void 43 | { 44 | $this->documents->add($doc); 45 | } 46 | 47 | public function getSingle() 48 | { 49 | return $this->single; 50 | } 51 | 52 | public function getTestDocument() 53 | { 54 | return $this->testDocument; 55 | } 56 | 57 | /** 58 | * @return Collection 59 | */ 60 | public function getTestDocuments(): Collection 61 | { 62 | return $this->testDocuments; 63 | } 64 | 65 | public function getDocuments() 66 | { 67 | return $this->documents; 68 | } 69 | 70 | /** 71 | * Either define __toString or set property attribute on form mapping. 72 | */ 73 | public function __toString(): string 74 | { 75 | return $this->id; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/Unit/Form/Type/PathTypeTest.php: -------------------------------------------------------------------------------- 1 | reg = $this->createMock(ManagerRegistryInterface::class); 36 | 37 | $this->dm = $this->createMock(DocumentManager::class); 38 | 39 | $this->builder = $this->createMock(FormBuilder::class); 40 | $this->type = new PathType($this->reg); 41 | } 42 | 43 | public function testBuildForm(): void 44 | { 45 | $test = $this; 46 | $this->reg->expects($this->once()) 47 | ->method('getManager') 48 | ->with(null) 49 | ->willReturn($this->dm); 50 | $this->builder->expects($this->once()) 51 | ->method('addModelTransformer') 52 | ->willReturnCallback(function ($transformer) use ($test) { 53 | $test->assertInstanceOf( 54 | DocumentToPathTransformer::class, 55 | $transformer 56 | ); 57 | 58 | return $this->builder; 59 | }); 60 | 61 | $this->type->buildForm($this->builder, ['manager_name' => null]); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/Fixtures/fixtures/config/single.php: -------------------------------------------------------------------------------- 1 | loadFromExtension('doctrine_phpcr', [ 6 | 'session' => [ 7 | 'backend' => [ 8 | 'type' => 'jackrabbit', 9 | 'url' => 'http://localhost:8080/server/', 10 | 'logging' => true, 11 | 'profiling' => true, 12 | 'factory' => null, 13 | 'parameters' => [ 14 | 'jackalope.factory' => Factory::class, 15 | 'jackalope.check_login_on_server' => false, 16 | 'jackalope.disable_stream_wrapper' => false, 17 | 'jackalope.auto_lastmodified' => true, 18 | 'jackalope.default_header' => 'X-ID: %serverid%', 19 | 'jackalope.jackrabbit_expect' => true, 20 | ], 21 | ], 22 | 'workspace' => 'default', 23 | 'username' => 'admin', 24 | 'password' => 'admin', 25 | 'options' => [ 26 | 'jackalope.fetch_depth' => 1, 27 | ], 28 | ], 29 | 30 | 'odm' => [ 31 | 'configuration_id' => null, 32 | 'auto_mapping' => true, 33 | 'auto_generate_proxy_classes' => true, 34 | 'proxy-dir' => '/doctrine/PHPCRProxies', 35 | 'proxy_namespace' => 'PHPCRProxies', 36 | 'mappings' => [ 37 | 'test' => [ 38 | 'mapping' => true, 39 | 'type' => null, 40 | 'dir' => null, 41 | 'prefix' => null, 42 | 'is-bundle' => null, 43 | ], 44 | ], 45 | 46 | 'metadata_cache_driver' => [ 47 | 'type' => 'array', 48 | ], 49 | 50 | 'locales' => [ 51 | 'en' => ['de', 'fr'], 52 | 'de' => ['en', 'fr'], 53 | 'fr' => ['en', 'de'], 54 | ], 55 | 'locale_fallback' => 'hardcoded', 56 | 'default_locale' => 'fr', 57 | ], 58 | 'jackrabbit_jar' => '/path/to/jackrabbit.jar', 59 | 'dump_max_line_length' => 20, 60 | 'manager_registry_service_id' => 'my_phpcr_registry', 61 | ]); 62 | -------------------------------------------------------------------------------- /tests/Unit/DependencyInjection/Compiler/InitializerPassTest.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new InitializerPass()); 16 | 17 | $initializer = new Definition(); 18 | $this->setDefinition( 19 | 'doctrine_phpcr.initializer_manager', 20 | $initializer 21 | ); 22 | } 23 | 24 | public function testInitializerAddNoPriority(): void 25 | { 26 | $initializer = new Definition(); 27 | $initializer->addTag('doctrine_phpcr.initializer'); 28 | $this->setDefinition('test.initializer.1', $initializer); 29 | $this->compile(); 30 | 31 | $this->assertContainerBuilderHasServiceDefinitionWithMethodCall( 32 | 'doctrine_phpcr.initializer_manager', 33 | 'addInitializer', 34 | [ 35 | new Reference('test.initializer.1'), 36 | 0, 37 | ] 38 | ); 39 | } 40 | 41 | public function testInitializerAddWithPriority(): void 42 | { 43 | $initializer = new Definition(); 44 | $initializer->addTag('doctrine_phpcr.initializer', ['priority' => 40]); 45 | $this->setDefinition('test.initializer.1', $initializer); 46 | $this->compile(); 47 | 48 | $this->assertContainerBuilderHasServiceDefinitionWithMethodCall( 49 | 'doctrine_phpcr.initializer_manager', 50 | 'addInitializer', 51 | [ 52 | new Reference('test.initializer.1'), 53 | 40, 54 | ] 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Form/Type/PHPCRReferenceType.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class PHPCRReferenceType extends AbstractType 22 | { 23 | private ?SessionInterface $session; 24 | 25 | public function __construct(?SessionInterface $session = null) 26 | { 27 | $this->session = $session; 28 | } 29 | 30 | public function buildForm(FormBuilderInterface $builder, array $options): void 31 | { 32 | $transformer = match (strtolower($options['transformer_type'])) { 33 | 'uuid' => new PHPCRNodeToUuidTransformer($this->session), 34 | 'path' => new PHPCRNodeToPathTransformer($this->session), 35 | default => throw new InvalidConfigurationException(sprintf(' 36 | The option "transformer_type" must be either "uuid" or "path", "%s" given', 37 | $options['transformer_type'] 38 | )), 39 | }; 40 | 41 | $builder->addModelTransformer($transformer); 42 | } 43 | 44 | public function configureOptions(OptionsResolver $resolver): void 45 | { 46 | $resolver->setDefaults([ 47 | 'transformer_type' => 'uuid', 48 | ]); 49 | } 50 | 51 | public function getParent(): string 52 | { 53 | return method_exists(AbstractType::class, 'getBlockPrefix') ? TextType::class : 'text'; 54 | } 55 | 56 | public function getBlockPrefix(): string 57 | { 58 | return 'phpcr_reference'; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Resources/config/jackalope.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/Command/NodeDumpCommand.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class NodeDumpCommand extends BaseDumpCommand 18 | { 19 | private const NAME = 'doctrine:phpcr:node:dump'; 20 | 21 | public function __construct( 22 | private PhpcrConsoleDumperHelper $consoleDumper, 23 | private int $dumpMaxLineLength, 24 | ) { 25 | parent::__construct(self::NAME); 26 | } 27 | 28 | protected function configure(): void 29 | { 30 | parent::configure(); 31 | 32 | $this 33 | ->setName(self::NAME) 34 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 35 | ; 36 | } 37 | 38 | protected function execute(InputInterface $input, OutputInterface $output): int 39 | { 40 | $application = $this->getApplication(); 41 | DoctrineCommandHelper::setApplicationPHPCRSession( 42 | $application, 43 | $input->getOption('session') 44 | ); 45 | $helperSet = $application->getHelperSet(); 46 | $helperSet->set($this->consoleDumper); 47 | 48 | if (!$input->hasOption('max_line_length')) { 49 | $input->setOption('max_line_length', $this->dumpMaxLineLength); 50 | } 51 | 52 | return parent::execute($input, $output); 53 | } 54 | 55 | public function getApplication(): Application 56 | { 57 | $application = parent::getApplication(); 58 | if (!$application instanceof Application) { 59 | throw new \InvalidArgumentException('Expected to find '.Application::class.' but got '. 60 | ($application ? \get_class($application) : null)); 61 | } 62 | 63 | return $application; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/Unit/Form/Type/PHPCRReferenceTypeTest.php: -------------------------------------------------------------------------------- 1 | createMock(SessionInterface::class); 25 | 26 | // hmm, phpunit won't mock a traversable interface so mocking the concrete class 27 | $this->builder = $this->createMock(FormBuilder::class); 28 | $this->type = new PHPCRReferenceType($session); 29 | } 30 | 31 | public function provideTypes(): array 32 | { 33 | return [ 34 | ['uuid', PHPCRNodeToUuidTransformer::class], 35 | ['path', PHPCRNodeToPathTransformer::class], 36 | ]; 37 | } 38 | 39 | /** 40 | * @dataProvider provideTypes 41 | */ 42 | public function testBuildForm(string $transformerType, string $transformerFqn): void 43 | { 44 | $type = null; 45 | $this->builder->expects($this->once()) 46 | ->method('addModelTransformer') 47 | ->willReturnCallback(function ($transformer) use (&$type) { 48 | $type = \get_class($transformer); 49 | 50 | return $this->builder; 51 | }); 52 | $this->type->buildForm($this->builder, ['transformer_type' => $transformerType]); 53 | 54 | $this->assertEquals($transformerFqn, $type); 55 | } 56 | 57 | public function testInvalidType(): void 58 | { 59 | $this->expectException(InvalidConfigurationException::class); 60 | 61 | $this->type->buildForm($this->builder, ['transformer_type' => 'asdasd']); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /.github/workflows/test-application.yaml: -------------------------------------------------------------------------------- 1 | name: "Test application" 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - "[0-9]+.x" 8 | - "[0-9]+.[0-9]+" 9 | - "[0-9]+.[0-9]+.x" 10 | 11 | jobs: 12 | test: 13 | name: "PHP ${{ matrix.php-version }}, Symfony ${{ matrix.symfony-version }}" 14 | runs-on: "ubuntu-latest" 15 | env: 16 | SYMFONY_REQUIRE: ${{matrix.symfony-require}} 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | include: 22 | - php-version: "8.1" 23 | phpunit-flags: "-v --coverage-text" 24 | symfony-version: "6.0.*" 25 | 26 | - php-version: "8.1" 27 | 28 | - php-version: "8.2" 29 | 30 | - php-version: "8.3" 31 | symfony-version: "7.*" 32 | 33 | steps: 34 | - name: "Checkout project" 35 | uses: "actions/checkout@v4" 36 | 37 | - name: "Install and configure PHP" 38 | uses: "shivammathur/setup-php@v2" 39 | with: 40 | php-version: "${{ matrix.php-version }}" 41 | extensions: "pdo, pdo_sqlite" 42 | tools: "composer:v2" 43 | 44 | - name: "Require specific symfony version" 45 | if: "${{ matrix.symfony-version }}" 46 | run: | 47 | composer require --no-update symfony/flex 48 | composer config --no-plugins allow-plugins.symfony/flex true 49 | 50 | - name: "Require additional dependencies" 51 | if: "${{ matrix.composer-require }}" 52 | run: "composer require --no-update ${{ matrix.composer-require }}" 53 | 54 | - name: "Install dependencies with Composer" 55 | uses: "ramsey/composer-install@v2" 56 | with: 57 | dependency-versions: "${{ matrix.dependencies }}" 58 | composer-options: "--prefer-dist --no-suggest" 59 | 60 | - name: "Setup phpcr" 61 | run: "tests/phpcr_odm_doctrine_dbal.sh" 62 | 63 | - name: "Execute test cases" 64 | run: vendor/bin/phpunit ${{ matrix.phpunit-flags }} 65 | -------------------------------------------------------------------------------- /src/Validator/Constraints/ValidPhpcrOdmValidator.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class ValidPhpcrOdmValidator extends ConstraintValidator 17 | { 18 | private ManagerRegistryInterface $registry; 19 | 20 | public function __construct(ManagerRegistryInterface $registry) 21 | { 22 | $this->registry = $registry; 23 | } 24 | 25 | /** 26 | * @param object $document 27 | */ 28 | public function validate($document, Constraint $constraint): void 29 | { 30 | if (!$constraint instanceof ValidPhpcrOdm) { 31 | throw new \InvalidArgumentException('Expected a constraint of class '.ValidPhpcrOdm::class); 32 | } 33 | $className = \get_class($document); 34 | $dm = $this->registry->getManagerForClass($className); 35 | 36 | if (!$dm instanceof DocumentManagerInterface) { 37 | throw new ConstraintDefinitionException('This document is not managed by the PHPCR ODM.'); 38 | } 39 | 40 | $classMetadata = $dm->getClassMetadata($className); 41 | 42 | if ($classMetadata->getFieldValue($document, $classMetadata->identifier)) { 43 | return; 44 | } 45 | 46 | $parent = $classMetadata->getFieldValue($document, $classMetadata->parentMapping); 47 | 48 | if (empty($parent)) { 49 | $this->context->buildViolation($constraint->message) 50 | ->atPath($classMetadata->parentMapping) 51 | ->addViolation(); 52 | } 53 | 54 | $name = $classMetadata->getFieldValue($document, $classMetadata->nodename); 55 | 56 | if (empty($name)) { 57 | $this->context->buildViolation($constraint->message) 58 | ->atPath($classMetadata->nodename) 59 | ->addViolation(); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Command/RepositoryInitCommand.php: -------------------------------------------------------------------------------- 1 | setName(self::NAME) 33 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 34 | ->setDescription('Initialize the PHPCR repository.') 35 | ->setHelp(<<<'EOT' 36 | Run all initializers tagged with doctrine_phpcr.initializer to create documents 37 | or base paths so the application can work. If phpcr-odm is present, also runs 38 | the doctrine:phpcr:register-system-node-types command. 39 | EOT 40 | ); 41 | } 42 | 43 | protected function execute(InputInterface $input, OutputInterface $output): int 44 | { 45 | if (class_exists(RegisterSystemNodeTypesCommand::class)) { 46 | DoctrineCommandHelper::setApplicationPHPCRSession( 47 | $this->getApplication(), 48 | $input->getOption('session') 49 | ); 50 | 51 | $command = new RegisterSystemNodeTypesCommand(); 52 | $command->setApplication($this->getApplication()); 53 | $command->execute($input, $output); 54 | } 55 | 56 | $this->initializerManager->setLoggingClosure(function ($message) use ($output) { 57 | $output->writeln($message); 58 | }); 59 | 60 | $this->initializerManager->initialize($input->getOption('session')); 61 | 62 | return 0; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/Functional/Form/ChoiceList/PhpcrOdmQueryBuilderLoaderTest.php: -------------------------------------------------------------------------------- 1 | getRepositoryManager(); 21 | $repositoryManager->loadFixtures([LoadData::class]); 22 | 23 | $this->dm = $repositoryManager->getDocumentManager(); 24 | } 25 | 26 | public function testGetByIds(): void 27 | { 28 | $qb = $this->dm->getRepository(TestDocument::class)->createQueryBuilder('e'); 29 | $loader = new PhpcrOdmQueryBuilderLoader($qb, $this->dm); 30 | $ids = ['/test/doc', '/test/doc2', '/test/doc3']; 31 | $documents = $loader->getEntitiesByIds('id', $ids); 32 | $this->assertCount(2, $documents); 33 | foreach ($documents as $i => $document) { 34 | $this->assertInstanceOf(TestDocument::class, $document); 35 | $this->assertContains($document->id, $ids); 36 | } 37 | } 38 | 39 | public function testGetByIdsNotFound(): void 40 | { 41 | $qb = $this->dm->getRepository(TestDocument::class)->createQueryBuilder('e'); 42 | $loader = new PhpcrOdmQueryBuilderLoader($qb, $this->dm); 43 | $documents = $loader->getEntitiesByIds('id', ['/foo/bar']); 44 | $this->assertCount(0, $documents); 45 | } 46 | 47 | public function testGetByIdsFilter(): void 48 | { 49 | $qb = $this->dm->getRepository(TestDocument::class)->createQueryBuilder('e'); 50 | $this->assertInstanceOf(QueryBuilder::class, $qb); 51 | $qb->where()->eq()->field('e.text')->literal('thiswillnotmatch'); 52 | $loader = new PhpcrOdmQueryBuilderLoader($qb, $this->dm); 53 | $documents = $loader->getEntitiesByIds('id', ['/test/doc']); 54 | $this->assertCount(0, $documents); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/Fixtures/fixtures/config/single.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 15 | 21 | Jackalope\Factory 22 | false 23 | false 24 | true 25 | X-ID: %serverid% 26 | true 27 | 28 | 31 | 32 | 33 | 41 | 42 | 49 | 50 | 53 | 54 | de 55 | fr 56 | 57 | 58 | en 59 | fr 60 | 61 | 62 | en 63 | de 64 | 65 | fr 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /tests/Unit/Form/DataTransformer/DocumentToPathTransformerTest.php: -------------------------------------------------------------------------------- 1 | dm = $this->createMock(DocumentManagerInterface::class); 31 | $this->uow = $this->createMock(UnitOfWork::class); 32 | $this->transformer = new DocumentToPathTransformer($this->dm); 33 | $this->document = new \stdClass(); 34 | } 35 | 36 | public function testTransform(): void 37 | { 38 | $this->dm->expects($this->once()) 39 | ->method('getUnitOfWork') 40 | ->willReturn($this->uow); 41 | $this->uow->expects($this->once()) 42 | ->method('getDocumentId') 43 | ->with($this->document) 44 | ->willReturn('/asd'); 45 | 46 | $res = $this->transformer->transform($this->document); 47 | $this->assertEquals('/asd', $res); 48 | } 49 | 50 | public function testReverseTransform(): void 51 | { 52 | $this->dm->expects($this->once()) 53 | ->method('find') 54 | ->with(null, '/asd') 55 | ->willReturn($this->document); 56 | 57 | $res = $this->transformer->reverseTransform('/asd'); 58 | $this->assertSame($this->document, $res); 59 | } 60 | 61 | public function testReverseTransformNotFound(): void 62 | { 63 | $this->dm->expects($this->once()) 64 | ->method('find') 65 | ->with(null, '/asd') 66 | ->willReturn(null); 67 | 68 | $this->expectException(TransformationFailedException::class); 69 | 70 | $res = $this->transformer->reverseTransform('/asd'); 71 | $this->assertSame($this->document, $res); 72 | } 73 | 74 | public function testReverseTransformEmpty(): void 75 | { 76 | $this->dm->expects($this->never()) 77 | ->method('find'); 78 | $res = $this->transformer->reverseTransform(''); 79 | $this->assertNull($res); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/Unit/Form/DataTransformer/PHPCRNodeToPathTransformerTest.php: -------------------------------------------------------------------------------- 1 | session = $this->createMock(SessionInterface::class); 32 | $this->transformer = new PHPCRNodeToPathTransformer($this->session); 33 | $this->node = $this->createMock(Node::class); 34 | } 35 | 36 | public function testTransform(): void 37 | { 38 | $this->node->expects($this->once()) 39 | ->method('getPath') 40 | ->willReturn('/asd'); 41 | 42 | $res = $this->transformer->transform($this->node); 43 | 44 | $this->assertEquals('/asd', $res); 45 | } 46 | 47 | public function testTransformWrongType(): void 48 | { 49 | $this->expectException(UnexpectedTypeException::class); 50 | 51 | $this->transformer->transform(new \stdClass()); 52 | } 53 | 54 | public function testReverseTransform(): void 55 | { 56 | $this->session->expects($this->once()) 57 | ->method('getNode') 58 | ->with('/asd') 59 | ->willReturn($this->node); 60 | 61 | $res = $this->transformer->reverseTransform('/asd'); 62 | 63 | $this->assertSame($this->node, $res); 64 | } 65 | 66 | public function testReverseTransformEmpty(): void 67 | { 68 | $this->session->expects($this->never()) 69 | ->method('getNode'); 70 | 71 | $res = $this->transformer->reverseTransform(''); 72 | 73 | $this->assertNull($res); 74 | } 75 | 76 | /** 77 | * Check the transformer does not hide the exception thrown by PHPCR. 78 | */ 79 | public function testReverseTransformNotFound(): void 80 | { 81 | $this->session->expects($this->once()) 82 | ->method('getNode') 83 | ->with('/not/existing/node') 84 | ->will($this->throwException(new \Exception())); 85 | 86 | $this->expectException(\Exception::class); 87 | $this->transformer->reverseTransform('/not/existing/node'); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Initializer/GenericInitializer.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class GenericInitializer implements InitializerInterface, SessionAwareInitializerInterface 22 | { 23 | private string $name; 24 | private ?string $cnd; 25 | 26 | /** 27 | * List of base paths to create. 28 | * 29 | * @var string[] 30 | */ 31 | private array $basePaths; 32 | 33 | /** 34 | * Name of the session in which this initializer should run. 35 | * 36 | * If this is null, the default session is used. 37 | */ 38 | private ?string $sessionName = null; 39 | 40 | /** 41 | * @param string $name name to identify this initializer instance 42 | * @param array $basePaths a list of base paths to create if not existing 43 | * @param string|null $cnd node type and namespace definitions in cnd 44 | * format, pass null to not create any node types 45 | */ 46 | public function __construct(string $name, array $basePaths, ?string $cnd = null) 47 | { 48 | $this->cnd = $cnd; 49 | $this->basePaths = $basePaths; 50 | $this->name = $name; 51 | } 52 | 53 | public function init(ManagerRegistryInterface $registry): void 54 | { 55 | $session = $registry->getConnection($this->sessionName); 56 | 57 | if ($this->cnd) { 58 | $this->registerCnd($session, $this->cnd); 59 | } 60 | if (\count($this->basePaths)) { 61 | $this->createBasePaths($session, $this->basePaths); 62 | } 63 | } 64 | 65 | public function getName(): string 66 | { 67 | return $this->name; 68 | } 69 | 70 | public function setSessionName(string $sessionName): void 71 | { 72 | $this->sessionName = $sessionName; 73 | } 74 | 75 | protected function registerCnd(SessionInterface $session, string $cnd): void 76 | { 77 | $session->getWorkspace()->getNodeTypeManager()->registerNodeTypesCnd($cnd, true); 78 | } 79 | 80 | protected function createBasePaths(SessionInterface $session, array $basePaths): void 81 | { 82 | foreach ($basePaths as $path) { 83 | NodeHelper::createPath($session, $path); 84 | } 85 | 86 | $session->save(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/ManagerRegistry.php: -------------------------------------------------------------------------------- 1 | container = $container; 28 | 29 | parent::__construct( 30 | 'PHPCR', 31 | $connections, 32 | $entityManagers, 33 | $defaultConnectionName, 34 | $defaultEntityManagerName, 35 | $proxyInterfaceName 36 | ); 37 | } 38 | 39 | public function getManager($name = null): DocumentManagerInterface 40 | { 41 | $dm = parent::getManager($name); 42 | \assert($dm instanceof DocumentManagerInterface); 43 | 44 | return $dm; 45 | } 46 | 47 | public function resetManager($name = null): DocumentManagerInterface 48 | { 49 | $dm = parent::resetManager($name); 50 | \assert($dm instanceof DocumentManagerInterface); 51 | 52 | return $dm; 53 | } 54 | 55 | public function getManagerForClass($class = null): ?DocumentManagerInterface 56 | { 57 | $dm = parent::getManagerForClass($class); 58 | \assert(null === $dm || $dm instanceof DocumentManagerInterface); 59 | 60 | return $dm; 61 | } 62 | 63 | public function getConnection($name = null): SessionInterface 64 | { 65 | $conn = parent::getConnection($name); 66 | \assert($conn instanceof SessionInterface); 67 | 68 | return $conn; 69 | } 70 | 71 | /** 72 | * Get the admin connection associated to the connection. 73 | */ 74 | public function getAdminConnection(?string $name = null): SessionInterface 75 | { 76 | if (null === $name) { 77 | $name = $this->getDefaultConnectionName(); 78 | } 79 | 80 | $serviceName = sprintf('doctrine_phpcr.admin.%s_session', $name); 81 | 82 | $connections = $this->getConnectionNames(); 83 | if (!isset($connections[$name])) { 84 | throw new \InvalidArgumentException(sprintf('Doctrine %s Connection named "%s" does not exist.', $this->getName(), $name)); 85 | } 86 | 87 | $connection = $this->getService($serviceName); 88 | \assert($connection instanceof SessionInterface); 89 | 90 | return $connection; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/Fixtures/App/DataFixtures/PHPCR/LoadData.php: -------------------------------------------------------------------------------- 1 | setNodename('test'); 30 | $base->setParentDocument($manager->find(null, '/')); 31 | 32 | $doc = new TestDocument(); 33 | $doc->parent = $base; 34 | $doc->nodename = 'doc'; 35 | $doc->bool = true; 36 | $doc->date = new \DateTime('2014-01-14'); 37 | $doc->integer = 42; 38 | $doc->long = 24; 39 | $doc->number = 3.14; 40 | $doc->text = 'text content'; 41 | 42 | $manager->persist($doc); 43 | 44 | $doc = new TestDocument(); 45 | $doc->parent = $base; 46 | $doc->nodename = 'doc2'; 47 | $doc->bool = true; 48 | $doc->date = new \DateTime('2014-01-14'); 49 | $doc->integer = 42; 50 | $doc->long = 24; 51 | $doc->number = 3.14; 52 | $doc->text = 'text content'; 53 | 54 | $manager->persist($doc); 55 | 56 | $ref = new ReferrerDocument(); 57 | $ref->id = '/test/ref'; 58 | $ref->addDocument($doc); 59 | 60 | $manager->persist($ref); 61 | 62 | $doc = new TestDocument(); 63 | $doc->parent = $base; 64 | $doc->nodename = 'doc-very-long'; 65 | $doc->bool = true; 66 | $doc->date = new \DateTime('2014-01-14'); 67 | $doc->integer = 42; 68 | $doc->long = 24; 69 | $doc->number = 3.14; 70 | $doc->text = 'Lorem ipsum dolor sit amet, consectetur adipiscing'. 71 | ' elit. Aenean ultrices consectetur ex. Integer fringilla'. 72 | ' augue sed lacus blandit, non aliquam leo dapibus. Sed'. 73 | ' ac dolor lorem. Sed non ullamcorper nisl.'; 74 | 75 | $manager->persist($doc); 76 | 77 | $manager->flush(); 78 | 79 | $node = $manager->getPhpcrSession()->getNode('/test/doc'); 80 | $node->addNode('child'); 81 | $node->addNode('second'); 82 | $manager->getPhpcrSession()->save(); 83 | 84 | $manager->clear(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Command/NodeTypeRegisterCommand.php: -------------------------------------------------------------------------------- 1 | %s directory of activated bundles. 26 | EOT; 27 | $help = $this->getHelp().sprintf($newHelp, self::BUNDLE_NT_PATH); 28 | 29 | $this 30 | ->setName('doctrine:phpcr:node-type:register') 31 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 32 | ->setHelp($help) 33 | ; 34 | } 35 | 36 | protected function execute(InputInterface $input, OutputInterface $output): int 37 | { 38 | $application = $this->getApplication(); 39 | if (!$application instanceof Application) { 40 | throw new \InvalidArgumentException('Expected to find '.Application::class.' but got '. 41 | ($application ? \get_class($application) : null)); 42 | } 43 | 44 | DoctrineCommandHelper::setApplicationPHPCRSession( 45 | $application, 46 | $input->getOption('session'), 47 | true 48 | ); 49 | 50 | $definitions = $input->getArgument('cnd-file'); 51 | 52 | // if no cnd-files, automatically load from bundles 53 | if (0 === \count($definitions)) { 54 | $bundles = $application->getKernel()->getBundles(); 55 | 56 | $candidatePaths = []; 57 | foreach ($bundles as $bundle) { 58 | $candidatePath = sprintf('%s/%s', $bundle->getPath(), self::BUNDLE_NT_PATH); 59 | 60 | if (!file_exists($candidatePath)) { 61 | continue; 62 | } 63 | 64 | $candidatePaths[] = $candidatePath; 65 | } 66 | 67 | if (0 === \count($candidatePaths)) { 68 | $output->writeln(sprintf( 69 | 'No definition files specified and could not find any definitions in any /%s folders. Aborting.', 70 | self::BUNDLE_NT_PATH 71 | )); 72 | 73 | return 1; 74 | } 75 | 76 | $input->setArgument('cnd-file', $candidatePaths); 77 | } 78 | 79 | return parent::execute($input, $output); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/Unit/Initializer/GenericInitializerTest.php: -------------------------------------------------------------------------------- 1 | registry = $this->createMock(ManagerRegistryInterface::class); 40 | 41 | $this->session = $this->createMock(SessionInterface::class); 42 | $this->workspace = $this->createMock(WorkspaceInterface::class); 43 | $this->nodeTypeManager = $this->createMock(NodeTypeManager::class); 44 | $this->node = $this->createMock(Node::class); 45 | } 46 | 47 | public function provideInitializer(): array 48 | { 49 | return [ 50 | [ 51 | 'test_init', [ 52 | 'foo/bar/1', 'foobar/2', 53 | ], 'this is CND', 54 | ], 55 | ]; 56 | } 57 | 58 | /** 59 | * @dataProvider provideInitializer 60 | */ 61 | public function testInitializer(string $name, array $basePaths, string $cnd): void 62 | { 63 | $this->registry->expects($this->once()) 64 | ->method('getConnection') 65 | ->willReturn($this->session); 66 | 67 | if ($cnd) { 68 | $this->session->expects($this->once()) 69 | ->method('getWorkspace') 70 | ->willReturn($this->workspace); 71 | $this->workspace->expects($this->once()) 72 | ->method('getNodeTypeManager') 73 | ->willReturn($this->nodeTypeManager); 74 | $this->nodeTypeManager->expects($this->once()) 75 | ->method('registerNodeTypesCnd') 76 | ->with($cnd); 77 | } 78 | 79 | if ($basePaths) { 80 | $this->node->expects($this->any()) 81 | ->method('addNode') 82 | ->willReturn($this->node); 83 | $this->session->expects($this->exactly(\count($basePaths))) 84 | ->method('getRootNode') 85 | ->willReturn($this->node); 86 | } 87 | 88 | $initializer = new GenericInitializer($name, $basePaths, $cnd); 89 | $initializer->init($this->registry); 90 | $this->assertEquals($name, $initializer->getName()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/Fixtures/App/Document/TestDocument.php: -------------------------------------------------------------------------------- 1 | referrers = new ArrayCollection(); 75 | $this->mixedReferrers = new ArrayCollection(); 76 | $this->children = new ArrayCollection(); 77 | } 78 | 79 | public function getReferrers(): Collection 80 | { 81 | return $this->referrers; 82 | } 83 | 84 | public function addReferrer($referrer): void 85 | { 86 | $this->referrers->add($referrer); 87 | } 88 | 89 | public function removeReferrer($referrer): void 90 | { 91 | $this->referrers->remove($referrer); 92 | } 93 | 94 | public function getMixedReferrers(): Collection 95 | { 96 | return $this->mixedReferrers; 97 | } 98 | 99 | public function getChildren(): Collection 100 | { 101 | return $this->children; 102 | } 103 | 104 | public function addChild($referrer): void 105 | { 106 | $this->children->add($referrer); 107 | } 108 | 109 | public function removeChild($referrer): void 110 | { 111 | $this->children->remove($referrer); 112 | } 113 | 114 | /** 115 | * Either define __toString or set property attribute on form mapping. 116 | */ 117 | public function __toString(): string 118 | { 119 | return $this->id; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Command/DoctrineCommandHelper.php: -------------------------------------------------------------------------------- 1 | 22 | */ 23 | abstract class DoctrineCommandHelper 24 | { 25 | /** 26 | * Prepare just the DBAL connection for the init command where no session is available yet. 27 | */ 28 | public static function setApplicationConnection(Application $application, string $sessionName): void 29 | { 30 | $connectionService = sprintf('doctrine_phpcr.jackalope_doctrine_dbal.%s_connection', $sessionName); 31 | $helperSet = $application->getHelperSet(); 32 | $helperSet->set(new DoctrineDbalHelper($application->getKernel()->getContainer()->get($connectionService))); 33 | } 34 | 35 | /** 36 | * Prepare the DBAL connection and the PHPCR session. 37 | */ 38 | public static function setApplicationPHPCRSession(Application $application, ?string $sessionName = null, bool $admin = false): void 39 | { 40 | $registry = self::getRegistry($application); 41 | $session = $admin ? $registry->getAdminConnection($sessionName) : $registry->getConnection($sessionName); 42 | 43 | $helperSet = $application->getHelperSet(); 44 | if (class_exists(Version::class)) { 45 | $helperSet->set(new DocumentManagerHelper($session)); 46 | } else { 47 | $helperSet->set(new PhpcrHelper($session)); 48 | } 49 | 50 | if ($session instanceof JackalopeSession 51 | && ($session->getTransport() instanceof DbalClient 52 | || $session->getTransport() instanceof DbalLoggingClient 53 | ) 54 | ) { 55 | $helperSet->set(new DoctrineDbalHelper($session->getTransport()->getConnection())); 56 | } 57 | } 58 | 59 | /** 60 | * Select which document manager should be used. 61 | */ 62 | public static function setApplicationDocumentManager(Application $application, ?string $dmName): void 63 | { 64 | $documentManager = self::getRegistry($application)->getManager($dmName); 65 | \assert($documentManager instanceof DocumentManagerInterface); 66 | 67 | $helperSet = $application->getHelperSet(); 68 | $helperSet->set(new DocumentManagerHelper(null, $documentManager)); 69 | } 70 | 71 | private static function getRegistry(Application $application): ManagerRegistryInterface 72 | { 73 | $registry = $application->getKernel()->getContainer()->get('doctrine_phpcr'); 74 | if (!$registry instanceof ManagerRegistryInterface) { 75 | throw new ConfigurationException('Registry was expected to implement '.ManagerRegistryInterface::class); 76 | } 77 | 78 | return $registry; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/Functional/Form/Type/DocumentTypeTest.php: -------------------------------------------------------------------------------- 1 | getRepositoryManager(); 26 | $repositoryManager->loadFixtures([LoadData::class]); 27 | $this->dm = $repositoryManager->getDocumentManager(); 28 | $document = $this->dm->find(null, '/test/doc'); 29 | $this->assertNotNull($document, 'fixture loading not working'); 30 | $this->referrer = $this->dm->find(null, '/test/ref'); 31 | $this->assertNotNull($this->referrer, 'fixture loading not working'); 32 | } 33 | 34 | private function createFormBuilder(ReferrerDocument $data): FormBuilderInterface 35 | { 36 | return self::getTestContainer()->get('form.factory')->createBuilder(FormType::class, $data, []); 37 | } 38 | 39 | /** 40 | * Render a form and return the HTML. 41 | */ 42 | private function renderForm(FormBuilderInterface $formBuilder): string 43 | { 44 | $formView = $formBuilder->getForm()->createView(); 45 | /** @var Environment $twig */ 46 | $twig = self::getTestContainer()->get('twig'); 47 | 48 | return $twig->render('form.html.twig', ['form' => $formView]); 49 | } 50 | 51 | public function testUnfiltered(): void 52 | { 53 | $formBuilder = $this->createFormBuilder($this->referrer); 54 | 55 | $formBuilder 56 | ->add('single', DocumentType::class, [ 57 | 'class' => TestDocument::class, 58 | ]) 59 | ; 60 | 61 | $html = $this->renderForm($formBuilder); 62 | $this->assertStringContainsString('assertStringNotContainsString(' 11 | */ 12 | class InitializerManager 13 | { 14 | /** 15 | * @var InitializerInterface[] 16 | */ 17 | private array $initializers = []; 18 | 19 | private ManagerRegistryInterface $registry; 20 | private ?\Closure $loggingClosure = null; 21 | 22 | /** 23 | * @var InitializerInterface[] 24 | */ 25 | private array $sortedInitializers; 26 | 27 | public function __construct(ManagerRegistryInterface $registry) 28 | { 29 | $this->registry = $registry; 30 | } 31 | 32 | public function setLoggingClosure(?\Closure $closure = null): void 33 | { 34 | $this->loggingClosure = $closure; 35 | } 36 | 37 | /** 38 | * Add an initializer to this manager at the specified priority. 39 | * 40 | * @param int $priority The higher the number, the earlier the initializer is executed 41 | */ 42 | public function addInitializer(InitializerInterface $initializer, int $priority = 0): void 43 | { 44 | if (empty($this->initializers[$priority])) { 45 | $this->initializers[$priority] = []; 46 | } 47 | 48 | $this->initializers[$priority][] = $initializer; 49 | $this->sortedInitializers = []; 50 | } 51 | 52 | /** 53 | * Iterate over the registered initializers and execute each of them. 54 | */ 55 | public function initialize(?string $sessionName = null): void 56 | { 57 | $loggingClosure = $this->loggingClosure; 58 | 59 | foreach ($this->getInitializers() as $initializer) { 60 | if ($loggingClosure) { 61 | $loggingClosure(sprintf('Executing initializer: %s', $initializer->getName())); 62 | } 63 | 64 | // handle specified session if present 65 | if ($sessionName) { 66 | if ($initializer instanceof SessionAwareInitializerInterface) { 67 | $initializer->setSessionName($sessionName); 68 | } elseif ($loggingClosure) { 69 | $loggingClosure(sprintf('Initializer "%s" does not implement SessionAwareInitializerInterface, "session" parameter will be omitted.', $initializer->getName())); 70 | } 71 | } 72 | 73 | $initializer->init($this->registry); 74 | } 75 | } 76 | 77 | /** 78 | * Return the ordered initializers. 79 | * 80 | * @return InitializerInterface[] 81 | */ 82 | private function getInitializers(): array 83 | { 84 | if (empty($this->sortedInitializers)) { 85 | $this->sortedInitializers = $this->sortInitializers(); 86 | } 87 | 88 | return $this->sortedInitializers; 89 | } 90 | 91 | /** 92 | * Sort initializers by priority. 93 | * 94 | * The highest priority number is the highest priority (reverse sorting). 95 | * 96 | * @return InitializerInterface[] 97 | */ 98 | private function sortInitializers(): array 99 | { 100 | $sortedInitializers = []; 101 | krsort($this->initializers); 102 | 103 | foreach ($this->initializers as $initializers) { 104 | $sortedInitializers = array_merge($sortedInitializers, $initializers); 105 | } 106 | 107 | return $sortedInitializers; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Command/MigratorMigrateCommand.php: -------------------------------------------------------------------------------- 1 | setName(self::NAME) 28 | ->setDescription('Migrates PHPCR data.') 29 | ->addArgument('migrator_name', InputArgument::OPTIONAL, 'The name of the alias/service to be used to migrate the data.') 30 | ->addOption('identifier', null, InputOption::VALUE_REQUIRED, 'Path or UUID of the node to migrate', '/') 31 | ->addOption('depth', null, InputOption::VALUE_REQUIRED, 'Set to a number to limit how deep into the tree to recurse', '-1') 32 | ->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command') 33 | ->setHelp(<<<'EOT' 34 | To find the available 'migrators' run this command without an input argument 35 | EOT 36 | ) 37 | ; 38 | } 39 | 40 | protected function execute(InputInterface $input, OutputInterface $output): int 41 | { 42 | $application = $this->getApplication(); 43 | if (!$application instanceof Application) { 44 | throw new \InvalidArgumentException('Expected to find '.Application::class.' but got '. 45 | ($application ? \get_class($application) : null)); 46 | } 47 | DoctrineCommandHelper::setApplicationPHPCRSession( 48 | $application, 49 | $input->getOption('session') 50 | ); 51 | $session = $this->getPhpcrSession(); 52 | 53 | $migrators = $this->container->getParameter('doctrine_phpcr.migrate.migrators'); 54 | 55 | $migratorName = $input->getArgument('migrator_name'); 56 | if (!$migratorName) { 57 | $output->write('Available migrators:', true); 58 | $output->write(implode("\n", array_keys($migrators)), true); 59 | 60 | return 0; 61 | } 62 | 63 | $id = $migrators[$migratorName] ?? null; 64 | if (!$id || !$this->container->has($id)) { 65 | throw new \InvalidArgumentException("Wrong value '$migratorName' for migrator_name argument.\nAvailable migrators:\n".implode("\n", array_keys($migrators))); 66 | } 67 | 68 | $migrator = $this->container->get($id); 69 | if (!$migrator instanceof MigratorInterface) { 70 | throw new \InvalidArgumentException('Looked for a '.MigratorInterface::class.' but found '.($migrator ? \get_class($migrator) : $migrator)); 71 | } 72 | $migrator->init($session, $output); 73 | 74 | $identifier = $input->getOption('identifier'); 75 | $depth = $input->getOption('depth'); 76 | $output->write("Migrating identifier '$identifier' with depth '$depth' using '$migratorName'", true); 77 | $exitCode = $migrator->migrate($identifier, $depth); 78 | 79 | if (0 === $exitCode) { 80 | $output->write('Successful', true); 81 | } else { 82 | $output->write('Failed!', true); 83 | } 84 | 85 | return $exitCode; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Resources/config/phpcr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 26 | 27 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | 54 | 55 | 58 | 59 | %doctrine_phpcr.sessions% 60 | %doctrine_phpcr.odm.document_managers% 61 | %doctrine_phpcr.default_session% 62 | %doctrine_phpcr.odm.default_document_manager% 63 | Doctrine\Common\Proxy\Proxy 64 | 65 | 66 | 68 | 69 | 70 | 71 | 72 | 74 | 75 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/Command/PhpcrShellCommand.php: -------------------------------------------------------------------------------- 1 | setName('doctrine:phpcr:shell'); 23 | $this->addArgument('cmd', InputArgument::IS_ARRAY); 24 | $this->addOption('session', null, InputOption::VALUE_REQUIRED, 'The session to use for this command'); 25 | $this->setDescription('Proxy for an embedded PHPCR Shell. Commands should be quoted'); 26 | $this->setHelp(<<<'EOT' 27 | This command will send commands to an embedded PHPCR shell. For it to work you 28 | will need to have the phpcr-shell dependency installed. 29 | 30 | To list the available sub-commands: 31 | 32 | $ %command.full_name% 33 | 34 | Simple commands can be executed as follows: 35 | 36 | $ %command.full_name% node:list 37 | $ %command.full_name% node:create foobar my:nodetype 38 | $ %command.full_name% session:namespace:set foo http://foobar.com/foo 39 | 40 | Due to limitations with the Symfony Console component, if you want to specify 41 | options you will need to quote the entire sub-command: 42 | 43 | $ %command.full_name% "node:list /path/to/some/node --level=3 --template" 44 | 45 | You can execute SELECT JCR-SQL2 queries as follows: 46 | 47 | $ php app/console phpcr "SELECT * FROM [nt:unstructured]" 48 | 49 | NOTE: When executing single commands the session is saved automatically. This 50 | is in contrast to the shell, where the session has to be explicitly saved with 51 | the session:save command. 52 | EOT 53 | ); 54 | } 55 | 56 | protected function execute(InputInterface $input, OutputInterface $output): int 57 | { 58 | if (!class_exists(SessionApplication::class)) { 59 | throw new \InvalidArgumentException( 60 | 'PHPCR-Shell not installed as a dependency. Add the "phpcr/phpcr-shell" to your '. 61 | 'composer.json file to use this command' 62 | ); 63 | } 64 | $application = $this->getApplication(); 65 | if (!$application instanceof Application) { 66 | throw new \InvalidArgumentException('Expected to find '.Application::class.' but got '. 67 | ($application ? \get_class($application) : null)); 68 | } 69 | DoctrineCommandHelper::setApplicationPHPCRSession( 70 | $application, 71 | $input->getOption('session') 72 | ); 73 | 74 | $args = $input->getArgument('cmd'); 75 | $launchShell = empty($args); 76 | $session = $this->getPhpcrSession(); 77 | 78 | // If no arguments supplied, launch the shell with the embedded application 79 | if ($launchShell) { 80 | PhpcrShell::createEmbeddedShell($session)->run(); 81 | 82 | return 0; 83 | } 84 | 85 | // else try and run the command using the given input 86 | $phpcrApplication = PhpcrShell::createEmbeddedApplication($session); 87 | $exitCode = $phpcrApplication->runWithStringInput(implode(' ', $args), $output); 88 | 89 | // always save the session after running a single command 90 | $session->save(); 91 | 92 | return $exitCode; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Resources/meta/approval_LGPL-to-MIT/bergie.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: david.buchmann@liip.ch 2 | Received: by 10.229.12.79 with SMTP id w15csp23699qcw; 3 | Wed, 11 Jul 2012 06:22:39 -0700 (PDT) 4 | Received: by 10.14.189.10 with SMTP id b10mr11965009een.9.1342012958956; 5 | Wed, 11 Jul 2012 06:22:38 -0700 (PDT) 6 | Return-Path: 7 | Received: from psmtp.com (eu1sys200amx133.postini.com. [207.126.144.222]) 8 | by mx.google.com with SMTP id x56si1010072eea.113.2012.07.11.06.22.38 9 | (version=TLSv1/SSLv3 cipher=OTHER); 10 | Wed, 11 Jul 2012 06:22:38 -0700 (PDT) 11 | Received-SPF: pass (google.com: domain of henri.bergius@gmail.com designates 209.85.161.177 as permitted sender) client-ip=209.85.161.177; 12 | Authentication-Results: mx.google.com; spf=pass (google.com: domain of henri.bergius@gmail.com designates 209.85.161.177 as permitted sender) smtp.mail=henri.bergius@gmail.com; dkim=pass header.i=@gmail.com 13 | Received: from mail-gg0-f177.google.com ([209.85.161.177]) (using TLSv1) by eu1sys200amx133.postini.com ([207.126.147.10]) with SMTP; 14 | Wed, 11 Jul 2012 13:22:38 GMT 15 | Received: by ggcs5 with SMTP id s5so1437469ggc.22 16 | for ; Wed, 11 Jul 2012 06:22:37 -0700 (PDT) 17 | DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; 18 | d=gmail.com; s=20120113; 19 | h=mime-version:sender:in-reply-to:references:date 20 | :x-google-sender-auth:message-id:subject:from:to:cc:content-type; 21 | bh=Pa3twSK+m65SymagBm3/8oZvnArB0LgEyUca/se2pe8=; 22 | b=esOISpHGG19OxZRmOW1T0C0AeI8OV6FPNhoRHov12S0eklQf54UvlSdAW+9Kcd5+ew 23 | TaxqrHmwLEsXN/iDgMAq+Abzihriinog/i28JmJkKh/ZxsAaFmsO5aGux5fry4Ju+x3e 24 | SHsA0aX7DfbdYyf0sb/vkgFsVPnGpsPFJlgO+XfxSbUnwlaJe+4Ep+H1Jrgk+XCIJ/Pr 25 | 6m7pQA1E7u9kkBteAZ+esC7p7W9VC/JuDWvOYENkc6pWMMszPqgYVZ+oU5ICz3DnEGoq 26 | IL6Wy6iSBoqgSnlz42YQx8mZpoIL14Tn6a4xqzXwctPxJacuIYx7eMoWuOyqgb7vnRNV 27 | ws9A== 28 | MIME-Version: 1.0 29 | Received: by 10.50.140.4 with SMTP id rc4mr14514296igb.68.1342012956979; Wed, 30 | 11 Jul 2012 06:22:36 -0700 (PDT) 31 | Sender: henri.bergius@gmail.com 32 | Received: by 10.50.207.9 with HTTP; Wed, 11 Jul 2012 06:22:36 -0700 (PDT) 33 | In-Reply-To: <4FFD76C2.3040806@liip.ch> 34 | References: <4FFD76C2.3040806@liip.ch> 35 | Date: Wed, 11 Jul 2012 15:22:36 +0200 36 | X-Google-Sender-Auth: 6a3YQvOjueDOebannDknjfx8WpE 37 | Message-ID: 38 | Subject: Re: please confirm doctrine phpcr bundle license change to MIT 39 | From: Henri Bergius 40 | To: David Buchmann 41 | Cc: Christophe Coevoet , Florent Cailhol , 42 | "Julien 'ruian' Galenski" , Lukas Kahwe Smith , 43 | Simon Holywell , =?ISO-8859-1?Q?Uwe_J=E4ger?= 44 | Content-Type: text/plain; charset=ISO-8859-1 45 | X-pstn-dkim: 1 skipped:not-enabled 46 | X-pstn-nxpr: disp=neutral, envrcpt=david.buchmann@liip.ch 47 | X-pstn-nxp: bodyHash=9b549671f4afb9eeaff2ad8e6a4c2f2e0ae0d961, 48 | headerHash=3af464feaa44cba7bfc2d6836f92e9bd2e6337a8, keyName=4, 49 | rcptHash=f64fd3aad49032f902032049efab1b9761a3df63, sourceip=209.85.161.177, version=1 50 | 51 | Hi, 52 | 53 | On Wed, Jul 11, 2012 at 2:51 PM, David Buchmann wrote: 54 | > as the doctrine phpcr bundle was not covered in the switch of doctrine 55 | > to MIT [1] i wanted to ask all of you as the contributers to the 56 | > bundle if you are ok with switching the bundle license to MIT as well. 57 | > 58 | > please just reply to this email if it is ok. 59 | 60 | +1 61 | 62 | -- 63 | Henri Bergius 64 | Motorcycle Adventures and Free Software 65 | http://bergie.iki.fi/ 66 | 67 | Jabber: henri.bergius@gmail.com 68 | Microblogs: @bergie 69 | -------------------------------------------------------------------------------- /src/Form/ChoiceList/PhpcrOdmQueryBuilderLoader.php: -------------------------------------------------------------------------------- 1 | 18 | * @author Ivan Borzenkov 19 | */ 20 | final class PhpcrOdmQueryBuilderLoader implements EntityLoaderInterface 21 | { 22 | private QueryBuilder $queryBuilder; 23 | 24 | /** 25 | * @param QueryBuilder|\Closure $queryBuilder 26 | */ 27 | public function __construct($queryBuilder, ?DocumentManagerInterface $manager = null, ?string $class = null) 28 | { 29 | // If a query builder was passed, it must be a closure or QueryBuilder 30 | // instance 31 | if (!($queryBuilder instanceof QueryBuilder || $queryBuilder instanceof \Closure)) { 32 | throw new UnexpectedTypeException($queryBuilder, ObjectManager::class.' or \Closure'); 33 | } 34 | 35 | if ($queryBuilder instanceof \Closure) { 36 | if (null === $manager) { 37 | throw new \InvalidArgumentException('Can not use a closure for the query builder when no document manager has been specified'); 38 | } 39 | $queryBuilder = $queryBuilder($manager->getRepository($class)); 40 | 41 | if (!$queryBuilder instanceof QueryBuilder) { 42 | throw new UnexpectedTypeException($queryBuilder, ObjectManager::class); 43 | } 44 | } 45 | 46 | $this->queryBuilder = $queryBuilder; 47 | } 48 | 49 | /** 50 | * Returns an array of documents that are valid choices in the 51 | * corresponding choice list. 52 | * 53 | * @return array the documents 54 | */ 55 | public function getEntities(): array 56 | { 57 | return $this->getResult($this->queryBuilder); 58 | } 59 | 60 | /** 61 | * Returns an array of documents matching the given identifiers. 62 | * 63 | * @param string $identifier The identifier field of the object. This method 64 | * is not applicable for fields with multiple 65 | * identifiers. 66 | * @param array $values the values of the identifiers 67 | * 68 | * @return array the entities 69 | */ 70 | public function getEntitiesByIds(string $identifier, array $values): array 71 | { 72 | $values = array_values(array_filter($values, static function ($v) { 73 | return !empty($v); 74 | })); 75 | 76 | if (0 === \count($values)) { 77 | return []; 78 | } 79 | 80 | /* performance: if we could figure out whether the query builder is 81 | * "empty" (that is only checking for the class) we could optimize this 82 | * to a $this->dm->findMany(null, $values) 83 | */ 84 | 85 | $qb = clone $this->queryBuilder; 86 | $alias = $qb->getPrimaryAlias(); 87 | $where = $qb->andWhere()->orX(); 88 | foreach ($values as $val) { 89 | $where->same($val, $alias); 90 | } 91 | 92 | return $this->getResult($qb); 93 | } 94 | 95 | /** 96 | * Run the query and return a consecutive array. 97 | * 98 | * @return array list of result documents 99 | */ 100 | private function getResult(QueryBuilder $qb): array 101 | { 102 | return array_values($qb->getQuery()->execute()->toArray()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "doctrine/phpcr-bundle", 3 | "type": "symfony-bundle", 4 | "description": "Symfony DoctrinePHPCRBundle", 5 | "keywords": [ 6 | "PHPCR", 7 | "ODM", 8 | "Database", 9 | "Persistence" 10 | ], 11 | "homepage": "http://www.doctrine-project.org", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Lukas Kahwe Smith", 16 | "email": "smith@pooteeweet.org" 17 | }, 18 | { 19 | "name": "Benjamin Eberlei", 20 | "email": "kontakt@beberlei.de" 21 | } 22 | ], 23 | "require": { 24 | "php": "^8.0", 25 | "ext-dom": "*", 26 | "phpcr/phpcr-utils": "^1.3 || ^2.0", 27 | "symfony/cache": "^5.4 || ^6.0 || ^7.0", 28 | "symfony/doctrine-bridge": "^5.4 || ^6.0 || ^7.0", 29 | "symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0" 30 | }, 31 | "conflict": { 32 | "doctrine/doctrine-bundle": "< 2.0.3", 33 | "doctrine/persistence": "< 3.0.0", 34 | "doctrine/phpcr-odm": "< 2.0", 35 | "jackalope/jackalope": "< 2.0.0 || >= 3.0.0", 36 | "jackalope/jackalope-doctrine-dbal": "< 2.0.0 || >= 3.0.0", 37 | "jackalope/jackalope-jackrabbit": "< 2.0.0 || >= 3.0.0", 38 | "symfony/dependency-injection": "< 3", 39 | "symfony/console": "< 4" 40 | }, 41 | "require-dev": { 42 | "ext-libxml": "*", 43 | "doctrine/data-fixtures": "^2.0", 44 | "doctrine/doctrine-bundle": "^2.0.3", 45 | "doctrine/phpcr-odm": "^2.0", 46 | "doctrine/orm": "^2.0 || ^3.0", 47 | "jackalope/jackalope-doctrine-dbal": "^2.0", 48 | "matthiasnoback/symfony-dependency-injection-test": "^4.3.1 || ^5.0", 49 | "phpcr/phpcr-shell": "^1.6", 50 | "phpstan/phpstan": "^2.0", 51 | "phpstan/phpstan-doctrine": "^2.0", 52 | "phpstan/phpstan-phpunit": "^2.0", 53 | "phpstan/phpstan-symfony": "^2.0", 54 | "phpunit/phpunit": "^9.5", 55 | "symfony/asset": "^5.4 || ^6.0 || ^7.0", 56 | "symfony/browser-kit": "^5.4 || ^6.0 || ^7.0", 57 | "symfony/css-selector": "^5.4 || ^6.0 || ^7.0", 58 | "symfony/error-handler": "^5.4 || ^6.0 || ^7.0", 59 | "symfony/form": "^5.4 || ^6.0 || ^7.0", 60 | "symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.0", 61 | "symfony/monolog-bundle": "^3.4", 62 | "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0", 63 | "symfony/templating": "^5.4 || ^6.0 || ^7.0", 64 | "symfony/translation": "^5.4 || ^6.0 || ^7.0", 65 | "symfony/twig-bundle": "^5.4 || ^6.0 || ^7.0", 66 | "symfony/validator": "^5.4 || ^6.0 || ^7.0", 67 | "symfony/web-profiler-bundle": "^5.4 || ^6.0 || ^7.0" 68 | }, 69 | "suggest": { 70 | "burgov/key-value-form-bundle": "to edit assoc multivalue properties. require version 1.0.*", 71 | "doctrine/data-fixtures": "if you want to use the fixture loading.", 72 | "doctrine/doctrine-bundle": "when using jackalope-doctrine-dbal", 73 | "doctrine/phpcr-odm": "if you want to use the odm as well. require version ^2.0", 74 | "jackalope/jackalope-doctrine-dbal": "if you want to use jackalope-doctrine-dbal. require version ^2.0", 75 | "jackalope/jackalope-jackrabbit": "if you want to connect to jackrabbit. require version ^2.0", 76 | "ocramius/proxy-manager": "To avoid unnecessary database requests when using jackalope-doctrine-dbal", 77 | "phpcr/phpcr-shell": "If you want native access to PHPCR-Shell to manage the PHPCR repository" 78 | }, 79 | "config": { 80 | "sort-packages": true, 81 | "allow-plugins": { 82 | "composer/package-versions-deprecated": true 83 | } 84 | }, 85 | "autoload": { 86 | "psr-4": { 87 | "Doctrine\\Bundle\\PHPCRBundle\\": "src/" 88 | } 89 | }, 90 | "autoload-dev": { 91 | "psr-4": { 92 | "Doctrine\\Bundle\\PHPCRBundle\\Tests\\": "tests/" 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Resources/meta/approval_LGPL-to-MIT/treffynnon.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: david.buchmann@liip.ch 2 | Received: by 10.229.12.79 with SMTP id w15csp23697qcw; 3 | Wed, 11 Jul 2012 06:22:38 -0700 (PDT) 4 | Received: by 10.14.119.15 with SMTP id m15mr11409524eeh.171.1342012957813; 5 | Wed, 11 Jul 2012 06:22:37 -0700 (PDT) 6 | Return-Path: 7 | Received: from psmtp.com (eu1sys200amx125.postini.com. [207.126.144.194]) 8 | by mx.google.com with SMTP id w11si1027507eef.30.2012.07.11.06.22.36 9 | (version=TLSv1/SSLv3 cipher=OTHER); 10 | Wed, 11 Jul 2012 06:22:37 -0700 (PDT) 11 | Received-SPF: neutral (google.com: 217.155.179.134 is neither permitted nor denied by best guess record for domain of Simon@emosaic.co.uk) client-ip=217.155.179.134; 12 | Authentication-Results: mx.google.com; spf=neutral (google.com: 217.155.179.134 is neither permitted nor denied by best guess record for domain of Simon@emosaic.co.uk) smtp.mail=Simon@emosaic.co.uk 13 | Received: from email.mosaic-digital.co.uk ([217.155.179.134]) (using TLSv1) by eu1sys200amx125.postini.com ([207.126.147.10]) with SMTP; 14 | Wed, 11 Jul 2012 06:22:37 PDT 15 | Received: from [192.168.0.190] (192.168.0.190) by JEEVES.emosaic.local 16 | (192.168.0.231) with Microsoft SMTP Server (TLS) id 14.0.722.0; Wed, 11 Jul 17 | 2012 14:20:48 +0100 18 | Message-ID: <4FFD7DE9.5070505@emosaic.co.uk> 19 | Date: Wed, 11 Jul 2012 14:21:45 +0100 20 | From: Simon Holywell 21 | Organization: Mosaic 22 | User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:13.0) Gecko/20120615 Thunderbird/13.0.1 23 | MIME-Version: 1.0 24 | To: David Buchmann 25 | CC: Christophe Coevoet , Florent Cailhol , 26 | Henri Bergius , Julien 'ruian' Galenski 27 | , Lukas Kahwe Smith , 28 | =?ISO-8859-15?Q?Uwe_J=E4ger?= 29 | Subject: Re: please confirm doctrine phpcr bundle license change to MIT 30 | References: <4FFD76C2.3040806@liip.ch> 31 | In-Reply-To: <4FFD76C2.3040806@liip.ch> 32 | Content-Type: text/plain; charset="ISO-8859-15"; format=flowed 33 | Content-Transfer-Encoding: 7bit 34 | Return-Path: simon@emosaic.co.uk 35 | X-pstn-dkim: 0 skipped:not-enabled 36 | X-pstn-nxpr: disp=neutral, envrcpt=david.buchmann@liip.ch 37 | X-pstn-nxp: bodyHash=469f17d98984719864317513bfdec7212d5a9160, 38 | headerHash=60f79f2dae020383432b74471ecab040fc63ed12, keyName=4, 39 | rcptHash=f64fd3aad49032f902032049efab1b9761a3df63, sourceip=217.155.179.134, version=1 40 | 41 | Yes, go for it. 42 | 43 | Thanks, 44 | Simon (Treffynnon) 45 | 46 | Simon Holywell 47 | Lead Developer | Mosaic 48 | 49 | +44.1273 811 091 50 | simon@emosaic.co.uk 51 | http://www.emosaic.co.uk 52 | 53 | On 11/07/12 13:51, David Buchmann wrote: 54 | > -----BEGIN PGP SIGNED MESSAGE----- 55 | > Hash: SHA1 56 | > 57 | > hi, 58 | > 59 | > as the doctrine phpcr bundle was not covered in the switch of doctrine 60 | > to MIT [1] i wanted to ask all of you as the contributers to the 61 | > bundle if you are ok with switching the bundle license to MIT as well. 62 | > 63 | > please just reply to this email if it is ok. 64 | > 65 | > you can see your contributions on the github page 66 | > https://github.com/doctrine/DoctrinePHPCRBundle/graphs/contributors 67 | > 68 | > @stof: github does not show you because the only commit you have was a 69 | > merge commit. i still include you for completeness and because i am 70 | > not a lawyer :-) 71 | > 72 | > cheers,david 73 | > 74 | > [1] http://dlm.beberlei.de/licenses/projects 75 | > - -- 76 | > Liip AG // Agile Web Development // T +41 26 422 25 11 77 | > CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch 78 | > 79 | > -----BEGIN PGP SIGNATURE----- 80 | > Version: GnuPG v1.4.11 (GNU/Linux) 81 | > Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ 82 | > 83 | > iEYEARECAAYFAk/9dr0ACgkQqBnXnqWBgIuNoQCfVOaJ1KAV+9uBM1OCo3Dh/LwD 84 | > ILQAn0IZ8C++sO40auTEZfGOUTa5stxV 85 | > =h+Mh 86 | > -----END PGP SIGNATURE----- 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/Test/RepositoryManager.php: -------------------------------------------------------------------------------- 1 | managerRegistry; 30 | } 31 | 32 | public function getDocumentManager(?string $managerName = null): DocumentManagerInterface 33 | { 34 | return $this->getRegistry()->getManager($managerName); 35 | } 36 | 37 | /** 38 | * @param bool $initialize whether the PHPCR repository should also be initialized 39 | */ 40 | public function purgeRepository(bool $initialize = false): void 41 | { 42 | $this->getExecutor($initialize)->purge(); 43 | } 44 | 45 | /** 46 | * Load fixtures, taking into account possible DependentFixtureInterface fixtures. 47 | * 48 | * @param string[] $classNames FQN for the fixture classes to load 49 | * @param bool $initialize whether the PHPCR repository should also be initialized 50 | * 51 | * @throws \InvalidArgumentException if any of the $classNames do not exist 52 | */ 53 | public function loadFixtures(array $classNames, bool $initialize = false): void 54 | { 55 | $loader = new Loader(); 56 | 57 | foreach ($classNames as $className) { 58 | $this->loadFixture($loader, $className); 59 | } 60 | 61 | $this->getExecutor($initialize)->execute($loader->getFixtures(), false); 62 | } 63 | 64 | /** 65 | * Recursively load the specified fixtures and their dependent fixtures. 66 | * 67 | * @throws \InvalidArgumentException if $className does not exist 68 | */ 69 | private function loadFixture(Loader $loader, string $className): void 70 | { 71 | if (!class_exists($className)) { 72 | throw new \InvalidArgumentException(sprintf( 73 | 'Fixture class "%s" does not exist.', 74 | $className 75 | )); 76 | } 77 | 78 | $fixture = new $className(); 79 | 80 | if ($loader->hasFixture($fixture)) { 81 | unset($fixture); 82 | 83 | return; 84 | } 85 | 86 | $loader->addFixture($fixture); 87 | 88 | if ($fixture instanceof DependentFixtureInterface) { 89 | foreach ($fixture->getDependencies() as $dependency) { 90 | $this->loadFixture($loader, $dependency); 91 | } 92 | } 93 | } 94 | 95 | private function getExecutor(bool $initialize = false): PHPCRExecutor 96 | { 97 | static $lastInitialize = null; 98 | 99 | if (isset($this->executor) && $initialize === $lastInitialize) { 100 | return $this->executor; 101 | } 102 | 103 | $initializerManager = $initialize ? $this->initializerManager : null; 104 | $purger = new PHPCRPurger(); 105 | $executor = new PHPCRExecutor($this->getDocumentManager(), $purger, $initializerManager); 106 | $referenceRepository = new ProxyReferenceRepository($this->getDocumentManager()); 107 | $executor->setReferenceRepository($referenceRepository); 108 | 109 | $this->executor = $executor; 110 | $lastInitialize = $initialize; 111 | 112 | return $executor; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /doc/events.rst: -------------------------------------------------------------------------------- 1 | .. index:: 2 | single: Events; DoctrinePHPCRBundle 3 | 4 | Doctrine PHPCR-ODM Events 5 | ========================= 6 | 7 | Doctrine PHPCR-ODM provides an event system allowing to react to all 8 | important operations that documents have during their lifecycle. Please 9 | see the `Doctrine PHPCR-ODM event system documentation`_ for a full 10 | list of supported events. 11 | 12 | The DoctrinePHPCRBundle provides dependency injection support for the 13 | event listeners and event subscribers. 14 | 15 | Dependency Injection Tags 16 | ------------------------- 17 | 18 | You can tag services to listen to Doctrine PHPCR-ODM events. It works the same 19 | way as for `Doctrine ORM events`_. The only differences are: 20 | 21 | * use the tag name ``doctrine_phpcr.event_listener`` resp. 22 | ``doctrine_phpcr.event_subscriber`` instead of ``doctrine.event_listener``; 23 | * expect the argument to be of class 24 | ``Doctrine\Common\Persistence\Event\LifecycleEventArgs``. 25 | 26 | To tag a service as event listener and another service as event subscriber, 27 | use this configuration: 28 | 29 | .. configuration-block:: 30 | 31 | .. code-block:: yaml 32 | 33 | # app/config/services.yml 34 | services: 35 | app.phpcr_search_indexer: 36 | class: App\EventListener\SearchIndexer 37 | tags: 38 | - { name: doctrine_phpcr.event_listener, event: postPersist } 39 | 40 | app.phpcr_listener: 41 | class: App\EventListener\MyListener 42 | tags: 43 | - { name: doctrine_phpcr.event_subscriber } 44 | 45 | .. code-block:: xml 46 | 47 | 48 | 49 | 50 | 51 | 53 | 54 | 55 | 57 | 58 | 59 | 60 | 61 | 62 | .. code-block:: php 63 | 64 | // app/config/config.php 65 | use App\EventListener\SearchIndexer; 66 | use App\EventListener\MyListener; 67 | 68 | $container 69 | ->register( 70 | 'app.phpcr_search_indexer', 71 | SearchIndexer::class 72 | ) 73 | ->addTag('doctrine_phpcr.event_listener', [ 74 | 'event' => 'postPersist', 75 | ]) 76 | ; 77 | 78 | $container 79 | ->register( 80 | 'app.phpcr_listener', 81 | MySubscriber::class 82 | ) 83 | ->addTag('doctrine_phpcr.event_subscriber') 84 | ; 85 | 86 | .. tip:: 87 | 88 | Doctrine event subscribers (both ORM and PHPCR-ODM) can **not** return a 89 | flexible array of methods to call like the `Symfony event subscriber`_. 90 | Doctrine event subscribers must return a simple array of the event 91 | names they subscribe to. Doctrine will then expect methods on the 92 | subscriber with the names of the subscribed events, just as when using an 93 | event listener. 94 | 95 | You can find more information and examples of the doctrine event system 96 | in "`How to Register Event Listeners and Subscribers`_" of the core documentation. 97 | 98 | .. _`Doctrine PHPCR-ODM event system documentation`: http://docs.doctrine-project.org/projects/doctrine-phpcr-odm/en/latest/reference/events.html 99 | .. _`Symfony event subscriber`: https://symfony.com/doc/current/components/event_dispatcher/introduction.html#using-event-subscribers 100 | .. _`Doctrine ORM events`: https://symfony.com/doc/current/doctrine/event_listeners_subscribers.html 101 | .. _`How to Register Event Listeners and Subscribers`: https://symfony.com/doc/current/doctrine/event_listeners_subscribers.html 102 | -------------------------------------------------------------------------------- /src/Resources/config/commands.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | %doctrine_phpcr.dump_max_line_length% 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /tests/Unit/EventListener/LocaleListenerTest.php: -------------------------------------------------------------------------------- 1 | chooser = $this->createMock(LocaleChooserInterface::class); 34 | $this->responseEvent = $this->createMock(RequestEvent::class); 35 | $this->request = $this->createMock(Request::class); 36 | $this->allowedLocales = ['fr', 'en', 'de']; 37 | } 38 | 39 | public function testOnKernelRequestWithFallbackHardcoded(): void 40 | { 41 | $localeListener = new LocaleListener( 42 | $this->chooser, 43 | $this->allowedLocales, 44 | LocaleListener::FALLBACK_HARDCODED 45 | ); 46 | 47 | $this->responseEvent->expects($this->exactly(4)) 48 | ->method('getRequest') 49 | ->willReturn($this->request); 50 | 51 | $this->request->expects($this->exactly(2)) 52 | ->method('getLocale') 53 | ->will($this->onConsecutiveCalls('it', 'fr')); 54 | 55 | $this->chooser->expects($this->once()) 56 | ->method('setLocale') 57 | ->with($this->equalTo('fr')); 58 | 59 | $localeListener->onKernelRequest($this->responseEvent); 60 | $localeListener->onKernelRequest($this->responseEvent); 61 | } 62 | 63 | public function testOnKernelRequestWithDefaultFallback(): void 64 | { 65 | $localeListener = new LocaleListener( 66 | $this->chooser, 67 | $this->allowedLocales 68 | ); 69 | 70 | $this->responseEvent->expects($this->exactly(2)) 71 | ->method('getRequest') 72 | ->willReturn($this->request); 73 | 74 | $this->request->expects($this->once()) 75 | ->method('getLocale') 76 | ->will($this->onConsecutiveCalls('en')); 77 | 78 | $this->chooser->expects($this->once()) 79 | ->method('setLocale') 80 | ->with($this->equalTo('en')); 81 | 82 | $this->request->expects($this->once()) 83 | ->method('getLanguages') 84 | ->willReturn(['it', 'fr_FR', 'fr_CA', 'en_GB']); 85 | 86 | $this->chooser->expects($this->once()) 87 | ->method('setFallbackLocales') 88 | ->with('en', ['fr', 'en'], false); 89 | 90 | $localeListener->onKernelRequest($this->responseEvent); 91 | } 92 | 93 | public function testOnKernelRequestWithFallbackReplace(): void 94 | { 95 | $localeListener = new LocaleListener( 96 | $this->chooser, 97 | $this->allowedLocales, 98 | LocaleListener::FALLBACK_REPLACE 99 | ); 100 | 101 | $this->responseEvent->expects($this->exactly(2)) 102 | ->method('getRequest') 103 | ->willReturn($this->request); 104 | 105 | $this->request->expects($this->once()) 106 | ->method('getLocale') 107 | ->will($this->onConsecutiveCalls('en')); 108 | 109 | $this->chooser->expects($this->once()) 110 | ->method('setLocale') 111 | ->with($this->equalTo('en')); 112 | 113 | $this->request->expects($this->once()) 114 | ->method('getLanguages') 115 | ->willReturn(['it', 'fr_FR', 'fr_CA', 'en_GB']); 116 | 117 | $this->chooser->expects($this->once()) 118 | ->method('setFallbackLocales') 119 | ->with('en', ['fr', 'en'], true); 120 | 121 | $localeListener->onKernelRequest($this->responseEvent); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/Resources/meta/approval_LGPL-to-MIT/lsmith77.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: david.buchmann@liip.ch 2 | Received: by 10.229.12.79 with SMTP id w15csp22406qcw; 3 | Wed, 11 Jul 2012 05:53:04 -0700 (PDT) 4 | Received: by 10.14.188.139 with SMTP id a11mr11916432een.139.1342011183795; 5 | Wed, 11 Jul 2012 05:53:03 -0700 (PDT) 6 | Return-Path: 7 | Received: from psmtp.com (eu1sys200amx103.postini.com. [207.126.144.52]) 8 | by mx.google.com with SMTP id y51si984925eea.31.2012.07.11.05.53.02 9 | (version=TLSv1/SSLv3 cipher=OTHER); 10 | Wed, 11 Jul 2012 05:53:03 -0700 (PDT) 11 | Received-SPF: neutral (google.com: 176.9.111.84 is neither permitted nor denied by best guess record for domain of smith@pooteeweet.org) client-ip=176.9.111.84; 12 | Authentication-Results: mx.google.com; spf=neutral (google.com: 176.9.111.84 is neither permitted nor denied by best guess record for domain of smith@pooteeweet.org) smtp.mail=smith@pooteeweet.org 13 | Received: from ssl.backendmedia.com ([176.9.111.84]) (using TLSv1) by eu1sys200amx103.postini.com ([207.126.147.10]) with SMTP; 14 | Wed, 11 Jul 2012 12:53:03 GMT 15 | Received: from localhost (unknown [127.0.0.1]) 16 | by ssl.backendmedia.com (Postfix) with ESMTP id 0EE6D5EFE32A; 17 | Wed, 11 Jul 2012 12:53:04 +0000 (UTC) 18 | X-Virus-Scanned: amavisd-new at backendmedia.com 19 | Received: from ssl.backendmedia.com ([127.0.0.1]) 20 | by localhost (hq2.backendmedia.com [127.0.0.1]) (amavisd-new, port 10024) 21 | with ESMTP id MiEBTcQZJhv9; Wed, 11 Jul 2012 14:53:03 +0200 (CEST) 22 | Received: from glass.compensate.volia.net (glass.compensate.volia.net [93.72.133.30]) 23 | (using TLSv1 with cipher ECDHE-RSA-AES128-SHA (128/128 bits)) 24 | (No client certificate requested) 25 | (Authenticated sender: smith@pooteeweet.org) 26 | by ssl.backendmedia.com (Postfix) with ESMTPSA id DCD185EFE324; 27 | Wed, 11 Jul 2012 14:53:01 +0200 (CEST) 28 | Subject: Re: please confirm doctrine phpcr bundle license change to MIT 29 | Mime-Version: 1.0 (Apple Message framework v1278) 30 | Content-Type: text/plain; charset=us-ascii 31 | From: Lukas Kahwe Smith 32 | In-Reply-To: <4FFD76C2.3040806@liip.ch> 33 | Date: Wed, 11 Jul 2012 15:53:09 +0300 34 | Cc: Christophe Coevoet , 35 | Florent Cailhol , 36 | Henri Bergius , 37 | Julien 'ruian' Galenski , 38 | Simon Holywell , 39 | =?iso-8859-1?Q?Uwe_J=E4ger?= 40 | Content-Transfer-Encoding: 7bit 41 | Message-Id: <8322EEC1-231F-423D-BB31-F0313435D149@pooteeweet.org> 42 | References: <4FFD76C2.3040806@liip.ch> 43 | To: David Buchmann 44 | X-Mailer: Apple Mail (2.1278) 45 | X-pstn-dkim: 0 skipped:not-enabled 46 | X-pstn-nxpr: disp=neutral, envrcpt=david.buchmann@liip.ch 47 | X-pstn-nxp: bodyHash=91e40e7921e30bbcd6e612ea43d3c8871e49c7c0, 48 | headerHash=28170e9385e0e98b18848898bd8af11ded26df8b, keyName=4, 49 | rcptHash=f64fd3aad49032f902032049efab1b9761a3df63, sourceip=176.9.111.84, version=1 50 | 51 | all good with me :) 52 | 53 | On Jul 11, 2012, at 3:51 PM, David Buchmann wrote: 54 | 55 | > -----BEGIN PGP SIGNED MESSAGE----- 56 | > Hash: SHA1 57 | > 58 | > hi, 59 | > 60 | > as the doctrine phpcr bundle was not covered in the switch of doctrine 61 | > to MIT [1] i wanted to ask all of you as the contributers to the 62 | > bundle if you are ok with switching the bundle license to MIT as well. 63 | > 64 | > please just reply to this email if it is ok. 65 | > 66 | > you can see your contributions on the github page 67 | > https://github.com/doctrine/DoctrinePHPCRBundle/graphs/contributors 68 | > 69 | > @stof: github does not show you because the only commit you have was a 70 | > merge commit. i still include you for completeness and because i am 71 | > not a lawyer :-) 72 | > 73 | > cheers,david 74 | > 75 | > [1] http://dlm.beberlei.de/licenses/projects 76 | > - -- 77 | > Liip AG // Agile Web Development // T +41 26 422 25 11 78 | > CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch 79 | > 80 | > -----BEGIN PGP SIGNATURE----- 81 | > Version: GnuPG v1.4.11 (GNU/Linux) 82 | > Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ 83 | > 84 | > iEYEARECAAYFAk/9dr0ACgkQqBnXnqWBgIuNoQCfVOaJ1KAV+9uBM1OCo3Dh/LwD 85 | > ILQAn0IZ8C++sO40auTEZfGOUTa5stxV 86 | > =h+Mh 87 | > -----END PGP SIGNATURE----- 88 | 89 | Lukas Kahwe Smith 90 | smith@pooteeweet.org 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/EventListener/LocaleListener.php: -------------------------------------------------------------------------------- 1 | chooser = $chooser; 59 | $this->allowedLocales = $allowedLocales; 60 | switch ($fallback) { 61 | case self::FALLBACK_MERGE: 62 | case self::FALLBACK_REPLACE: 63 | case self::FALLBACK_HARDCODED: 64 | $this->fallback = $fallback; 65 | 66 | break; 67 | default: 68 | $this->fallback = self::FALLBACK_MERGE; 69 | 70 | break; 71 | } 72 | } 73 | 74 | /** 75 | * Decides which locale will be used. 76 | * 77 | * @return string|null a locale or null if no valid locale is found 78 | */ 79 | protected function determineLocale(RequestEvent $event): ?string 80 | { 81 | $locale = $event->getRequest()->getLocale(); 82 | 83 | return \in_array($locale, $this->allowedLocales, true) ? 84 | $locale : 85 | null; 86 | } 87 | 88 | public function onKernelRequest(RequestEvent $event): void 89 | { 90 | $request = $event->getRequest(); 91 | 92 | if (!$locale = $this->determineLocale($event)) { 93 | return; 94 | } 95 | 96 | $this->chooser->setLocale($locale); 97 | 98 | if (self::FALLBACK_HARDCODED === $this->fallback) { 99 | return; 100 | } 101 | 102 | // expand language list to include base locales 103 | // copy-pasted from Request::getPreferredLanguage 104 | $preferredLanguages = $request->getLanguages(); 105 | $extendedPreferredLanguages = []; 106 | foreach ($preferredLanguages as $language) { 107 | $extendedPreferredLanguages[] = $language; 108 | if (false !== $position = strpos($language, '_')) { 109 | $superLanguage = substr($language, 0, $position); 110 | if (!\in_array($superLanguage, $preferredLanguages)) { 111 | $extendedPreferredLanguages[] = $superLanguage; 112 | } 113 | } 114 | } 115 | $order = array_intersect($this->allowedLocales, $extendedPreferredLanguages); 116 | $this->chooser->setFallbackLocales($locale, $order, self::FALLBACK_REPLACE === $this->fallback); 117 | } 118 | 119 | /** 120 | * We are only interested in request events. 121 | */ 122 | public static function getSubscribedEvents(): array 123 | { 124 | return [ 125 | KernelEvents::REQUEST => [['onKernelRequest', 1]], 126 | ]; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /tests/Unit/Initializer/InitializerManagerTest.php: -------------------------------------------------------------------------------- 1 | registry = $this->createMock(ManagerRegistryInterface::class); 36 | 37 | $this->initializer1 = $this 38 | ->getMockBuilder(InitializerInterface::class) 39 | ->setMockClassName('TestInitializerOne') 40 | ->getMock(); 41 | $this->initializer2 = $this 42 | ->getMockBuilder(InitializerInterface::class) 43 | ->setMockClassName('TestInitializerTwo') 44 | ->getMock(); 45 | $this->initializer3 = $this 46 | ->getMockBuilder(InitializerInterface::class) 47 | ->setMockClassName('TestInitializerTwo') 48 | ->getMock(); 49 | 50 | $this->initializerManager = new InitializerManager($this->registry); 51 | } 52 | 53 | public function provideInitialize(): array 54 | { 55 | return [ 56 | [ 57 | [ 58 | ['initializer1', 0], 59 | ['initializer2', 0], 60 | ['initializer3', 0], 61 | ], 62 | ['initializer1', 'initializer2', 'initializer3'], 63 | ], 64 | [ 65 | [ 66 | ['initializer1', null], 67 | ['initializer2', null], 68 | ['initializer3', null], 69 | ], 70 | ['initializer1', 'initializer2', 'initializer3'], 71 | ], 72 | [ 73 | [ 74 | ['initializer3', 0], 75 | ['initializer1', 0], 76 | ['initializer2', 0], 77 | ], 78 | ['initializer3', 'initializer1', 'initializer2'], 79 | ], 80 | [ 81 | [ 82 | ['initializer3', 100], 83 | ['initializer1', -100], 84 | ['initializer2', 0], 85 | ], 86 | ['initializer3', 'initializer2', 'initializer1'], 87 | ], 88 | ]; 89 | } 90 | 91 | /** 92 | * @dataProvider provideInitialize 93 | */ 94 | public function testInitialize(array $initializers, array $expectedOrder): void 95 | { 96 | foreach ($initializers as $initializerConfig) { 97 | [$initializerVar, $priority] = $initializerConfig; 98 | 99 | $initializer = $this->$initializerVar; 100 | 101 | $initializer->expects($this->once()) 102 | ->method('getName') 103 | ->willReturn($initializerVar); 104 | 105 | $initializer->expects($this->once()) 106 | ->method('init') 107 | ->with($this->registry); 108 | 109 | if (null !== $priority) { 110 | $this->initializerManager->addInitializer($initializer, $priority); 111 | } else { 112 | $this->initializerManager->addInitializer($initializer); 113 | } 114 | } 115 | 116 | $log = []; 117 | $this->initializerManager->setLoggingClosure(function ($message) use (&$log) { 118 | $log[] = $message; 119 | }); 120 | 121 | $this->initializerManager->initialize(); 122 | 123 | $this->assertCount(\count($initializers), $log); 124 | 125 | // check expected order against the log 126 | foreach ($expectedOrder as $i => $initializerVar) { 127 | $this->assertStringContainsString($initializerVar, $log[$i]); 128 | } 129 | } 130 | 131 | public function testNoLogging(): void 132 | { 133 | $this->initializer1->expects($this->never()) 134 | ->method('getName'); 135 | $this->initializer1->expects($this->once()) 136 | ->method('init'); 137 | 138 | $this->initializerManager->addInitializer($this->initializer1); 139 | $this->initializerManager->initialize(); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/Resources/meta/approval_LGPL-to-MIT/uwej711.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: david.buchmann@liip.ch 2 | Received: by 10.229.12.79 with SMTP id w15csp41735qcw; 3 | Wed, 11 Jul 2012 13:16:08 -0700 (PDT) 4 | Received: by 10.14.98.77 with SMTP id u53mr12285393eef.185.1342037768301; 5 | Wed, 11 Jul 2012 13:16:08 -0700 (PDT) 6 | Return-Path: 7 | Received: from psmtp.com (eu1sys200amx114.postini.com. [207.126.144.183]) 8 | by mx.google.com with SMTP id e4si1659785eea.94.2012.07.11.13.16.07 9 | (version=TLSv1/SSLv3 cipher=OTHER); 10 | Wed, 11 Jul 2012 13:16:08 -0700 (PDT) 11 | Received-SPF: pass (google.com: domain of uwej711@gmail.com designates 209.85.220.177 as permitted sender) client-ip=209.85.220.177; 12 | Authentication-Results: mx.google.com; spf=pass (google.com: domain of uwej711@gmail.com designates 209.85.220.177 as permitted sender) smtp.mail=uwej711@gmail.com; dkim=pass header.i=@gmail.com 13 | Received: from mail-vc0-f177.google.com ([209.85.220.177]) (using TLSv1) by eu1sys200amx114.postini.com ([207.126.147.10]) with SMTP; 14 | Wed, 11 Jul 2012 20:16:08 GMT 15 | Received: by vcbf13 with SMTP id f13so1336515vcb.22 16 | for ; Wed, 11 Jul 2012 13:16:06 -0700 (PDT) 17 | DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; 18 | d=gmail.com; s=20120113; 19 | h=mime-version:in-reply-to:references:date:message-id:subject:from:to 20 | :cc:content-type; 21 | bh=+ADMQQGrqFURMBrvdA4+Mdggnabeg11Sxh4Qxhwl33Q=; 22 | b=osRqaCqP2tYaDm8I45Dhi2TqsPQdSVtN4iGPwWLd1o21WXa7+dCZn4FsNucq3F8/GZ 23 | PE5ILi7F1mgE4xB3+iRT0fjFRg9YdSmgJqoqTHZM+Yx+uEihaUHT4RC7CS1zekgQSxA9 24 | cfCeytVDaMiOLnmv1N2JP08V9NkFRuhYUfLjMIsLYwJA1iXiso8p1UelTTSjBVJf4+BW 25 | OTBhl7GHyz2+a179+hSnsnVA9HiCpxjzxvLp3bh6U0OMTc7ooZK/yyf/c99xuhBlVUkb 26 | F8Yc67Rr2on7+SfMFgPrn/F9OUkD23/gLiYaueIVfCZJ+NEV3/dnZd8uEmFIUQAjf1Vh 27 | EFbA== 28 | MIME-Version: 1.0 29 | Received: by 10.220.16.8 with SMTP id m8mr23692845vca.10.1342037766028; Wed, 30 | 11 Jul 2012 13:16:06 -0700 (PDT) 31 | Received: by 10.220.18.140 with HTTP; Wed, 11 Jul 2012 13:16:05 -0700 (PDT) 32 | In-Reply-To: <4FFD7DE9.5070505@emosaic.co.uk> 33 | References: <4FFD76C2.3040806@liip.ch> 34 | <4FFD7DE9.5070505@emosaic.co.uk> 35 | Date: Wed, 11 Jul 2012 22:16:05 +0200 36 | Message-ID: 37 | Subject: Re: please confirm doctrine phpcr bundle license change to MIT 38 | From: =?ISO-8859-1?Q?Uwe_J=E4ger?= 39 | To: Simon Holywell 40 | Cc: David Buchmann , Christophe Coevoet , 41 | Florent Cailhol , Henri Bergius , 42 | "Julien 'ruian' Galenski" , Lukas Kahwe Smith , 43 | =?ISO-8859-1?Q?Uwe_J=E4ger?= 44 | Content-Type: text/plain; charset=ISO-8859-1 45 | X-pstn-dkim: 1 skipped:not-enabled 46 | X-pstn-nxpr: disp=neutral, envrcpt=david.buchmann@liip.ch 47 | X-pstn-nxp: bodyHash=667cca79c4e44a2aaa325d1cf58bf08b3be0e9e7, 48 | headerHash=1fa647ea9ac7e51ec4441614cd914be776af0eb6, keyName=4, 49 | rcptHash=f64fd3aad49032f902032049efab1b9761a3df63, sourceip=209.85.220.177, version=1 50 | 51 | Hi, 52 | 53 | fine with me, too. 54 | 55 | Cheers 56 | Uwe 57 | 58 | 2012/7/11 Simon Holywell : 59 | > Yes, go for it. 60 | > 61 | > Thanks, 62 | > Simon (Treffynnon) 63 | > 64 | > Simon Holywell 65 | > Lead Developer | Mosaic 66 | > 67 | > +44.1273 811 091 68 | > simon@emosaic.co.uk 69 | > http://www.emosaic.co.uk 70 | > 71 | > 72 | > On 11/07/12 13:51, David Buchmann wrote: 73 | >> 74 | >> -----BEGIN PGP SIGNED MESSAGE----- 75 | >> Hash: SHA1 76 | >> 77 | >> hi, 78 | >> 79 | >> as the doctrine phpcr bundle was not covered in the switch of doctrine 80 | >> to MIT [1] i wanted to ask all of you as the contributers to the 81 | >> bundle if you are ok with switching the bundle license to MIT as well. 82 | >> 83 | >> please just reply to this email if it is ok. 84 | >> 85 | >> you can see your contributions on the github page 86 | >> https://github.com/doctrine/DoctrinePHPCRBundle/graphs/contributors 87 | >> 88 | >> @stof: github does not show you because the only commit you have was a 89 | >> merge commit. i still include you for completeness and because i am 90 | >> not a lawyer :-) 91 | >> 92 | >> cheers,david 93 | >> 94 | >> [1] http://dlm.beberlei.de/licenses/projects 95 | >> - -- Liip AG // Agile Web Development // T +41 26 422 25 11 96 | >> CH-1700 Fribourg // PGP 0xA581808B // www.liip.ch 97 | >> 98 | >> -----BEGIN PGP SIGNATURE----- 99 | >> Version: GnuPG v1.4.11 (GNU/Linux) 100 | >> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ 101 | >> 102 | >> iEYEARECAAYFAk/9dr0ACgkQqBnXnqWBgIuNoQCfVOaJ1KAV+9uBM1OCo3Dh/LwD 103 | >> ILQAn0IZ8C++sO40auTEZfGOUTa5stxV 104 | >> =h+Mh 105 | >> -----END PGP SIGNATURE----- 106 | > 107 | > 108 | > 109 | -------------------------------------------------------------------------------- /src/Resources/config/odm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | Doctrine\Common\Cache\ArrayCache 12 | Doctrine\Common\Cache\ApcCache 13 | Doctrine\Common\Cache\MemcacheCache 14 | localhost 15 | 11211 16 | Memcache 17 | Doctrine\Common\Cache\MemcachedCache 18 | localhost 19 | 11211 20 | Memcached 21 | Doctrine\Common\Cache\XcacheCache 22 | Doctrine\Bundle\PHPCRBundle\Mapping\Driver\XmlDriver 23 | Doctrine\Bundle\PHPCRBundle\Mapping\Driver\YamlDriver 24 | Doctrine\Persistence\Mapping\Driver\StaticPHPDriver 25 | Doctrine\Persistence\Mapping\Driver\MappingDriverChain 26 | Doctrine\ODM\PHPCR\Mapping\Driver\AttributeDriver 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 52 | 53 | 54 | 60 | 61 | 63 | 64 | 65 | 66 | 67 | 69 | 70 | 71 | 72 | 73 | 75 | 76 | 77 | %doctrine_phpcr.form.type_guess% 78 | 79 | 80 | 82 | 83 | 84 | 85 | 86 | 87 | 89 | 90 | 91 | %doctrine_phpcr.odm.namespaces.translation.alias% 92 | 93 | 94 | 95 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | --------------------------------------------------------------------------------