English spoken conference
WARNING: You are browsing the documentation for version 2.0 which is not maintained anymore. If some of your projects are still using this version, consider upgrading.

DoctrinePHPCRBundle

2.0 version
Maintained Unmaintained

DoctrinePHPCRBundle

The DoctrinePHPCRBundle provides integration with the PHP content repository and optionally with Doctrine PHPCR-ODM to provide the ODM document manager in symfony.

Out of the box, this bundle supports the following PHPCR implementations:

  • Jackalope (Jackrabbit, Doctrine DBAL and prismic transports)

Tip

This reference only explains the Symfony2 integration of PHPCR and PHPCR-ODM. To learn how to use PHPCR, refer to the PHPCR website and for Doctrine PHPCR-ODM to the PHPCR-ODM documentation.

Setup

Requirements

  • When using jackalope-jackrabbit: Java, Apache Jackalope and libxml version >= 2.7.0 (due to a bug in libxml)
  • When using jackalope-doctrine-dbal with MySQL: MySQL >= 5.1.5 (as you need the xml function ExtractValue)

Installation

You can install this bundle with composer using the doctrine/phpcr-bundle package. You need a concrete implementation of the PHPCR API. For this example, we assume that you require Jackalope Doctrine DBAL. See Choosing a PHPCR Implementation for alternatives.

If you want to use PHPCR-ODM, you additionally need to require doctrine/phpcr-odm.

1
2
3
4
5
6
7
require: {
    ...
    "jackalope/jackalope-doctrine-dbal": "1.2.*",
    "doctrine/phpcr-odm": "1.2.*",
    "doctrine/phpcr-bundle": "1.2.*",
    ...
}

Besides the DoctrinePHPCRBundle you also need to instantiate the base DoctrineBundle in your kernel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// app/AppKernel.php

// ...
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            // ...
            new Doctrine\Bundle\PHPCRBundle\DoctrinePHPCRBundle(),
            new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
        ];

        // ...
    }

    // ...
}

Configuration

PHPCR Session Configuration

The session needs a PHPCR implementation specified in the backend section by the type field, along with configuration options to bootstrap the implementation. The examples here assume that you are using Jackalope Doctrine DBAL. The full documentation is in the configuration reference.

To use Jackalope Doctrine DBAL, you need to configure a database connection with the DoctrineBundle. For detailed information, see the Symfony2 Doctrine documentation. A simple example is:

1
2
3
4
5
6
7
8
9
# app/config/parameters.yml
parameters:
    database_driver:   pdo_mysql
    database_host:     localhost
    database_name:     test_project
    database_user:     root
    database_password: password

# ...
  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    # app/config/config.yml
    doctrine:
        dbal:
            driver:   "%database_driver%"
            host:     "%database_host%"
            dbname:   "%database_name%"
            user:     "%database_user%"
            password: "%database_password%"
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:doctrine="http://symfony.com/schema/dic/doctrine"
        xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
                            http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">
    
        <doctrine:config>
            <doctrine:dbal
                driver="%database_driver%"
                host="%database_host%"
                dbname="%database_name%"
                user="%database_user%"
                password="%database_password%"
            />
        </doctrine:config>
    
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    // app/config/config.php
    $configuration->loadFromExtension('doctrine', [
        'dbal' => [
            'driver'   => '%database_driver%',
            'host'     => '%database_host%',
            'dbname'   => '%database_name%',
            'user'     => '%database_user%',
            'password' => '%database_password%',
        ],
    ]);
    

Jackalope Doctrine DBAL provides a PHPCR implementation without any installation requirements beyond any of the RDBMS supported by Doctrine. Once you set up Doctrine DBAL, you can configure Jackalope:

  • YAML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # app/config/config.yml
    doctrine_phpcr:
        session:
            backend:
                type: doctrinedbal
                # connection: default
    
                # requires DoctrineCacheBundle
                # caches:
                #     meta: doctrine_cache.providers.phpcr_meta
                #     nodes: doctrine_cache.providers.phpcr_nodes
                # enable logging
                logging: true
                # enable profiling in the debug toolbar.
                profiling: true
            workspace: default
            username: admin
            password: admin
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services">
    
        <config xmlns="http://doctrine-project.org/schema/symfony-dic/odm/phpcr">
    
            <session
                workspace="default"
                username="admin"
                password="admin"
            >
    
                <backend
                    type="doctrinedbal"
                    logging="true"
                    profiling="true"
                >
                    <!-- connection="default" - option on <backend> to change dbal connection -->
                    <!--
                    <caches
                        meta="doctrine_cache.providers.phpcr_meta"
                        nodes="doctrine_cache.providers.phpcr_nodes"
                    />
                    -->
                </backend>
            </session>
        </config>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // app/config/config.php
    $container->loadFromExtension('doctrine_phpcr', [
        'session' => [
            'backend' => [
                'type'       => 'doctrinedbal',
                //'connection': 'default',
                'logging'    => true,
                'profiling'  => true,
                //'caches' => [
                //    'meta' => 'doctrine_cache.providers.phpcr_meta'
                //    'nodes' => 'doctrine_cache.providers.phpcr_nodes'
                //],
            ],
            'workspace' => 'default',
            'username'  => 'admin',
            'password'  => 'admin',
        ],
    ]);
    

Now make sure the database exists and initialize it:

1
2
3
# without Doctrine ORM
php bin/console doctrine:database:create
php bin/console doctrine:phpcr:init:dbal

Tip

You can also use a different doctrine dbal connection instead of the default. Specify the dbal connection name in the connection option of the backend configuration.

It is recommended to use a separate connection to a separate database if you also use Doctrine ORM or direct DBAL access to data, rather than mixing this data with the tables generated by Jackalope Doctrine Dbal. If you have a separate connection, you need to pass the alternate connection name to the doctrine:database:create command with the --connection option. For Doctrine PHPCR commands, this parameter is not needed as you configured the connection to use.

If you are using Doctrine ORM on the same connection, the schema is integrated into doctrine:schema:create|update|drop and also DoctrineMigrationsBundle so that you can create migrations.

1
2
3
# Using Doctrine ORM
php bin/console doctrine:database:create
php bin/console doctrine:schema:create

Note

To use the cache, install and configure the DoctrineCacheBundle. Then uncomment the cache meta and nodes settings.

Doctrine PHPCR-ODM Configuration

This configuration section manages the document mapper system that converts your PHPCR nodes to domain model objects. If you do not configure anything here, the ODM services will not be loaded.

  • YAML
    1
    2
    3
    4
    5
    # app/config/config.yml
    doctrine_phpcr:
        odm:
            auto_mapping: true
            auto_generate_proxy_classes: "%kernel.debug%"
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services">
    
        <config xmlns="http://doctrine-project.org/schema/symfony-dic/odm/phpcr">
    
            <odm
                auto-mapping="true"
                auto-generate-proxy-classes="%kernel.debug%"
            />
        </config>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    // app/config/config.php
    $container->loadFromExtension('doctrine_phpcr', [
        'odm' => [
            'auto_mapping' => true,
            'auto_generate_proxy_classes' => '%kernel.debug%',
        ],
    ]);
    

Unless you disable auto_mapping, you can place your documents in the Document folder inside your bundles and use annotations or name the mapping files following this schema: <Bundle>/Resources/config/doctrine/<DocumentClass>.phpcr.xml or *.phpcr.yml.

If auto_generate_proxy_classes is false, you need to run the cache:warmup command in order to have the proxy classes generated after you modified a document. This is usually done in production to gain some performance.

Registering System Node Types

PHPCR-ODM uses a custom node type to track meta information without interfering with your content. There is a command that makes it trivial to register this type and the PHPCR namespace, as well as all base paths of bundles:

1
$ php bin/console doctrine:phpcr:repository:init

You only need to run this command once when you created a new repository. (But nothing goes wrong if you run it on each deployment for example.)

Profiling and Performance of Jackalope

When using any of the Jackalope PHPCR implementations, you can activate logging to log to the symfony log, or profiling to show information in the Symfony2 debug toolbar:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    # app/config/config.yml
    doctrine_phpcr:
        session:
            backend:
                # ...
                logging: true
                profiling: true
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services">
    
        <config xmlns="http://doctrine-project.org/schema/symfony-dic/odm/phpcr">
    
            <session>
    
                <backend
                    logging="true"
                    profiling="true"
                />
            </session>
        </config>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    // app/config/config.yml
    $container->loadFromExtension('doctrine_phpcr', [
        'session' => [
            'backend' => [
                // ...
                'logging'   => true,
                'profiling' => true,
            ],
        ],
    ]);
    

Now that you can see the effects of changes, you can try if adjusting the global fetch depth reduces the number and duration for queries. Set the option jackalope.fetch_depth to something bigger than 0 to have Jackalope pre-fetch children or whole subtrees. This can reduce the number of queries needed, but watch out for longer queries because more data is fetched.

When using Jackalope Doctrine DBAL, it is highly recommended to activate the caching options.

Note that you can also set the fetch-depth on the session on the fly for specific calls, or use the fetch-depth option on children mappings of your documents.

The parameter jackalope.check_login_on_server can be set to false to save an initial call to the database to check if the connection works.

Services

There are 3 main services provided by this bundle:

  • doctrine_phpcr- The ManagerRegistry instance with references to all sessions and document manager instances;
  • doctrine_phpcr.default_session - The PHPCR session instance;
  • doctrine_phpcr.odm.default_document_manager - The PHPCR-ODM document manager instance.

Doctrine PHPCR Commands

All commands about PHPCR are prefixed with doctrine:phpcr and you can use the --session argument to use a non-default session if you configured several PHPCR sessions.

Some of these commands are specific to a backend or to the ODM. Those commands will only be available if such a backend is configured.

Use php bin/console help <command> to see all options each of the commands has.

  • doctrine:phpcr:document:migrate-class: Command to migrate document classes;
  • doctrine:phpcr:fixtures:load: Load data fixtures to your PHPCR database;
  • doctrine:phpcr:init:dbal: Prepare the database for Jackalope Doctrine-Dbal;
  • doctrine:phpcr:jackrabbit: Start and stop the Jackrabbit server (see also Running Jackrabbit);
  • doctrine:phpcr:mapping:info: Shows basic information about all mapped documents;
  • doctrine:phpcr:migrator:migrate: Migrates PHPCR data;
  • doctrine:phpcr:node-type:list: List all available node types in the repository;
  • doctrine:phpcr:node-type:register: Register node types in the PHPCR repository;
  • doctrine:phpcr:node:dump: Dump subtrees of the content repository;
  • doctrine:phpcr:node:move: Moves a node from one path to another;
  • doctrine:phpcr:node:remove: Remove content from the repository;
  • doctrine:phpcr:node:touch: Create or modify a node;
  • doctrine:phpcr:nodes:update: Command to manipulate the nodes in the workspace;
  • doctrine:phpcr:repository:init: Initialize the PHPCR repository;
  • doctrine:phpcr:workspace:create: Create a workspace in the configured repository;
  • doctrine:phpcr:workspace:export: Export nodes from the repository, either to the JCR system view format or the document view format;
  • doctrine:phpcr:workspace:import: Import xml data into the repository, either in JCR system view format or arbitrary xml;
  • doctrine:phpcr:workspace:list: List all available workspaces in the configured repository;
  • doctrine:phpcr:workspace:purge: Remove all nodes from a workspace;
  • doctrine:phpcr:workspace:query: Execute a JCR SQL2 statement.

Note

To use the doctrine:phpcr:fixtures:load command, you additionally need to install the DoctrineFixturesBundle and its dependencies. See Fixture Loading for how to use fixtures.

Some Example Command Runs

Running SQL2 queries against the repository:

1
$ php bin/console doctrine:phpcr:workspace:query "SELECT title FROM [nt:unstructured] WHERE NAME() = 'home'"

Dumping nodes under /cms/simple including their properties:

1
$ php bin/console doctrine:phpcr:node:dump /cms/simple --props

Simple Backup and Restore

To export all repository data into a file, you can use:

1
$ php bin/console doctrine:phpcr:workspace:export --path /cms /path/to/backup.xml

Note

You always want to specify a path to export. Without any path you will export the root node of the repository, which will be imported later as jcr:root.

To restore this backup you can run:

1
$ php bin/console doctrine:phpcr:workspace:import /path/to/backup.xml

Note that you can also export and import parts of your repository by choosing a different path on export and specifying the --parentpath option to the import.

If you already have data in your repository that you want to replace, you can remove the target node first:

1
$ php bin/console doctrine:phpcr:node:remove /cms

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.