Skip to content

[PropertyAccess] Allow custom methods on property accesses #18016

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

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Fixed the metadata caching mess
  • Loading branch information
lrlopez committed Jul 3, 2016
commit 94e6157440c88c8ba49f462dfc2019cf0b66c46f
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,8 @@ private function addPropertyAccessSection(ArrayNodeDefinition $rootNode)
->addDefaultsIfNotSet()
->info('Property access configuration')
->children()
->scalarNode('cache')->end()
->booleanNode('enable_annotations')->defaultFalse()->end()
->booleanNode('magic_call')->defaultFalse()->end()
->booleanNode('throw_exception_on_invalid_index')->defaultFalse()->end()
->end()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -924,17 +924,14 @@ private function registerAnnotationsConfiguration(array $config, ContainerBuilde
*/
Copy link
Member

Choose a reason for hiding this comment

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

no need for this docblock imo

private function registerPropertyAccessConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
$loader->load('property_access.xml');

$container
->getDefinition('property_accessor')
->replaceArgument(0, $config['magic_call'])
->replaceArgument(1, $config['throw_exception_on_invalid_index'])
;

if (!$this->isConfigEnabled($container, $config)) {
return;
}

$loader->load('property_access.xml');
$chainLoader = $container->getDefinition('property_access.mapping.chain_loader');

$serializerLoaders = array();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
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">

<parameters>
<parameter key="property_access.mapping.cache.prefix" />
</parameters>

<services>

<!-- Loader -->
Expand All @@ -12,16 +16,19 @@
</service>

<!-- Class Metadata Factory -->
<service id="property_access.mapping.class_metadata_factory" class="Symfony\Component\PropertyAccess\Mapping\Factory\ClassMetadataFactory" public="false">
<service id="property_access.mapping.class_metadata_factory" class="Symfony\Component\PropertyAccess\Mapping\Factory\LazyLoadingMetadataFactory" public="false">
<argument type="service" id="property_access.mapping.chain_loader" />
<argument>null</argument>
</service>

<!-- Cache -->
<service id="property_access.mapping.cache.apc" class="Doctrine\Common\Cache\ApcCache" public="false">
<call method="setNamespace">
<argument>%property_access.mapping.cache.prefix%</argument>
</call>
<service id="property_access.mapping.cache.doctrine.apc" class="Symfony\Component\PropertyAccess\Mapping\Cache\DoctrineCache" public="false">
<argument type="service">
<service class="Doctrine\Common\Cache\ApcCache">
<call method="setNamespace">
<argument>%property_access.mapping.cache.prefix%</argument>
</call>
</service>
</argument>
</service>

<service id="property_accessor" class="Symfony\Component\PropertyAccess\PropertyAccessor" >
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@

<xsd:complexType name="property_access">
<xsd:attribute name="magic-call" type="xsd:boolean" />
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="throw-exception-on-invalid-index" type="xsd:boolean" />
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
</xsd:complexType>

<xsd:complexType name="serializer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@
'debug' => true,
'file_cache_dir' => '%kernel.cache_dir%/annotations',
),
'property_access' => array(
'magic_call' => false,
'throw_exception_on_invalid_index' => false,
'enable_annotations' => true,
'cache' => 'property_access.mapping.cache.doctrine.apc',
),
'serializer' => array(
'enabled' => true,
'enable_annotations' => true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@
<framework:validation enabled="true" cache="validator.mapping.cache.doctrine.apc" />
<framework:annotations cache="file" debug="true" file-cache-dir="%kernel.cache_dir%/annotations" />
<framework:serializer enabled="true" enable-annotations="true" name-converter="serializer.name_converter.camel_case_to_snake_case" />
<framework:property-access cache="property_access.mapping.cache.doctrine.apc" enable-annotations="true" magic-call="false" throw-exception-on-invalid-index="false" />
Copy link
Member

Choose a reason for hiding this comment

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

Should be removed and use the new cache component instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right.

</framework:config>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ framework:
enabled: true
enable_annotations: true
name_converter: serializer.name_converter.camel_case_to_snake_case
property_access:
enable_annotations: true
magic_call: false
throw_exception_on_invalid_index: false
cache: property_access.mapping.cache.doctrine.apc
ide: file%%link%%format
request:
formats:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\PropertyAccess\Exception;

/**
* @author Luis Ramón López <lrlopez@gmail.com>
*/
class NoSuchMetadataException extends AccessException
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\PropertyAccess\Mapping\Cache;

use Symfony\Component\PropertyAccess\Mapping\ClassMetadata;

/**
* Persists ClassMetadata instances in a cache.
*
* @author Luis Ramón López <lrlopez@gmail.com>
*/
interface CacheInterface
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a need for another CacheInterface? Why not just stick to PSR-6 without the need for another layer of indirection?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Metadata caching is still WIP. I just migrated the Validator component cache into PropertyAccess. As you say, the next logical step is integrate with the new Cache component

{
/**
* Returns whether metadata for the given class exists in the cache.
*
* @param string $class
*/
public function has($class);

/**
* Returns the metadata for the given class from the cache.
*
* @param string $class Class Name
*
* @return ClassMetadata|false A ClassMetadata instance or false on miss
*/
public function read($class);

/**
* Stores a class metadata in the cache.
*
* @param ClassMetadata $metadata A Class Metadata
*/
public function write(ClassMetadata $metadata);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\PropertyAccess\Mapping\Cache;

use Doctrine\Common\Cache\Cache;
use Symfony\Component\PropertyAccess\Mapping\ClassMetadata;

/**
* Adapts a Doctrine cache to a CacheInterface.
*
* @author Luis Ramón López <lrlopez@gmail.com>
*/
final class DoctrineCache implements CacheInterface
Copy link
Contributor

Choose a reason for hiding this comment

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

The new Symfony Cache component (a PSR-6 implementation) has a Doctrine Cache adapter.

{
private $cache;

/**
* Creates a new Doctrine cache.
*
* @param Cache $cache The cache to adapt
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}

/**
* Sets the cache to adapt.
*
* @param Cache $cache The cache to adapt
*/
public function setCache(Cache $cache)
{
$this->cache = $cache;
}

/**
* {@inheritdoc}
*/
public function has($class)
{
return $this->cache->contains($class);
}

/**
* {@inheritdoc}
*/
public function read($class)
{
return $this->cache->fetch($class);
}

/**
* {@inheritdoc}
*/
public function write(ClassMetadata $metadata)
{
$this->cache->save($metadata->getName(), $metadata);
}
}
78 changes: 78 additions & 0 deletions src/Symfony/Component/PropertyAccess/Mapping/Cache/Psr6Cache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\PropertyAccess\Mapping\Cache;

use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\PropertyAccess\Mapping\ClassMetadata;

/**
* PSR-6 adapter.
*
* @author Luis Ramón López <lrlopez@gmail.com>
*/
class Psr6Cache implements CacheInterface
{
/**
* @var CacheItemPoolInterface
*/
private $cacheItemPool;

public function __construct(CacheItemPoolInterface $cacheItemPool)
{
$this->cacheItemPool = $cacheItemPool;
}

/**
* {@inheritdoc}
*/
public function has($class)
{
return $this->cacheItemPool->hasItem($this->escapeClassName($class));
}

/**
* {@inheritdoc}
*/
public function read($class)
{
$item = $this->cacheItemPool->getItem($this->escapeClassName($class));

if (!$item->isHit()) {
return false;
}

return $item->get();
}

/**
* {@inheritdoc}
*/
public function write(ClassMetadata $metadata)
{
$item = $this->cacheItemPool->getItem($this->escapeClassName($metadata->getName()));
$item->set($metadata);

$this->cacheItemPool->save($item);
}

/**
* Replaces backslashes by dots in a class name.
*
* @param string $class
*
* @return string
*/
private function escapeClassName($class)
{
return str_replace('\\', '.', $class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\PropertyAccess\Mapping\Factory;

/**
* Metadata factory that does not store metadata.
*
* This implementation is useful if you want to validate values against
* constraints only and you don't need to add constraints to classes and
* properties.
*
* @author Luis Ramón López <lrlopez@gmail.com>
*/
class BlackHoleMetadataFactory implements MetadataFactoryInterface
{
/**
* {@inheritdoc}
*/
public function getMetadataFor($value)
{
throw new \LogicException('This class does not support metadata.');
}

/**
* {@inheritdoc}
*/
public function hasMetadataFor($value)
{
return false;
}
}
Loading