Maintaining Data in the Repository
PHPCR-ODM provides initializers that ensure a repository is ready for production use, migrators to programmatically load data and fixture loading for handling testing and demo fixtures.
Repository Initializers
The Initializer is the PHPCR equivalent of the ORM schema tools. It is used to let your application PHPCR node types and to create required base paths in the repository.
The concept of base paths is needed because there are no separate "tables" as in a relational database, but one tree containing all data. To be able to add a document, you need to ensure the parent path is already present in the repository. |
Initializers have to implement the
Doctrine\Bundle\PHPCRBundle\Initializer\InitializerInterface
. If you don't
need any special logic and want to create plain PHPCR nodes and not documents,
you can simply define services with GenericInitializer
. The generic
Initializer expects a name to identify the Initializer, an array of repository
paths it will create if they do not exist and an optional string defining
namespaces and primary / mixin node types in the CND language that should be
registered with the repository.
A service to use the generic Initializer looks like this:
You can execute your Initializers using the following command:
$ php bin/console doctrine:phpcr:repository:init
The load data fixtures command automatically executes the Initializers after purging the database, before executing the fixtures. |
The generic Initializer only creates PHPCR nodes. If you want to create
specific documents, you need your own Initializer. The interesting method
to overwrite is the init
method. It is passed the ManagerRegistry
,
from which you can retrieve the PHPCR session but also the document manager:
// src/App/Initializer/SiteInitializer.php
namespace App\Initializer;
use App\Documents\Site;
use Doctrine\Bundle\PHPCRBundle\Initializer\InitializerInterface;
use Doctrine\Bundle\PHPCRBundle\ManagerRegistry;
use PHPCR\SessionInterface;
use PHPCR\Util\NodeHelper;
class SiteInitializer implements InitializerInterface
{
private $basePath;
public function __construct($basePath = '/cms')
{
$this->basePath = $basePath;
}
public function init(ManagerRegistry $registry)
{
$dm = $registry->getManagerForClass(Site::class);
if ($dm->find(null, $this->basePath)) {
return;
}
$site = new Site();
$site->setId($this->basePath);
$dm->persist($site);
$dm->flush();
$session = $registry->getConnection();
// create the 'cms', 'pages', and 'posts' nodes
NodeHelper::createPath($session, '/cms/pages');
NodeHelper::createPath($session, '/cms/posts');
NodeHelper::createPath($session, '/cms/routes');
$session->save();
}
public function getName()
{
return 'Site Initializer';
}
}
Define a service for your Initializer as follows:
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 bin/console doctrine:phpcr:migrator:migrate
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.
A simple alternative if you do not need to reproduce the result can be to export part of your repository and re-import it on the target server. This is described in Simple Backup and Restore. |
Fixture Loading
To use the doctrine:phpcr:fixtures:load
command, you additionally need to
install the DoctrineFixturesBundle which brings the
Doctrine data-fixtures into Symfony.
Fixtures work the same way they work for Doctrine ORM. You write fixture
classes implementing Doctrine\Common\DataFixtures\FixtureInterface
. If you
place them in <App|Bundle>\DataFixtures\PHPCR
, they will be auto detected if you
don't specify a path in the command.
A simple example fixture class looks like this:
// src/App/DataFixtures/PHPCR/LoadPageData.php
namespace App\DataFixtures\PHPCR;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\ODM\PHPCR\DocumentManager;
class LoadPageData implements FixtureInterface
{
public function load(ObjectManager $manager)
{
if (!$manager instanceof DocumentManager) {
$class = get_class($manager);
throw new \RuntimeException("Fixture requires a PHPCR ODM DocumentManager instance, instance of '$class' given.");
}
// ... create and persist your data here
}
}
For more on fixtures, see the documentation of the DoctrineFixturesBundle.