Skip to content

[POC] Metadata and Annotation support #209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: 3.x
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 65 additions & 50 deletions DependencyInjection/CmfRoutingExtension.php
Original file line number Diff line number Diff line change
@@ -34,10 +34,12 @@ public function load(array $configs, ContainerBuilder $container)
{
$config = $this->processConfiguration(new Configuration(), $configs);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('metadata.xml');

if ($config['dynamic']['enabled']) {
// load this even if no explicit enabled value but some configuration
$this->setupDynamicRouter($config['dynamic'], $container, $loader);
$this->setupMetadataDrivers($config['dynamic'], $container);
}

/* set up the chain router */
@@ -53,6 +55,52 @@ public function load(array $configs, ContainerBuilder $container)
$this->setupFormTypes($config, $container, $loader);
}

public function setupMetadataDrivers($config, ContainerBuilder $container)
{
$configDriver = $container->getDefinition($this->getAlias() . '.metadata.driver.configuration');
$annotationDriver = $container->getDefinition($this->getAlias() . '.metadata.driver.annotation');

$mapping = array();

$controller = $container->getParameter($this->getAlias() . '.generic_controller');;

// configure annotation driver
$annotationDriver->addMethodCall('setGenericController', array($controller));

$mappings = array();

// configure configuration driver
if (!empty($config['controllers_by_class'])) {
foreach ($config['controllers_by_class'] as $classFqn => $controller) {
if (!isset($mappings[$classFqn])) {
$mappings[$classFqn] = array();
}

$mappings[$classFqn]['controller'] = $controller;
}
}

if (!empty($config['templates_by_class'])) {
foreach ($config['templates_by_class'] as $classFqn => $template) {
if (!isset($mappings[$classFqn])) {
$mappings[$classFqn] = array();
}

$mappings[$classFqn]['template'] = $template;
}
}

foreach ($mappings as $classFqn => &$mapping) {
if (!isset($mapping['controller'])) {
$mapping['controller'] = $container->getParameter(
$this->getAlias() . '.generic_controller'
);
}

$configDriver->addMethodCall('registerMapping', array($classFqn, $mapping));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The the validation for this mapping will be triggered the first time the configuration driver is instantiated. So it is not as early as you might want, but it the validation is eager and not lazy. See the ConfigurationDriver.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it still means we have to run the validation at runtime rather than compile time, which imho sucks. can't we keep validating here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would, I think, mean doing the same validation in two places. I guess one way around this problem would be to listen to a cache warming event or similar, that way drivers which are capable of validating their mapped objects (e.g. DI driver, XML, YAML and annotations when possible) can do so eagerly?

}
}

public function setupFormTypes(array $config, ContainerBuilder $container, LoaderInterface $loader)
{
$loader->load('form-type.xml');
@@ -76,7 +124,7 @@ public function setupFormTypes(array $config, ContainerBuilder $container, Loade
private function setupDynamicRouter(array $config, ContainerBuilder $container, LoaderInterface $loader)
{
// strip whitespace (XML support)
foreach (array('controllers_by_type', 'controllers_by_class', 'templates_by_class', 'route_filters_by_id') as $option) {
foreach (array('controllers_by_type', 'route_filters_by_id') as $option) {
$config[$option] = array_map(function ($value) {
return trim($value);
}, $config[$option]);
@@ -86,11 +134,10 @@ private function setupDynamicRouter(array $config, ContainerBuilder $container,
if (null === $defaultController) {
$defaultController = $config['generic_controller'];
}

$container->setParameter($this->getAlias() . '.default_controller', $defaultController);
$container->setParameter($this->getAlias() . '.generic_controller', $config['generic_controller']);
$container->setParameter($this->getAlias() . '.controllers_by_type', $config['controllers_by_type']);
$container->setParameter($this->getAlias() . '.controllers_by_class', $config['controllers_by_class']);
$container->setParameter($this->getAlias() . '.templates_by_class', $config['templates_by_class']);
$container->setParameter($this->getAlias() . '.uri_filter_regexp', $config['uri_filter_regexp']);
$container->setParameter($this->getAlias() . '.route_collection_limit', $config['route_collection_limit']);

@@ -150,55 +197,23 @@ private function setupDynamicRouter(array $config, ContainerBuilder $container,
)
);
}
if (!empty($config['controllers_by_class'])) {
$dynamic->addMethodCall(
'addRouteEnhancer',
array(
new Reference($this->getAlias() . '.enhancer.controllers_by_class'),
50
)
);
}
if (!empty($config['templates_by_class'])) {
$dynamic->addMethodCall(
'addRouteEnhancer',
array(
new Reference($this->getAlias() . '.enhancer.templates_by_class'),
40
)
);

/*
* The CoreBundle prepends the controller from ContentBundle if the
* ContentBundle is present in the project.
* If you are sure you do not need a generic controller, set the field
* to false to disable this check explicitly. But you would need
* something else like the default_controller to set the controller,
* as no controller will be set here.
*/
if (null === $config['generic_controller']) {
throw new InvalidConfigurationException('If you want to configure templates_by_class, you need to configure the generic_controller option.');
}
$dynamic->addMethodCall(
'addRouteEnhancer',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here we always add the template and controller enhancers, as the new, metadata aware, FieldByClass enhancer asks the factory directly for metadata. We do not know at this stage if the enhancers will be needed or not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we not let the compiler pass for the metadata add the enhancers as needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to add the enhancers for the AnnotationDriver to work, as it is lazy. The overhead with the ConfigurationDriver however is just a key check in an associative array and it will be possible to disable annotations.

Would it make sense to have a single MetadataEnhancer class instead of instantiating a FieldByClass enhancer for each case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single MetadataEnhancer: i would say so, as the metadata thing does not need to be super extensible. it should probably run first of the built in enhancer (it will be more specific rules than global rules).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for registering the enhancers, why not check if either we have configuration or have the annotations active and add if at least one of the two is true? that would be the smallest possible change in behaviour.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we not just register a single MetadataEnhancer in a compiler pass if any metadata driver classes are used? I guess by default we would have a chain driver with the proposed DIConfigDriver in first place, followed by AnnotationsDriver, so correspondingly the metadata enhancer would, by default, be registered and would be the only enhancer registered here.

array(
new Reference($this->getAlias() . '.enhancer.controllers_by_class'),
50
)
);

$dynamic->addMethodCall(
'addRouteEnhancer',
array(
new Reference($this->getAlias() . '.enhancer.templates_by_class'),
40
)
);

if (is_string($config['generic_controller'])) {
// if the content class defines the template, we also need to make sure we use the generic controller for those routes
$controllerForTemplates = array();
foreach ($config['templates_by_class'] as $key => $value) {
$controllerForTemplates[$key] = $config['generic_controller'];
}

$definition = $container->getDefinition($this->getAlias() . '.enhancer.controller_for_templates_by_class');
$definition->replaceArgument(2, $controllerForTemplates);

$dynamic->addMethodCall(
'addRouteEnhancer',
array(
new Reference($this->getAlias() . '.enhancer.controller_for_templates_by_class'),
30
)
);
}
}
if (!empty($config['generic_controller']) && $config['generic_controller'] !== $defaultController) {
$dynamic->addMethodCall(
'addRouteEnhancer',
84 changes: 84 additions & 0 deletions Enhancer/FieldByClassEnhancer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace Symfony\Cmf\Bundle\RoutingBundle\Enhancer;

use Symfony\Component\HttpFoundation\Request;
use Metadata\MetadataFactoryInterface;
use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;

/**
* This enhancer performs the same role as its counterpart
* in the Routing component, but it uses the Metadata factory.
*
* @author Daniel Leech <daniel@dantleech.com>
*/
class FieldByClassEnhancer implements RouteEnhancerInterface
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is a new implementation which uses the Metadata factory.

{
/**
* @var string field for the className class
*/
protected $classField;

/**
* @var string field to write hashmap lookup result into
*/
protected $targetField;

/**
* @var string field to write hashmap lookup result into
*/
protected $metaField;

/**
* @var Metadata\MetadataFactoryInterface
*/
protected $metadataFactory;

/**
* @param string $className the field name of the class
* @param string $targetField the field name to set from the map
* @param array $map the map of class names to field values
*/
public function __construct(
$classField,
$targetField,
$metaField,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targetField = field in $defaults, metaField = field in the Metadata class to get the value from .. does it make sense to specify them individually?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, should the metadata not all be evaluated when the container is built? i would have expected that this metadata stuff is never used at runtime - thats potentially very expensive.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the metadata should be "warmed up" like what happens in Doctrine. So there would be no overhead here, in production, for driver implementations which "know" about all of their mapped documents and are primed with a cache. The annotations would stil be evaluated lazily but would use a cached driver.

MetadataFactoryInterface $metadataFactory
)
{
$this->classField = $classField;
$this->targetField = $targetField;
$this->metaField = $metaField;
$this->metadataFactory = $metadataFactory;
}

/**
* If the class name is mapped
*
* {@inheritDoc}
*/
public function enhance(array $defaults, Request $request)
{
if (isset($defaults[$this->targetField])) {
return $defaults;
}

// return if the field containg the class name has not been set
if (! isset($defaults[$this->classField])) {
return $defaults;
}

$className = get_class($defaults[$this->classField]);

$meta = $this->metadataFactory->getMetadataForClass($className);

if (null !== $meta) {
$meta = $meta->getOutsideClassMetadata();
if (null !== $meta->{$this->metaField}) {
$defaults[$this->targetField] = $meta->{$this->metaField};
}
}

return $defaults;
}
}
11 changes: 11 additions & 0 deletions Metadata/Annotations/Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Symfony\Cmf\Bundle\RoutingBundle\Metadata\Annotations;

/**
* @Annotation
*/
class Controller
{
public $controller;
}
11 changes: 11 additions & 0 deletions Metadata/Annotations/Template.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Symfony\Cmf\Bundle\RoutingBundle\Metadata\Annotations;

/**
* @Annotation
*/
class Template
{
public $resource;
}
11 changes: 11 additions & 0 deletions Metadata/ClassMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Symfony\Cmf\Bundle\RoutingBundle\Metadata;

use Metadata\ClassMetadata as BaseClassMetadata;

class ClassMetadata extends BaseClassMetadata
{
public $template;
public $controller;
}
23 changes: 23 additions & 0 deletions Metadata/Driver/AbstractDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Symfony\Cmf\Bundle\RoutingBundle\Metadata\Driver;

use Metadata\Driver\DriverInterface;
use Symfony\Cmf\Bundle\RoutingBundle\Metadata\ClassMetadata;

abstract class AbstractDriver implements DriverInterface
{
public function validateMetadata(ClassMetadata $meta)
{
if (
null !== $meta->template &&
null == $meta->controller
) {
throw new \InvalidArgumentException(sprintf(
'Template specified for class "%s" but no controller specified.' .PHP_EOL.
'You must either explicitly map a controller to the class or define'.PHP_EOL.
'a "generic_controller" in the main configuration.'
, $meta->name));
}
}
}
56 changes: 56 additions & 0 deletions Metadata/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Symfony\Cmf\Bundle\RoutingBundle\Metadata\Driver;

use Symfony\Cmf\Bundle\RoutingBundle\Metadata\ClassMetadata;
use Doctrine\Common\Annotations\Reader;

class AnnotationDriver extends AbstractDriver
{
protected $reader;
protected $genericController;

/**
* @param AnnotationReader $reader
*/
public function __construct(Reader $reader)
{
$this->reader = $reader;
}

public function setGenericController($genericController)
{
$this->genericController = $genericController;
}

public function loadMetadataForClass(\ReflectionClass $class)
{
$templateAnnotation = $this->reader->getClassAnnotation(
$class,
'Symfony\Cmf\Bundle\RoutingBundle\Metadata\Annotations\Template'
);
$controllerAnnotation = $this->reader->getClassAnnotation(
$class,
'Symfony\Cmf\Bundle\RoutingBundle\Metadata\Annotations\Controller'
);


$meta = new ClassMetadata($class->name);

if (null !== $templateAnnotation) {
$meta->template = $templateAnnotation->resource;
}

if (null !== $controllerAnnotation) {
$meta->controller = $controllerAnnotation->controller;
}

if (null === $meta->controller) {
$meta->controller = $this->genericController;
}

$this->validateMetadata($meta);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AnnotationDriver validates lazily


return $meta;
}
}
46 changes: 46 additions & 0 deletions Metadata/Driver/ConfigurationDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Symfony\Cmf\Bundle\RoutingBundle\Metadata\Driver;

use Symfony\Cmf\Bundle\RoutingBundle\Metadata\ClassMetadata;

/**
* Driver which operates from explicitly defined mappings
*
* @author Daniel Leech <daniel@dantleech.com>
*/
class ConfigurationDriver extends AbstractDriver
{
protected $reader;
protected $metadata = array();

/**
* Eagerly loads the class metadata
*/
public function registerMapping($classFqn, $mapping)
{
$meta = new ClassMetadata($classFqn);

if (isset($mapping['template'])) {
$meta->template = $mapping['template'];
}

if (isset($mapping['controller'])) {
$meta->controller = $mapping['controller'];
}

$this->validateMetadata($meta);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigDriver is eager (validating when the mapping is registered).


$this->metadata[$classFqn] = $meta;
}

public function loadMetadataForClass(\ReflectionClass $class)
{
if (!isset($this->metadata[$class->name])) {
return null;
}

return $this->metadata[$class->name];
}
}

46 changes: 46 additions & 0 deletions Resources/config/metadata.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<!-- Factory -->
<service
id="cmf_routing.metadata.factory"
class="Metadata\MetadataFactory"
>
<argument
type="service"
id="cmf_routing.metadata.driver.chain"
/>
</service>

<!-- Chain Driver !-->
<service
id="cmf_routing.metadata.driver.chain"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer using cmf_routing.metadata.driver here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I think cmf_routing.metadata.driver should be an alias to whatever the driver actually is. So we should still have this definition, e.g. in symfony:

<service id="twig.loader" alias="twig.loader.filesystem" />

class="Metadata\Driver\DriverChain"
>
<argument type="collection">
<argument type="service" id="cmf_routing.metadata.driver.configuration"/>
<argument type="service" id="cmf_routing.metadata.driver.annotation"/>
</argument>
</service>

<!-- Annotations Driver -->
<service
id="cmf_routing.metadata.driver.annotation"
class="Symfony\Cmf\Bundle\RoutingBundle\Metadata\Driver\AnnotationDriver"
>
<argument type="service" id="annotation_reader"/>
<argument type="collection"/>
</service>

<!-- Annotations Driver -->
<service
id="cmf_routing.metadata.driver.configuration"
class="Symfony\Cmf\Bundle\RoutingBundle\Metadata\Driver\ConfigurationDriver"
>
<argument type="collection"/>
</service>
</services>
</container>
11 changes: 7 additions & 4 deletions Resources/config/routing-dynamic.xml
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
<parameter key="cmf_routing.enhancer.default_controller.class">Symfony\Cmf\Component\Routing\Enhancer\FieldPresenceEnhancer</parameter>
<parameter key="cmf_routing.enhancer.explicit_template.class">Symfony\Cmf\Component\Routing\Enhancer\FieldPresenceEnhancer</parameter>
<parameter key="cmf_routing.enhancer.controllers_by_type.class">Symfony\Cmf\Component\Routing\Enhancer\FieldMapEnhancer</parameter>
<parameter key="cmf_routing.enhancer.field_by_class.class">Symfony\Cmf\Component\Routing\Enhancer\FieldByClassEnhancer</parameter>
<parameter key="cmf_routing.enhancer.field_by_class.class">Symfony\Cmf\Bundle\RoutingBundle\Enhancer\FieldByClassEnhancer</parameter>
<parameter key="cmf_routing.redirect_controller.class">Symfony\Cmf\Bundle\RoutingBundle\Controller\RedirectController</parameter>
</parameters>

@@ -46,19 +46,22 @@
<service id="cmf_routing.enhancer.controllers_by_class" class="%cmf_routing.enhancer.field_by_class.class%" public="false">
<argument>_content</argument>
<argument>_controller</argument>
<argument>%cmf_routing.controllers_by_class%</argument>
<argument>controller</argument>
<argument type="service" id="cmf_routing.metadata.factory"/>
</service>

<service id="cmf_routing.enhancer.controller_for_templates_by_class" class="%cmf_routing.enhancer.field_by_class.class%" public="false">
<argument>_content</argument>
<argument>_controller</argument>
<argument type="collection" />
<argument>controller</argument>
<argument type="service" id="cmf_routing.metadata.factory"/>
</service>

<service id="cmf_routing.enhancer.templates_by_class" class="%cmf_routing.enhancer.field_by_class.class%" public="false">
<argument>_content</argument>
<argument>_template</argument>
<argument>%cmf_routing.templates_by_class%</argument>
<argument>template</argument>
<argument type="service" id="cmf_routing.metadata.factory"/>
</service>

<service id="cmf_routing.dynamic_router" class="%cmf_routing.dynamic_router.class%">
71 changes: 71 additions & 0 deletions Tests/Functional/Metadata/Driver/AnnotationDriverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

/*
* This file is part of the Symfony CMF package.
*
* (c) 2011-2013 Symfony CMF
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/


namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Functional\Metadata\Driver;

use Symfony\Component\HttpFoundation\RedirectResponse;

use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\Route;
use Symfony\Cmf\Bundle\RoutingBundle\Doctrine\Phpcr\RedirectRoute;
use Symfony\Cmf\Bundle\RoutingBundle\Controller\RedirectController;
use Symfony\Cmf\Bundle\RoutingBundle\Tests\Functional\BaseTestCase;

class AnnotationDriverTest extends BaseTestCase
{
public function setUp()
{
parent::setUp();

$this->chainDriver = $this->getContainer()->get('cmf_routing.metadata.factory');
$this->annotDriver = $this->getContainer()->get('cmf_routing.metadata.driver.annotation');
}

public function testDriverTemplateAndContent()
{
$meta = $this->chainDriver->getMetadataForClass(
'Symfony\Cmf\Bundle\RoutingBundle\Tests\Resources\Document\AnnotatedContent'
);

$this->assertNotNull($meta);

$meta = $meta->getOutsideClassMetadata();

$this->assertEquals('TestBundle:Content:index.html.twig', $meta->template);
$this->assertEquals('ThisIsAController', $meta->controller);
}

public function testDriverTemplateOnlyWithGenericController()
{
$meta = $this->chainDriver->getMetadataForClass(
'Symfony\Cmf\Bundle\RoutingBundle\Tests\Resources\Document\AnnotatedContentTemplateOnly'
);

$this->assertNotNull($meta);

$meta = $meta->getOutsideClassMetadata();

$this->assertEquals('TestBundle:Content:index.html.twig', $meta->template);
$this->assertEquals('cmf_content.controller:indexAction', $meta->controller);
}

/**
* @expectedException InvalidArgumentException
* @expectedExceptionMessage but no controller specified
*/
public function testDriverTemplateOnlyNoController()
{
$this->annotDriver->setGenericController(null);
$meta = $this->chainDriver->getMetadataForClass(
'Symfony\Cmf\Bundle\RoutingBundle\Tests\Resources\Document\AnnotatedContentTemplateOnly'
);
}
}
46 changes: 46 additions & 0 deletions Tests/Resources/Document/AnnotatedContent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/*
* This file is part of the Symfony CMF package.
*
* (c) 2011-2013 Symfony CMF
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/


namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Resources\Document;


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicated empty lines

use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCRODM;
use Symfony\Cmf\Bundle\RoutingBundle\Metadata\Annotations as CmfRouting;

/**
* @PHPCRODM\Document(referenceable=true)
*
* @CmfRouting\Template("TestBundle:Content:index.html.twig")
* @CmfRouting\Controller("ThisIsAController")
*/
class AnnotatedContent
{
/**
* @PHPCRODM\Id
*/
public $path;

/**
* PHPCRODM\String()
*/
public $title;

public function setId($path)
{
$this->path = $path;
}

public function setTitle($title)
{
$this->title = $title;
}
}
45 changes: 45 additions & 0 deletions Tests/Resources/Document/AnnotatedContentTemplateOnly.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Symfony CMF package.
*
* (c) 2011-2013 Symfony CMF
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/


namespace Symfony\Cmf\Bundle\RoutingBundle\Tests\Resources\Document;


use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCRODM;
use Symfony\Cmf\Bundle\RoutingBundle\Metadata\Annotations as CmfRouting;

/**
* @PHPCRODM\Document(referenceable=true)
*
* @CmfRouting\Template("TestBundle:Content:index.html.twig")
*/
class AnnotatedContentTemplateOnly
{
/**
* @PHPCRODM\Id
*/
public $path;

/**
* PHPCRODM\String()
*/
public $title;

public function setId($path)
{
$this->path = $path;
}

public function setTitle($title)
{
$this->title = $title;
}
}
43 changes: 43 additions & 0 deletions Tests/Unit/Metadata/Driver/ConfigurationDriverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Unit\Metadata\Driver;

use Symfony\Cmf\Bundle\RoutingBundle\Metadata\Driver\ConfigurationDriver;

class ConfigurationDriverTest extends \PHPUnit_Framework_TestCase
{
protected $driver;

public function setUp()
{
$this->driver = new ConfigurationDriver;
}

public function testDriver()
{
$this->driver->registerMapping('stdClass', array(
'template' => 'foobar.html.twig',
'controller' => 'FoobarController',
));

$refl = new \ReflectionClass('stdClass');
$meta = $this->driver->loadMetadataForClass($refl);

$this->assertEquals('foobar.html.twig', $meta->template);
$this->assertEquals('FoobarController', $meta->controller);
}

/**
* @expectedException InvalidArgumentException
* @expectedExceptionMessage but no controller specified
*/
public function testDriverMissingController()
{
$this->driver->registerMapping('stdClass', array(
'template' => 'foobar.html.twig',
));

$refl = new \ReflectionClass('stdClass');
$meta = $this->driver->loadMetadataForClass($refl);
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,8 @@
"require": {
"php": ">=5.3.3",
"symfony-cmf/routing": "~1.2.0",
"symfony/framework-bundle": "~2.2"
"symfony/framework-bundle": "~2.2",
"jms/metadata": "1.5.0"
},
"require-dev": {
"symfony-cmf/core-bundle": "1.0.*",
4 changes: 4 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -19,6 +19,10 @@
<testsuite name="orm">
<directory>./Tests/Functional/Doctrine/Orm</directory>
</testsuite>

<testsuite name="metadata">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wouterj - I added this, is it worth it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherwise the database is purged and reloaded on each test

<directory>./Tests/Functional/Metadata</directory>
</testsuite>
</testsuites>

<filter>