diff --git a/spec/Knp/DictionaryBundle/DataCollector/DictionaryDataCollectorSpec.php b/spec/Knp/DictionaryBundle/DataCollector/DictionaryDataCollectorSpec.php index c2e0b454..2365b4b5 100644 --- a/spec/Knp/DictionaryBundle/DataCollector/DictionaryDataCollectorSpec.php +++ b/spec/Knp/DictionaryBundle/DataCollector/DictionaryDataCollectorSpec.php @@ -2,29 +2,43 @@ namespace spec\Knp\DictionaryBundle\DataCollector; -use Knp\DictionaryBundle\Dictionary\DictionaryRegistry; use PhpSpec\ObjectBehavior; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; class DictionaryDataCollectorSpec extends ObjectBehavior { - function let(DictionaryRegistry $registry) - { - $this->beConstructedWith($registry); - } - function it_is_initializable() { $this->shouldHaveType('Knp\DictionaryBundle\DataCollector\DictionaryDataCollector'); } - function it_collects_data_from_dictionaries(Request $request, Response $response, $registry) + function it_collects_data_from_dictionaries() { - $registry->all()->willReturn(['foo', 'bar', 'baz']); - $this->collect($request, $response); + $this->addDictionary('foo', ['key1', 'key2'], ['value1', 'value2']); + $this->addDictionary('foo', ['key1', 'key2'], ['value1', 'value2']); + $this->addDictionary('bar', ['keyA', 'keyB'], ['valueA', 'valueB']); - $this->getDictionaries()->shouldReturn(['foo', 'bar', 'baz']); + $this->getDictionaries()->shouldReturn([ + 'foo' => [ + [ + 'key' => 'key1', + 'value' => 'value1', + ], + [ + 'key' => 'key2', + 'value' => 'value2', + ], + ], + 'bar' => [ + [ + 'key' => 'keyA', + 'value' => 'valueA', + ], + [ + 'key' => 'keyB', + 'value' => 'valueB', + ], + ], + ]); } function it_has_a_name() diff --git a/spec/Knp/DictionaryBundle/Dictionary/CallableDictionarySpec.php b/spec/Knp/DictionaryBundle/Dictionary/CallableDictionarySpec.php index 66db6ae9..c5c9a403 100644 --- a/spec/Knp/DictionaryBundle/Dictionary/CallableDictionarySpec.php +++ b/spec/Knp/DictionaryBundle/Dictionary/CallableDictionarySpec.php @@ -2,6 +2,7 @@ namespace spec\Knp\DictionaryBundle\Dictionary; +use Knp\DictionaryBundle\Dictionary; use PhpSpec\ObjectBehavior; class CallableDictionarySpec extends ObjectBehavior @@ -46,16 +47,6 @@ function it_supports_some_array_access_functions() expect(isset($dictionary['foo']))->toBe(false); } - function it_can_be_serialized_and_unserialized() - { - $dictionary = $this->getWrappedObject(); - - $dictionary = unserialize(serialize($dictionary)); - - expect($dictionary['foo'])->toBe(0); - expect(isset($dictionary['foo']))->toBe(true); - } - function it_provides_a_set_of_values() { $this->getValues()->shouldReturn([ diff --git a/spec/Knp/DictionaryBundle/Dictionary/TraceableDictionarySpec.php b/spec/Knp/DictionaryBundle/Dictionary/TraceableDictionarySpec.php new file mode 100644 index 00000000..fb1d61a9 --- /dev/null +++ b/spec/Knp/DictionaryBundle/Dictionary/TraceableDictionarySpec.php @@ -0,0 +1,84 @@ + 'bar', + 'baz' => null, + ]); + + $this->beConstructedWith($dictionary, $collector); + } + + function it_is_initializable() + { + $this->shouldHaveType('Knp\DictionaryBundle\Dictionary\TraceableDictionary'); + } + + function it_is_a_dictionary() + { + $this->shouldImplement('Knp\DictionaryBundle\Dictionary'); + } + + function it_has_a_name() + { + $this->getName()->shouldReturn('name'); + } + + function it_traces_keys($collector) + { + $collector->addDictionary('name', ['foo', 'baz'], ['bar', null])->shouldbeCalled(); + + $this->getKeys()->shouldReturn(['foo', 'baz']); + } + + function it_traces_values($collector) + { + $collector->addDictionary('name', ['foo', 'baz'], ['bar', null])->shouldbeCalled(); + + $this->getValues()->shouldReturn(['foo' => 'bar', 'baz' => null]); + } + + function it_traces_values_get($collector) + { + $collector->addDictionary('name', ['foo', 'baz'], ['bar', null])->shouldbeCalled(); + + $this['foo']->shouldReturn('bar'); + } + + function it_traces_value_set($collector) + { + $collector->addDictionary('name', ['foo', 'baz', 'yo'], ['bar', null, 'lo'])->shouldbeCalled(); + + $this['yo'] = 'lo'; + } + + function it_traces_value_unset($collector) + { + $collector->addDictionary('name', ['baz'], [null])->shouldbeCalled(); + + unset($this['foo']); + } + + function it_traces_key_exists($collector) + { + $collector->addDictionary('name', ['foo', 'baz'], ['bar', null])->shouldbeCalled(); + + expect(isset($this['baz']))->toBe(true); + } + + function it_trace_iteration($collector) + { + $collector->addDictionary('name', ['foo', 'baz'], ['bar', null])->shouldbeCalled(); + + expect(iterator_to_array($this->getIterator()->getWrappedObject()))->toBe(['foo' => 'bar', 'baz' => null]); + } +} diff --git a/spec/Knp/DictionaryBundle/KnpDictionaryBundleSpec.php b/spec/Knp/DictionaryBundle/KnpDictionaryBundleSpec.php index 57de71d8..c1d2d04a 100644 --- a/spec/Knp/DictionaryBundle/KnpDictionaryBundleSpec.php +++ b/spec/Knp/DictionaryBundle/KnpDictionaryBundleSpec.php @@ -30,6 +30,11 @@ function it_registers_compiler_passes(ContainerBuilder $container) ->shouldBeCalled() ; + $container + ->addCompilerPass(Argument::type('Knp\DictionaryBundle\DependencyInjection\Compiler\DictionaryTracePass')) + ->shouldBeCalled() + ; + $this->build($container); } } diff --git a/src/Knp/DictionaryBundle/DataCollector/DictionaryDataCollector.php b/src/Knp/DictionaryBundle/DataCollector/DictionaryDataCollector.php index bfc2c7ff..7d140cf0 100644 --- a/src/Knp/DictionaryBundle/DataCollector/DictionaryDataCollector.php +++ b/src/Knp/DictionaryBundle/DataCollector/DictionaryDataCollector.php @@ -2,7 +2,6 @@ namespace Knp\DictionaryBundle\DataCollector; -use Knp\DictionaryBundle\Dictionary\DictionaryRegistry; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollector; @@ -10,28 +9,21 @@ class DictionaryDataCollector extends DataCollector { /** - * @var DictionaryRegistry - */ - private $registry; - - /** - * @param DictionaryRegistry $registry + * {@inheritdoc} */ - public function __construct(DictionaryRegistry $registry) + public function collect(Request $request, Response $response, \Exception $exception = null) { - $this->registry = $registry; } - /** - * {@inheritdoc} - */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function addDictionary($name, array $keys, array $values) { - $this->data = $this->registry->all(); + $this->data[$name] = array_map(function ($key, $value) { + return ['key' => $key, 'value' => $value]; + }, $keys, $values); } /** - * @return Dictionary[] + * @return array */ public function getDictionaries() { diff --git a/src/Knp/DictionaryBundle/DependencyInjection/Compiler/DictionaryTracePass.php b/src/Knp/DictionaryBundle/DependencyInjection/Compiler/DictionaryTracePass.php new file mode 100644 index 00000000..dbb7c222 --- /dev/null +++ b/src/Knp/DictionaryBundle/DependencyInjection/Compiler/DictionaryTracePass.php @@ -0,0 +1,35 @@ +has('knp_dictionary.data_collector.dictionary_data_collector')) { + return; + } + + $collector = new Reference('knp_dictionary.data_collector.dictionary_data_collector'); + $services = $container->findTaggedServiceIds(DictionaryRegistrationPass::TAG_DICTIONARY); + + foreach ($services as $id => $tags) { + $serviceId = sprintf('%s.%s.traceable', $id, md5($id)); + + $dictionary = new Reference(sprintf('%s.inner', $serviceId)); + + $traceable = new Definition('Knp\DictionaryBundle\Dictionary\TraceableDictionary', [$dictionary, $collector]); + $traceable->setDecoratedService($id); + + $container->setDefinition($serviceId, $traceable); + } + } +} diff --git a/src/Knp/DictionaryBundle/Dictionary.php b/src/Knp/DictionaryBundle/Dictionary.php index c473c5f8..45ad9ec2 100644 --- a/src/Knp/DictionaryBundle/Dictionary.php +++ b/src/Knp/DictionaryBundle/Dictionary.php @@ -2,7 +2,10 @@ namespace Knp\DictionaryBundle; -interface Dictionary extends \ArrayAccess, \IteratorAggregate, \Serializable +use ArrayAccess; +use IteratorAggregate; + +interface Dictionary extends ArrayAccess, IteratorAggregate { const VALUE = 'value'; const VALUE_AS_KEY = 'value_as_key'; diff --git a/src/Knp/DictionaryBundle/Dictionary/CallableDictionary.php b/src/Knp/DictionaryBundle/Dictionary/CallableDictionary.php index bad872a9..e176a164 100644 --- a/src/Knp/DictionaryBundle/Dictionary/CallableDictionary.php +++ b/src/Knp/DictionaryBundle/Dictionary/CallableDictionary.php @@ -2,9 +2,9 @@ namespace Knp\DictionaryBundle\Dictionary; -use Knp\DictionaryBundle\Dictionary as DictionaryInterface; +use Knp\DictionaryBundle\Dictionary; -class CallableDictionary implements DictionaryInterface +class CallableDictionary implements Dictionary { /** * @var string @@ -111,30 +111,6 @@ public function getIterator() return new \ArrayIterator($this->values); } - /** - * {@inheritdoc} - */ - public function serialize() - { - $this->hydrate(); - - return serialize([ - 'name' => $this->name, - 'values' => $this->values, - ]); - } - - /** - * {@inheritdoc} - */ - public function unserialize($serialized) - { - $data = unserialize($serialized); - - $this->name = $data['name']; - $this->values = $data['values']; - } - /** * Hydrate values from callable. */ diff --git a/src/Knp/DictionaryBundle/Dictionary/SimpleDictionary.php b/src/Knp/DictionaryBundle/Dictionary/SimpleDictionary.php index f606f4b9..69117bb2 100644 --- a/src/Knp/DictionaryBundle/Dictionary/SimpleDictionary.php +++ b/src/Knp/DictionaryBundle/Dictionary/SimpleDictionary.php @@ -91,26 +91,4 @@ public function getIterator() { return new \ArrayIterator($this->values); } - - /** - * {@inheritdoc} - */ - public function serialize() - { - return serialize([ - 'name' => $this->name, - 'values' => $this->values, - ]); - } - - /** - * {@inheritdoc} - */ - public function unserialize($serialized) - { - $data = unserialize($serialized); - - $this->name = $data['name']; - $this->values = $data['values']; - } } diff --git a/src/Knp/DictionaryBundle/Dictionary/TraceableDictionary.php b/src/Knp/DictionaryBundle/Dictionary/TraceableDictionary.php new file mode 100644 index 00000000..55a1a337 --- /dev/null +++ b/src/Knp/DictionaryBundle/Dictionary/TraceableDictionary.php @@ -0,0 +1,117 @@ +dictionary = $dictionary; + $this->collector = $collector; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->dictionary->getName(); + } + + /** + * {@inheritdoc} + */ + public function getValues() + { + $this->trace(); + + return $this->dictionary->getValues(); + } + + /** + * {@inheritdoc} + */ + public function getKeys() + { + $this->trace(); + + return $this->dictionary->getKeys(); + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + $this->trace(); + + return $this->dictionary->offsetExists($offset); + } + + /** + * {@inheritdoc} + * + * @return mixed + */ + public function offsetGet($offset) + { + $this->trace(); + + return $this->dictionary->offsetGet($offset); + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->dictionary->offsetSet($offset, $value); + + $this->trace(); + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + $this->dictionary->offsetUnset($offset); + + $this->trace(); + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + $this->trace(); + + return $this->dictionary->getIterator(); + } + + /** + * Register this dictioanry as used. + */ + private function trace() + { + $this->collector->addDictionary( + $this->dictionary->getName(), + $this->dictionary->getKeys(), + array_values($this->dictionary->getValues()) + ); + } +} diff --git a/src/Knp/DictionaryBundle/KnpDictionaryBundle.php b/src/Knp/DictionaryBundle/KnpDictionaryBundle.php index 6ea04bee..fcc4f690 100644 --- a/src/Knp/DictionaryBundle/KnpDictionaryBundle.php +++ b/src/Knp/DictionaryBundle/KnpDictionaryBundle.php @@ -5,6 +5,7 @@ use Knp\DictionaryBundle\DependencyInjection\Compiler\DictionaryBuildingPass; use Knp\DictionaryBundle\DependencyInjection\Compiler\DictionaryFactoryBuildingPass; use Knp\DictionaryBundle\DependencyInjection\Compiler\DictionaryRegistrationPass; +use Knp\DictionaryBundle\DependencyInjection\Compiler\DictionaryTracePass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -16,7 +17,8 @@ class KnpDictionaryBundle extends Bundle public function build(ContainerBuilder $container) { $container->addCompilerPass(new DictionaryBuildingPass()); - $container->addCompilerPass(new DictionaryRegistrationPass()); $container->addCompilerPass(new DictionaryFactoryBuildingPass()); + $container->addCompilerPass(new DictionaryRegistrationPass()); + $container->addCompilerPass(new DictionaryTracePass()); } } diff --git a/src/Knp/DictionaryBundle/Resources/config/dictionary.xml b/src/Knp/DictionaryBundle/Resources/config/dictionary.xml index a64b1013..e48827f5 100644 --- a/src/Knp/DictionaryBundle/Resources/config/dictionary.xml +++ b/src/Knp/DictionaryBundle/Resources/config/dictionary.xml @@ -3,7 +3,6 @@ - diff --git a/src/Knp/DictionaryBundle/Resources/views/layout.html.twig b/src/Knp/DictionaryBundle/Resources/views/layout.html.twig index 9981d2ff..73f8e943 100644 --- a/src/Knp/DictionaryBundle/Resources/views/layout.html.twig +++ b/src/Knp/DictionaryBundle/Resources/views/layout.html.twig @@ -1,33 +1,42 @@ {% extends 'WebProfilerBundle:Profiler:layout.html.twig' %} {% block menu %} - - - Dictionary - -Dictionaries - - {{ collector.dictionaries|length }} + + + Dictionary + + Dictionaries + {% if collector.dictionaries is not empty %} + + {{ collector.dictionaries|length }} used + + {% endif %} {% endblock %} {% block panel %} -

Dictionaries

-{% for dictionary in collector.dictionaries %} -

{{ dictionary.name }}

+{% for name, dictionary in collector.dictionaries %} +

{{ name }}

- {% for key, value in dictionary %} + {% for item in dictionary %} - - + + {% endfor %}
Key Value
{{ key }}{{ value }}{{ item.key }}{{ item.value }}
+ {% if false == loop.last %} +
+ {% endif %} +{% else %} +
+

No dictionary used

+
{% endfor %} {% endblock %}