Skip to content

Commit

Permalink
Console command for verifying unique node type mapping.
Browse files Browse the repository at this point in the history
  • Loading branch information
sarcher committed Nov 2, 2015
1 parent ce11972 commit 79c476c
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 0 deletions.
1 change: 1 addition & 0 deletions bin/phpcrodm.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
new \Doctrine\ODM\PHPCR\Tools\Console\Command\GenerateProxiesCommand(),
new \Doctrine\ODM\PHPCR\Tools\Console\Command\DumpQueryBuilderReferenceCommand(),
new \Doctrine\ODM\PHPCR\Tools\Console\Command\InfoDoctrineCommand(),
new \Doctrine\ODM\PHPCR\Tools\Console\Command\VerifyUniqueNodeTypesMappingCommand(),
new \Doctrine\ODM\PHPCR\Tools\Console\Command\RegisterSystemNodeTypesCommand(),
));
if (isset($extraCommands) && ! empty($extraCommands)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?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\ODM\PHPCR\Tools\Console\Command;

use Doctrine\ODM\PHPCR\Tools\Helper\UniqueNodeTypeHelper;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Show information about mapped documents
*/
class VerifyUniqueNodeTypesMappingCommand extends Command
{
/**
* {@inheritdoc}
*/
protected function configure()
{
parent::configure();

$this
->setName('doctrine:phpcr:mapping:verify_unique_node_types')
->setDescription('Verify that documents with unique node types are correctly mapped')
->setHelp(<<<EOT
The <info>%command.name%</info> command checks all mapped PHPCR-ODM documents
and verifies that any marked as having unique node types are, in fact, unique.
EOT
);
}

/**
* {@inheritDoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$documentManager = $this->getHelper('phpcr')->getDocumentManager();

UniqueNodeTypeHelper::checkNodeTypeMappings($documentManager, $output);

return 0;
}
}
71 changes: 71 additions & 0 deletions lib/Doctrine/ODM/PHPCR/Tools/Helper/UniqueNodeTypeHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?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\ODM\PHPCR\Tools\Helper;

use Doctrine\ODM\PHPCR\DocumentManagerInterface;
use Doctrine\ODM\PHPCR\Mapping\MappingException;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Provides unique node type mapping verification.
*/
class UniqueNodeTypeHelper
{
/**
* Check each mapped PHPCR-ODM document for the given document manager,
* throwing an exception if any document is set to use a unique node
* type but the node type is re-used. If an OutputInterface is provided,
* write some basic information to it.
*
* @param DocumentManagerInterface $documentManager The document manager to check mappings for.
* @param OutputInterface $output If provided, output will be written here.
*
* @throws MappingException
*/
public static function checkNodeTypeMappings(DocumentManagerInterface $documentManager, OutputInterface $output = null)
{
$knownNodeTypes = array();
$allMetadata = $documentManager->getMetadataFactory()->getAllMetadata();

foreach ($allMetadata as $classMetadata) {
if ($classMetadata->hasUniqueNodeType() && isset($knownNodeTypes[$classMetadata->getNodeType()])) {
throw new MappingException(sprintf(
'The class "%s" is mapped with uniqueNodeType set to true, but the node type "%s" is used by "%s" as well.',
$classMetadata->name,
$classMetadata->getNodeType(),
$knownNodeTypes[$classMetadata->getNodeType()]
));
}

$knownNodeTypes[$classMetadata->getNodeType()] = $classMetadata->name;

if (!is_null($output)) {

$output->writeln(sprintf(
'The document <info>%s</info> uses %snode type <info>%s</info>',
$classMetadata->name,
$classMetadata->hasUniqueNodeType() ? '<comment>uniquely mapped</comment> ' : '',
$classMetadata->getNodeType()
));

}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

namespace Doctrine\Tests\ODM\PHPCR\Tools\Helper;

use Doctrine\ODM\PHPCR\Mapping\ClassMetadata;
use Doctrine\ODM\PHPCR\Tools\Helper\UniqueNodeTypeHelper;

/**
* Verify the behavior of the UniqueNodeTypeHelper class that is used
* to confirm that any documents set to use unique node types do not
* conflict with any other mappings.
*/
class UniqueNodeTypeHelperTest extends \PHPUnit_Framework_TestCase
{
/**
* Configure a mocked DocumentManager that will return the supplied
* set of metadata.
*
* @param ClassMetadata[] $metadata
*
* @return DocumentManager
*/
public function configureDocumentManager(array $metadata)
{
$classMetadataFactory = $this->getMockBuilder('Doctrine\ODM\PHPCR\Mapping\ClassMetadataFactory')
->disableOriginalConstructor()
->setMethods(array('getAllMetadata'))
->getMock();
$classMetadataFactory->expects($this->once())
->method('getAllMetadata')
->will($this->returnValue($metadata));

$documentManager = $this->getMockBuilder('Doctrine\ODM\PHPCR\DocumentManager')
->disableOriginalConstructor()
->setMethods(array('getMetadataFactory'))
->getMock();
$documentManager->expects($this->once())
->method('getMetadataFactory')
->will($this->returnValue($classMetadataFactory));

return $documentManager;
}

/**
* Verify that a MappingException is correctly thrown when more than
* one document uses the same node type, but one is marked as unique.
*
* @expectedException Doctrine\ODM\PHPCR\Mapping\MappingException
* @expectedExceptionMessage The class "Doctrine\PHPCR\Models\ClassC" is mapped with uniqueNodeType set to true, but the
* node type "nt:unstructured" is used by "Doctrine\PHPCR\Models\ClassA" as well.
*/
public function testCheckNodeTypeMappingsWithDuplicate()
{
$metadataA = new ClassMetadata('Doctrine\PHPCR\Models\ClassA');
$metadataA->setNodeType('nt:unstructured');

$metadataB = new ClassMetadata('Doctrine\PHPCR\Models\ClassB');
$metadataB->setNodeType('custom:type');
$metadataB->setUniqueNodeType(true);

$metadataC = new ClassMetadata('Doctrine\PHPCR\Models\ClassC');
$metadataC->setNodeType('nt:unstructured');
$metadataC->setUniqueNodeType(true);

$documentManager = $this->configureDocumentManager(array(
$metadataA,
$metadataB,
$metadataC
));

UniqueNodeTypeHelper::checkNodeTypeMappings($documentManager);
}

/**
* Verify that no exception results from a correctly-mapped set
* of documents.
*/
public function testCheckNodeTypeMappingsWithoutDuplicate()
{
$metadataA = new ClassMetadata('Doctrine\PHPCR\Models\ClassA');
$metadataA->setNodeType('nt:unstructured');

$metadataB = new ClassMetadata('Doctrine\PHPCR\Models\ClassB');
$metadataB->setNodeType('custom:type');
$metadataB->setUniqueNodeType(true);

$metadataC = new ClassMetadata('Doctrine\PHPCR\Models\ClassC');
$metadataA->setNodeType('nt:unstructured');

$documentManager = $this->configureDocumentManager(array(
$metadataA,
$metadataB,
$metadataC
));

UniqueNodeTypeHelper::checkNodeTypeMappings($documentManager);
}
}

0 comments on commit 79c476c

Please sign in to comment.