DoctrinePHPCRBundle

El DoctrinePHPCRBundle proporciona integración con el repositorio de contenido PHP y opcionalmente con el PHPCR-ODM de Doctrine para proporcionar el gestor de documentos ODM en Symfony.

Fuera de la caja, este paquete apoya las siguientes implementaciones PHPCR:

Truco

Esta referencia sólo explica la integración de Symfony2 con PHPCR y PHPCR-ODM. Para aprender cómo utilizar PHPCR ve al sitio web de PHPCR y para la documentación del PHPCR-ODM de Doctrine .

Este paquete está basado en el AbstractDoctrineBundle y por lo tanto es similar a la configuración de los paquetes ORM y MongoDB de Doctrine.

Configurando

Truco

Si sólo quieres utilizar el PHPCR sencillo sin el PHPCR-ODM, sencillamente no configures la sección odm para evitar que cargue los servicios. Ten en cuenta que muchos paquetes predefinidos del CMF usan documentos PHPCR-ODM y por ello necesitas habilitar el ODM.

Configurando la sesión PHPCR

La sesión necesita que especifiques una implementación PHPCR en la sección backend para el campo type, junto con opciones de configuración al arranque de la implementación. Actualmente apoyamos jackrabbit, doctrinedbal y midgard2. Independientemente de la interfaz de administración, cada sesión PHPCR necesita un espacio de trabajo, nombre de usuario y contraseña.

Truco

Cada implementación de PHPCR debería proporcionar el espacio de trabajo llamado «default», pero puedes elegir uno diferente. Existe la orden doctrine:phpcr:workspace:create para iniciar un nuevo espacio de trabajo. See also Servicios.

El nombre de usuario y contraseña que especifiques aquí son los utilizados en la capa PHPCR en PHPCR\SimpleCredentials. Normalmente serán diferentes del nombre de usuario y contraseña utilizados por Midgard2 o el DBAL de Doctrine para conectar al RDBMS subyacente donde de hecho se almacenan los datos.

Si estás utilizando una de las interfaces de administración de Jackalope, también puedes especificar opciones. Estas serán puestas en la sesión de Jackalope. Actualmente esto se puede ajustar a nodos prerecuperados poniendo jackalope.fetch_depth a algo más grande que 0.

  • YAML
    # app/config/config.yml
    doctrine_phpcr:
        session:
            backend:
                # ve abajo cómo configurar la interfaz de administración que elejiste
            workspace: default
            username: admin
            password: admin
            ## ajusta opciones para jackrabbit y doctrinedbal (todas las versiones de jackalope)
            # options:
            #    'jackalope.fetch_depth': 1
    

Sesión PHPCR con Jackalope Jackrabbit

Es la única configuración requerida para instalar el Jackrabbit de apache (ve instalando Jackrabbit).

La configuración necesita que el parámetro url apunte a tu jackrabbit. Además puedes afinar algunas otras opciones específicas de jackrabbit, por ejemplo para utilizarlas en la configuración de una carga balanceada o para fallar temprano y aminorar el costo de algunos viajes de ida y vuelta a la interfaz de administración.

  • YAML
    # app/config/config.yml
    doctrine_phpcr:
        session:
            backend:
                type: jackrabbit
                url: http://localhost:8080/server/
                ## únicamente jackrabbit, opcional. ve https://github.com/jackalope/jackalope/blob/master/src/Jackalope/RepositoryFactoryJackrabbit.php
                # default_header: ...
                # expect: 'Esperaba: 100-continue'
                # habilita si de cualquier manera quieres tener una excepción si
                # falla el incio de sesión PHPCR
                # check_login_on_server: false
                # habilita si experimentas fallos de segmentación mientras
                # trabajas con datos binarios en documentos
                # disable_stream_wrapper: true
                # habilita si no quieres usar transacciones y tampoco quieres
                # que el odm use transacciones automáticamente, es altamente
                # recomendable NO deshabilitar las transacciones
                # disable_transactions: true
    

Sesión PHPCR con el Jackalope y DBAL de Doctrine

Este tipo usa Jackalope con una abstracción en la capa de transporte de base de datos de Doctrine para proporcionar PHPCR sin ningún requisito de instalación más allá de cualquiera de los RDBMS apoyados por Doctrine.

Necesitas configurar una conexión de Doctrine según el DBAL elejido en la documentación de Doctrine en Symfony2.

  • YAML
    # app/config/config.yml
    doctrine_phpcr:
        session:
            backend:
                type: doctrinedbal
                connection: doctrine.dbal.default_connection
                # habilita si quieres tener una excepción inmediatamente si falla
                # el inicio de sesión PHPCR
                # check_login_on_server: false
                # habilita si experimentas fallos de segmentación mientras
                # trabajas con datos binarios en documentos
                # disable_stream_wrapper: true
                # habilita si no quieres usar transacciones y tampoco quieres
                # que el odm use transacciones automáticamente, es altamente
                # recomendable NO deshabilitar las transacciones
                # disable_transactions: true
    

Una vez configurada la conexión, puedes crear la base de datos y debes iniciar la base de datos con la orden doctrine:phpcr:init:dbal.

app/console doctrine:database:create
app/console doctrine:phpcr:init:dbal

Truco

Naturalmente, también puedes utilizar una diferente conexión en vez de la predefinida. Es recomendable utilizar una conexión independiente para una base de datos separada si también Doctrine usa el acceso a datos del ORM o DBAL directamente, en lugar de mezclar este dato con las tablas generadas por jackalope-doctrine-dbal. Si tienes una conexión separada, necesitas pasar el nombre de la conexión alterna a la orden doctrine:database:create con la opción --connection. Para las ordenes PHPCR de Doctrine, este parámetro no es necesario al configurar la conexión a utilizar.

Sesión PHPCR con Midgard2

Midgard2 es una aplicación que proporciona una extensión PHP compilada. Esta implementa la API de PHPCR en lo alto de un RDBMS estándar.

To use the Midgard2 PHPCR provider, you must have both the midgard2 PHP extension and the midgard/phpcr package installed. The settings here correspond to Midgard2 repository parameters as explained in the getting started document.

La sesión de configuración de la interfaz de administración es la siguiente:

  • YAML
    # app/config/config.yml
    doctrine_phpcr:
        session:
            backend:
                type: midgard2
                db_type: MySQL
                db_name: midgard2_test
                db_host: "0.0.0.0"
                db_port: 3306
                db_username: ""
                db_password: ""
                db_init: true
                blobdir: /tmp/cmf-blobs
    

Para más información, por favor, ve la documentación oficial del PHPCR de Midgard.

Configurando el PHPCR-ODM de Doctrine

Esta sección de configuración gestiona el sistema PHPCR-ODM de Doctrine. Si no configuras ninguna cosa aquí, los servicios ODM no serán cargados.

Si habilitas auto_mapping, puedes colocar tus asociaciones en <Paquete>/Resources/config/doctrine/<Document>.phpcr.xml resp. ...yml para configurar asociaciones a documentos proporcionadas en el directorio <Paquete>/Document. De lo contrario necesitas configurar manualmente la sección de asignaciones.

Si auto_generate_proxy_classes es false, necesitas ejecutar la orden cache:warmup para tener las clases delegadas generadas después de que modificaste un documento. También puedes ajustar cómo y dónde generar las clases delegadas con las opciones proxy_dir y proxy_namespace. Normalmente las predefinidas están bien aquí.

También puedes habilitar el almacenamiento de metadatos en caché.

  • YAML
    # app/config/config.yml
    doctrine_phpcr:
        odm:
            configuration_id:     ~
            auto_mapping: true
            mappings:
                <name>:
                    mapping:              true
                    type:                 ~
                    dir:                  ~
                    alias:                ~
                    prefix:               ~
                    is_bundle:            ~
            auto_generate_proxy_classes: %kernel.debug%
            proxy_dir:            %kernel.cache_dir%/doctrine/PHPCRProxies
            proxy_namespace:      PHPCRProxies
    
            metadata_cache_driver:
                type:                 array
                host:                 ~
                port:                 ~
                instance_class:       ~
                class:                ~
                id:                   ~

Configuración de traducción

Si estás utilizando documentos multilingües, necesitas configurar los idiomas disponibles. Para más información en documentos multilingües, ve la documentación PHPCR-ODM en multilenguaje.

  • YAML
    # app/config/config.yml
    doctrine_phpcr:
        odm:
            ...
            locales:
                en: [en, de, fr]
                de: [de, en, fr]
                fr: [fr, en, de]
    

Este bloque define el orden de regiones alternativas para ver si un documento no está traducido al idioma requerido.

Ajustes generales

Si ajustas la ruta a jackrabbit_jar, puedes utilizar la orden de consola doctrine:phpcr:jackrabbit para arrancar y parar el jackrabbit.

Puedes poner a punto la producción de la orden doctrine:phpcr:dump con dump_max_line_length.

  • YAML
    # app/config/config.yml
    doctrine_phpcr:
        jackrabbit_jar:       /ruta/a/jackrabbit.jar
        dump_max_line_length:  120
    

Configurando múltiples sesiones

Si necesitas más de una interfaz de administración PHPCR, puedes definir sessions como hijo de la información de session. Cada sesión tiene un nombre y configuración que puedes utilizar directamente en session. también puedes sobrescribir qué sesión utilizar como default_session.

  • YAML
    # app/config/config.yml
    doctrine_phpcr:
        session:
            default_session:      ~
            sessions:
                <name>:
                    workspace:            ~ # Requerido
                    username:             ~
                    password:             ~
                    backend:
                        # como arriba
                    options:
                        # como arriba
    

Si estás utilizando el ODM, también querrás configurar múltiples gestores de documento.

Dentro de la sección odm, puedes añadir entradas nombradas en document_managers. Para utilizar la sesión no predefinida, especifica el atributo session.

  • YAML
    odm:
        default_document_manager:  ~
        document_managers:
            <name>:
                # mismas claves como directamente en odm, ve arriba.
                session: <sessionname>
    

Un ejemplo completo se ve como sigue:

  • YAML
    doctrine_phpcr:
        # configura las sesiones PHPCR
        session:
            sessions:
    
                default:
                    backend: %phpcr_backend%
                    workspace: %phpcr_workspace%
                    username: %phpcr_user%
                    password: %phpcr_pass%
    
                website:
                    backend:
                        type: jackrabbit
                        url: %magnolia_url%
                    workspace: website
                    username: %magnolia_user%
                    password: %magnolia_pass%
    
                dms:
                    backend:
                        type: jackrabbit
                        url: %magnolia_url%
                    workspace: dms
                    username: %magnolia_user%
                    password: %magnolia_pass%
        # activa la capa ODM
        odm:
            document_managers:
                default:
                    session: default
                    mappings:
                        SandboxMainBundle: ~
                        SymfonyCmfContentBundle: ~
                        SymfonyCmfMenuBundle: ~
                        SymfonyCmfRoutingExtraBundle: ~
    
                website:
                    session: website
                    configuration_id: sandbox_magnolia.odm_configuration
                    mappings:
                        SandboxMagnoliaBundle: ~
    
                dms:
                    session: dms
                    configuration_id: sandbox_magnolia.odm_configuration
                    mappings:
                        SandboxMagnoliaBundle: ~
    
            auto_generate_proxy_classes: %kernel.debug%

Truco

Este ejemplo también utiliza diferentes configuraciones par repositorio (ve el atributo repository_id). Este caso se explica en Usando una clase documento personalizada asociada con PHPCR-ODM.

Servicios

Puedes acceder el servicios PHPCR con esto:

<?php

namespace Acme\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction()
    {
        // ManagerRegistry instance with references to all sessions and document manager instances
        $registry = $this->container->get('doctrine_phpcr');
        // instancia de la sesión PHPCR
        $session = $this->container->get('doctrine_phpcr.default_session');
        // instancia del gestor del documento ODM de PHPCR
        $documentManager = $this->container->get('doctrine_phpcr.odm.default_document_manager');
    }
}

Eventos

You can tag services to listen to Doctrine PHPCR-ODM events. Esto trabaja de la misma manera que en el ORM de Doctrine. Las únicas diferencias son:

  • Usa la etiqueta doctrine_phpcr.event_listener resp. doctrine_phpcr.event_subscriber en vez de doctrine.event_listener.
  • expect the argument to be of class Doctrine\ODM\PHPCR\Event\LifecycleEventArgs rather than in the ORM namespace. (this is subject to change, as doctrine commons 2.4 provides a common class for this event).

You can register for the events as described in the PHPCR-ODM documentation. Or you can tag your services as event listeners resp. event subscribers.

  • YAML
    services:
        my.listener:
            class: Acme\SearchBundle\EventListener\SearchIndexer
                tags:
                        - { name: doctrine_phpcr.event_listener, event: postPersist }
    
        my.subscriber:
            class: Acme\SearchBundle\EventSubscriber\MySubscriber
                tags:
                        - { name: doctrine_phpcr.event_subscriber }
    

Consejo

Doctrine event subscribers (both ORM and PHPCR-ODM) can not return a flexible array of methods to call like the Symfony event subscriber can do. Doctrine event subscribers must return a simple array of the event names they subscribe to. Doctrine will then expect methods on the subscriber with the names of the subscribed events, just as when using an event listener.

More information with PHP code examples for the doctrine event system integration is in this Symfony cookbook entry.

Constraint validator

The bundle provides a ValidPhpcrOdm constraint validator you can use to check if your document Id or Nodename and Parent fields are correct.

  • YAML
    # src/Acme/BlogBundle/Resources/config/validation.yml
    Acme\BlogBundle\Entity\Author:
        constraints:
            - Doctrine\Bundle\PHPCRBundle\Validator\Constraints\ValidPhpcrOdm
    
  • PHP
    // src/Acme/BlogBundle/Entity/Author.php
    
    // ...
    use Doctrine\Bundle\PHPCRBundle\Validator\Constraints as OdmAssert;
    
    /**
     * @OdmAssert\ValidPhpcrOdm
     */
    class Author
    {
       ...
    }
    
  • XML
    <!-- Resources/config/validation.xml -->
    <?xml version="1.0" ?>
    <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
            http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
        <class name="Symfony\Cmf\Bundle\RoutingExtraBundle\Document\Route">
            <constraint name="Doctrine\Bundle\PHPCRBundle\Validator\Constraints\ValidPhpcrOdm" />
        </class>
    </constraint-mapping>
    

Form types

The bundle provides a couple of handy form types for PHPCR and PHPCR-ODM specific cases, along with form type guessers.

phpcr_odm_image

The phpcr_odm_image form maps to a document of type Doctrine\ODM\PHPCR\Document\Image and provides a preview of the uploaded image. To use it, you need to include the LiipImagineBundle in your project and define an imagine filter for thumbnails.

This form type is only available if explicitly enabled in your application configuration by defining the imagine section under the odm section with at least enabled: true. You can also configure the imagine filter to use for the preview, as well as additional filters to remove from cache when the image is replaced. If the filter is not specified, it defaults to image_upload_thumbnail.

  • YAML
    doctrine_phpcr:
        ...
        odm:
            imagine:
                enabled: true
                # filter: image_upload_thumbnail
                # extra_filters:
                #    - imagine_filter_name1
                #    - imagine_filter_name2
    
    # Imagine Configuration
    liip_imagine:
        ...
        filter_sets:
            # define the filter to be used with the image preview
            image_upload_thumbnail:
                data_loader: phpcr
                filters:
                    thumbnail: { size: [100, 100], mode: outbound }
    

Then you can add images to document forms as follows:

use Symfony\Component\Form\FormBuilderInterface;

protected function configureFormFields(FormBuilderInterface $formBuilder)
{
     $formBuilder
        ->add('image', 'phpcr_odm_image', array('required' => false))
     ;
}

Truco

If you set required to true for the image, the user must re-upload a new image each time he edits the form. If the document must have an image, it makes sense to require the field when creating a new document, but make it optional when editing an existing document. We are trying to make this automatic.

Next you will need to add the fields.html.twig template from the DoctrinePHPCRBundle to the form.resources, to actually see the preview of the uploaded image in the backend.

  • YAML
    # Twig Configuration
    twig:
        form:
            resources:
                - 'DoctrinePHPCRBundle:Form:fields.html.twig'
    

The document that should contain the Image document has to implement a setter method. To profit from the automatic guesser of the form layer, the name in the form element and this method name have to match:

public function setImage($image)
{
    if (!$image) {
        // Esto es normal y sucede cuándo ninguna nueva imagen se ha cargado
        return;
    } elseif ($this->image && $this->image->getFile()) {
        // PENDIENTE: necesario hasta que se haya corregidi este fallo en PHPCRODM: https://github.com/doctrine/phpcr-odm/pull/262
        $this->image->getFile()->setFileContent($image->getFile()->getFileContent());
    } else {
        $this->image = $image;
    }
}

To delete an image, you need to delete the document containing the image. (There is a proposal to improve the user experience for that in a DoctrinePHPCRBundle issue.)

Nota

There is a doctrine listener to invalidate the imagine cache for the filters you specified. This listener will only operate when an Image is changed in a web request, but not when a CLI command changes images. When changing images with commands, you should handle cache invalidation in the command or manually remove the imagine cache afterwards.

phpcr_odm_reference_collection

This form type handles editing ReferenceMany collections on PHPCR-ODM documents. It is a choice field with an added referenced_class required option that specifies the class of the referenced target document.

To use this form type, you also need to specify the list of possible reference targets as an array of PHPCR-ODM ids or PHPCR paths.

The minimal code required to use this type looks as follows:

$dataArr = array(
    '/some/phpcr/path/item_1' => 'first item',
    '/some/phpcr/path/item_2' => 'second item',
);

$formMapper
    ->with('form.group_general')
        ->add('myCollection', 'phpcr_odm_reference_collection', array(
            'choices'   => $dataArr,
            'referenced_class'  => 'Class\Of\My\Referenced\Documents',
        ))
    ->end();

Truco

When building an admin interface with Sonata Admin there is also the sonata_type_model that is more powerful, allowing to add to the referenced documents on the fly. Unfortunately it is currently broken.

phpcr_reference

The phpcr_reference represents a PHPCR Property of type REFERENCE or WEAKREFERENCE within a form. The input will be rendered as a text field containing either the PATH or the UUID as per the configuration. The form will resolve the path or id back to a PHPCR node to set the reference.

This type extends the text form type. It adds an option transformer_type that can be set to either path or uuid.

Fixture loading

To use the doctrine:phpcr:fixtures:load command, you additionally need to install the DoctrineFixturesBundle which brings the Doctrine data-fixtures into Symfony2.

Fixtures work the same way they work for Doctrine ORM. You write fixture classes implementing Doctrine\Common\DataFixtures\FixtureInterface. If you place them in <Bundle>DataFixturesPHPCR, they will be auto detected if you specify no path to the fixture loading command.

A simple example fixture class looks like this:

<?php

namespace MyBundle\DataFixtures\PHPCR;

use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\FixtureInterface;

class LoadMyData implements FixtureInterface
{
    public function load(ObjectManager $manager)
    {
        // Create and persist your data here...
    }
}

For more on fixtures, see the documentation of the DoctrineFixturesBundle.

Migration loading

The DoctrinePHPCRBundle also ships with a simple command to run migration scripts. Migrations should implement the Doctrine\Bundle\PHPCRBundle\Migrator\MigratorInterface and registered as a service with a doctrine_phpcr.migrator tag contains an alias attribute uniquely identifying the migrator. There is an optional Doctrine\Bundle\PHPCRBundle\Migrator\AbstractMigrator class to use as a basis. To find out available migrations run:

$ php app/console doctrine:phpcr:migrator

Then pass in the name of the migrator to run it, optionally passing in an --identifier, --depth or --session argument. The later argument determines which session name to set on the migrator, while the first two arguments will simply be passed to the migrate() method. You can find an example migrator in the SimpleCmsBundle.

Órdenes del PHPCR de Doctrine

Todas las órdenes sobre el PHPCR van prefijadas con doctrine:phpcr y puedes utilizar el argumento --session para utilizar una sesión distinta a la predefinida si configuraste varias sesiones PHPCR.

Algunas de estas órdenes son específicas a una interfaz de administración o al ODM. Esas órdenes sólo estarán disponibles si tal interfaz de administración está configurada.

Usa app/console help <orden> para ver todas las opciones que tiene cada orden.

  • doctrine:phpcr:workspace:create Create a workspace in the configured repository
  • doctrine:phpcr:workspace:list List all available workspaces in the configured repository
  • doctrine:phpcr:purge Remove a subtree or all content from the repository
  • doctrine:phpcr:repository:init Register node types and create base paths
  • doctrine:phpcr:register-node-types Register node types from a .cnd file in the PHPCR repository
  • doctrine:phpcr:fixtures:load Load data fixtures to your PHPCR database.
  • doctrine:phpcr:import Import xml data into the repository, either in JCR system view format or arbitrary xml
  • doctrine:phpcr:export Export nodes from the repository, either to the JCR system view format or the document view format
  • doctrine:phpcr:dump Output all or some content of the repository
  • doctrine:phpcr:query Execute a JCR SQL2 statement
  • doctrine:phpcr:mapping:info Shows basic information about all mapped documents

Nota

To use the doctrine:phpcr:fixtures:load command, you additionally need to install the DoctrineFixturesBundle and its dependencies. Ve su página de documentación para aprender a utilizar los accesorios.

Órdenes específicas de Jackrabbit

Si estás utilizando jackalope-jackrabbit, también tienes una orden para arrancar y detener el servidor jackrabbit:

  • jackalope:run:jackrabbit Arranca y detiene el servidor Jackrabbit

Órdenes específicas para el DBAL de Doctrine

Si estás utilizando jackalope-doctrine-dbal, tienes una orden para iniciar la base de datos:

  • jackalope:init:dbal Prepara la base de datos para el DBAL de Doctrine con Jackalope

Ten en cuenta que también puedes utilizar la orden dbal de doctrine para crear la base de datos.

Algunas ordenes de ejemplo

Ejecutando consultas SQL2 contra el repositorio

app/console doctrine:phpcr:query "SELECT title FROM [nt:unstructured] WHERE NAME() = 'home'"

Vertiendo nodos bajo /cms/simple incluyendo sus propiedades

app/console doctrine:phpcr:dump /cms/simple --props
Bifúrcame en GitHub