Permalink
Browse files

added migrator

  • Loading branch information...
1 parent 5fa30aa commit 992fb93a565791ea1474ef8262a38a964392233f @lsmith77 lsmith77 committed Nov 29, 2012
View
88 Command/MigratorMigrateCommand.php
@@ -0,0 +1,88 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Bundle\PHPCRBundle\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
+
+class MigratorMigrateCommand extends ContainerAwareCommand
+{
+ /**
+ * @see \Symfony\Bundle\FrameworkBundle\Command\Command
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('doctrine:phpcr:migrator:migrate')
+ ->setDescription('Migrates PHPCR data.')
+ ->addArgument('migrator_name', InputArgument::OPTIONAL, 'The name of the alias/service to be used to migrate the data.')
+ ->addOption('identifier', null, InputOption::VALUE_OPTIONAL, 'Path or UUID of the node to dump', '/')
+ ->addOption('depth', null, InputOption::VALUE_OPTIONAL, 'Set to a number to limit how deep into the tree to recurse', "-1")
+ ->addOption('session', null, InputOption::VALUE_OPTIONAL, 'The session to use for this command', null)
+ ->setHelp(<<<EOT
+To find the available 'migrators' run this command without an input argument
+EOT
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $container = $this->getContainer();
+ $migrators = $container->getParameter('doctrine_phpcr.migrate.migrators');
+
+ $migratorName = $input->getArgument('migrator_name');
+ if (!$migratorName) {
+ $output->write("Available migrators:", true);
+ $output->write(implode("\n", array_keys($migrators)), true);
+ return 0;
+ }
+
+ $id = isset($migrators[$migratorName]) ? $migrators[$migratorName] : null;
+ if (!$id || !$container->has($id)) {
+ throw new \InvalidArgumentException("Wrong value '$migratorName' for migrator_name argument.\nAvailable migrators:\n".implode("\n", array_keys($migrators)));
+ }
+
+ $migrator = $container->get($id);
+
+ $mr = $container->get('doctrine_phpcr');
+ $session = $mr->getConnection($input->getOption('session'));
+ $migrator->init($session, $output);
+
+ $identifier = $input->getOption('identifier');
+ $depth = $input->getOption('depth');
+ $output->write("Migrating identifier '$identifier' with depth '$depth' using '$migratorName'", true);
+ $exitCode = $migrator->migrate($identifier, $depth);
+
+ if (0 === $exitCode) {
+ $output->write("Successful", true);
+ } else {
+ $output->write("Failed!", true);
+ }
+
+ return $exitCode;
+ }
+}
View
45 DependencyInjection/Compiler/MigratorPass.php
@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+
+/**
+ * A CompilerPass which registers available migrators.
+ */
+class MigratorPass implements CompilerPassInterface
+{
+ /**
+ * @param ContainerBuilder $container
+ */
+ public function process(ContainerBuilder $container)
+ {
+ $migrators = array();
+ foreach ($container->findTaggedServiceIds('doctrine_phpcr.migrator') as $id => $attributes) {
+ $alias = isset($attributes[0]['alias']) ? $attributes[0]['alias'] : null;
+ $migrators[$alias] = $id;
+ }
+
+ $container->setParameter('doctrine_phpcr.migrate.migrators', $migrators);
+ }
+}
+
View
15 DependencyInjection/DoctrinePHPCRExtension.php
@@ -40,8 +40,8 @@ class DoctrinePHPCRExtension extends AbstractDoctrineExtension
{
private $defaultSession;
private $sessions = array();
-
private $bundleDirs = array();
+ private $loader;
public function load(array $configs, ContainerBuilder $container)
{
@@ -57,6 +57,7 @@ public function load(array $configs, ContainerBuilder $container)
$processor = new Processor();
$configuration = new Configuration($container->getParameter('kernel.debug'));
$config = $processor->processConfiguration($configuration, $configs);
+ $this->loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
if (isset($config['workspace_dir'])) {
$container->setParameter('doctrine_phpcr.workspace_dir', $config['workspace_dir']);
@@ -76,12 +77,13 @@ public function load(array $configs, ContainerBuilder $container)
}
$this->odmLoad($config['odm'], $container);
}
+
+ $this->loader->load('migrator.xml');
}
private function sessionLoad($config, ContainerBuilder $container)
{
- $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
- $loader->load('phpcr.xml');
+ $this->loader->load('phpcr.xml');
$sessions = $loaded = array();
foreach ($config['sessions'] as $name => $session) {
@@ -97,14 +99,14 @@ private function sessionLoad($config, ContainerBuilder $container)
case 'doctrinedbal':
case 'jackrabbit':
if (empty($loaded['jackalope'])) {
- $loader->load('jackalope.xml');
+ $this->loader->load('jackalope.xml');
$loaded['jackalope'] = true;
}
$this->loadJackalopeSession($session, $container, $type);
break;
case 'midgard2':
if (empty($loaded['midgard2'])) {
- $loader->load('midgard2.xml');
+ $this->loader->load('midgard2.xml');
$loaded['midgard2'] = true;
}
$this->loadMidgard2Session($session, $container);
@@ -235,8 +237,7 @@ private function loadMidgard2Session(array $session, ContainerBuilder $container
private function odmLoad(array $config, ContainerBuilder $container)
{
- $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
- $loader->load('odm.xml');
+ $this->loader->load('odm.xml');
$documentManagers = array();
foreach ($config['document_managers'] as $name => $documentManager) {
View
2 DoctrinePHPCRBundle.php
@@ -28,6 +28,7 @@
use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPass;
use Doctrine\Common\Util\ClassUtils;
+use Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\MigratorPass;
use Doctrine\Bundle\PHPCRBundle\OptionalCommand\InitDoctrineDbalCommand;
use Doctrine\Bundle\PHPCRBundle\OptionalCommand\JackrabbitCommand;
@@ -37,6 +38,7 @@ public function build(ContainerBuilder $container)
{
parent::build($container);
+ $container->addCompilerPass(new MigratorPass());
$container->addCompilerPass(new RegisterEventListenersAndSubscribersPass('doctrine_phpcr.sessions', 'doctrine_phpcr.odm.%s_session.event_manager', 'doctrine_phpcr'), PassConfig::TYPE_BEFORE_OPTIMIZATION);
}
View
49 Migrator/AbstractMigrator.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Bundle\PHPCRBundle\Migrator;
+
+use Symfony\Component\Console\Output\OutputInterface;
+use PHPCR\SessionInterface;
+use PHPCR\Util\TraversingItemVisitor;
+
+abstract class AbstractMigrator extends TraversingItemVisitor implements MigratorInterface
+{
+ /**
+ * @var PHPCR\SessionInterface
+ */
+ protected $session;
+
+ /*
+ * @var Symfony\Component\Console\Output\OutputInterface
+ */
+ protected $output;
+
+ public function init(SessionInterface $session, OutputInterface $output)
+ {
+ $this->session = $session;
+ $this->output = $output;
+ }
+
+ public function setLevel($level)
+ {
+ $this->currentDepth = $level;
+ }
+}
View
41 Migrator/MigratorInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\Bundle\PHPCRBundle\Migrator;
+
+use PHPCR\SessionInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+interface MigratorInterface
+{
+ /**
+ * @param \PHPCR\SessionInterface $session
+ * @param \Symfony\Component\Console\Output\OutputInterface $output
+ * @return void
+ */
+ public function init(SessionInterface $session, OutputInterface $output);
@stof
stof Nov 29, 2012

should the migrator be tied to the Console component ?

@lsmith77
lsmith77 Nov 29, 2012

i was pondering this as well .. one alternative would be returning an array of messages that are then outputted in the command.

@dbu
dbu Nov 29, 2012

as long as we are in the phpcr bundle here, i think its not a problem. if we would want the migrator to become part of doctrine-phpcr however, i agree we should make the console optional.

i think in mid-term, we might want to do a phpcr-odm-migrations project similar to the DoctrineMigrations. or extending that one if suitable. but for right now, i think having this here is a good starting point to solve the problem at hand for existing users.

+
+ /**
+ * @param string $identifer
+ * @param int $depth
+ * @return int exit code
+ */
+ public function migrate($identifer = '/', $depth = -1);
+}
View
12 Resources/config/migrator.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" ?>
+
+<container xmlns="http://symfony.com/schema/dic/services"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
+
+ <services>
+
+ <service id="doctrine_phpcr.migrate.helper" class="Doctrine\Bundle\PHPCRBundle\Helper\MigrationHelper" />
@stof
stof Nov 29, 2012

This class does not exist

+
+ </services>
+</container>

2 comments on commit 992fb93

@stof
Doctrine member

shouldn't this be shipped in PHPCR-Utils ?

@lsmith77
Doctrine member

@stof we (@dbu and I) discussed this .. its certainly possible, but would require some rewriting to handle the currently lazy loaded services from the DIC. if someone does the work, i am willing to merge it .. but right now it seemed like too much work.

Please sign in to comment.