diff --git a/.travis.yml b/.travis.yml index f2b6297..4431675 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ php: - 7.1 - 7.0 - 5.6 - - 5.5 - hhvm env: @@ -16,6 +15,7 @@ env: matrix: - SYMFONY_VERSION=2.7.* - SYMFONY_VERSION=2.8.* + - SYMFONY_VERSION=3.1.* - SYMFONY_VERSION=3.2.* branches: @@ -26,7 +26,7 @@ branches: matrix: fast_finish: true include: - - php: 5.5 + - php: 5.6 env: COMPOSER_COMMAND="composer update --prefer-lowest --prefer-stable" COVERAGE=true TEST_COMMAND="php -dzend_extension=xdebug.so vendor/bin/phpunit --coverage-clover=coverage.xml" SYMFONY_VERSION=2.7.* cache: @@ -36,7 +36,6 @@ cache: before_install: - if [[ $TRAVIS_PHP_VERSION != 'hhvm' ]]; then phpenv config-rm xdebug.ini; fi; - pip install --user codecov - - composer self-update - composer require symfony/symfony:${SYMFONY_VERSION} --no-update install: diff --git a/Changelog.md b/Changelog.md index f4fe833..9721120 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,19 @@ The change log describes what is "Added", "Removed", "Changed" or "Fixed" betwee ## UNRELEASED +## 0.5.0 + +### Changed + +- Using cache/session-handler: ^0.2. **This will break all cached sessions** +- Using cache/taggable-cache: ^0.5 to support the latest versions of the adapters. + +## 0.4.4 + +### Fixed + +- Make sure RecordingPool does not change the type of pool. + ## 0.4.3 ### Fixed diff --git a/composer.json b/composer.json index eb71ba3..e867685 100644 --- a/composer.json +++ b/composer.json @@ -24,15 +24,15 @@ } ], "require": { - "php": "^5.5 || ^7.0", + "php": "^5.6 || ^7.0", "symfony/framework-bundle": "^2.7 || ^3.0", "cache/taggable-cache": "^0.5", "cache/session-handler": "^0.2" }, "require-dev": { - "phpunit/phpunit": "^5.1 || ^4.0", + "phpunit/phpunit": "^5.7.17", "symfony/symfony": "^2.7 || ^3.0", - "cache/psr-6-doctrine-bridge": "^2.0", + "cache/psr-6-doctrine-bridge": "^3.0", "cache/array-adapter": "^0.5", "nyholm/symfony-bundle-test": "^1.0.1", "matthiasnoback/symfony-dependency-injection-test": "^1.0" diff --git a/src/Cache/FixedTaggingCachePool.php b/src/Cache/FixedTaggingCachePool.php index 4ac11c9..8d3287f 100644 --- a/src/Cache/FixedTaggingCachePool.php +++ b/src/Cache/FixedTaggingCachePool.php @@ -11,21 +11,20 @@ namespace Cache\CacheBundle\Cache; -use Cache\Taggable\TaggableItemInterface; -use Cache\Taggable\TaggablePoolInterface; +use Cache\TagInterop\TaggableCacheItemInterface; +use Cache\TagInterop\TaggableCacheItemPoolInterface; use Psr\Cache\CacheItemInterface; -use Psr\Cache\CacheItemPoolInterface; +use Psr\Cache\InvalidArgumentException; /** - * This class is a decorator for a TaggablePoolInterface. It tags everything with predefined tags. - * Use this class with the DoctrineBridge. + * This class is a decorator for a TaggableCacheItemPoolInterface. It tags everything with predefined tags. * * @author Tobias Nyholm */ -class FixedTaggingCachePool implements CacheItemPoolInterface +class FixedTaggingCachePool implements TaggableCacheItemPoolInterface { /** - * @type CacheItemPoolInterface|TaggablePoolInterface + * @type TaggableCacheItemPoolInterface */ private $cache; @@ -35,10 +34,10 @@ class FixedTaggingCachePool implements CacheItemPoolInterface private $tags; /** - * @param TaggablePoolInterface $cache - * @param array $tags + * @param TaggableCacheItemPoolInterface $cache + * @param array $tags */ - public function __construct(TaggablePoolInterface $cache, array $tags) + public function __construct(TaggableCacheItemPoolInterface $cache, array $tags) { $this->cache = $cache; $this->tags = $tags; @@ -97,10 +96,12 @@ public function deleteItems(array $keys) */ public function save(CacheItemInterface $item) { - if ($item instanceof TaggableItemInterface) { - $this->addTags($item); + if (!$item instanceof TaggableCacheItemInterface) { + throw new InvalidArgumentException('Cache items are not transferable between pools. Item MUST implement TaggableCacheItemInterface.'); } + $item->setTags($this->tags); + return $this->cache->save($item); } @@ -109,26 +110,36 @@ public function save(CacheItemInterface $item) */ public function saveDeferred(CacheItemInterface $item) { - $this->addTags($item); + if (!$item instanceof TaggableCacheItemInterface) { + throw new InvalidArgumentException('Cache items are not transferable between pools. Item MUST implement TaggableCacheItemInterface.'); + } + + $item->setTags($this->tags); return $this->cache->saveDeferred($item); } /** - * @param TaggableItemInterface $item + * {@inheritdoc} */ - private function addTags(TaggableItemInterface $item) + public function commit() { - foreach ($this->tags as $tag) { - $item->addTag($tag); - } + return $this->cache->commit(); } /** * {@inheritdoc} */ - public function commit() + public function invalidateTag($tag) { - return $this->cache->commit(); + return $this->invalidateTag($tag); + } + + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) + { + return $this->cache - $this->invalidateTags($tags); } } diff --git a/src/Cache/Recording/CachePool.php b/src/Cache/Recording/CachePool.php index a4d0d6c..6be2208 100644 --- a/src/Cache/Recording/CachePool.php +++ b/src/Cache/Recording/CachePool.php @@ -11,7 +11,6 @@ namespace Cache\CacheBundle\Cache\Recording; -use Cache\Taggable\TaggablePoolInterface; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Log\LoggerInterface; @@ -21,18 +20,14 @@ * * @author Aaron Scherer * @author Tobias Nyholm + * @author Nicolas Grekas */ -class CachePool implements CacheItemPoolInterface, TaggablePoolInterface +class CachePool implements CacheItemPoolInterface { - /** - * @type array - */ - private $calls = []; - /** * @type CacheItemPoolInterface */ - private $cachePool; + protected $pool; /** * @type LoggerInterface @@ -50,202 +45,176 @@ class CachePool implements CacheItemPoolInterface, TaggablePoolInterface private $level = 'info'; /** - * LoggingCachePool constructor. - * - * @param CacheItemPoolInterface $cachePool + * @type array calls */ - public function __construct(CacheItemPoolInterface $cachePool) - { - $this->cachePool = $cachePool; - } + private $calls = []; /** - * Record a call. - * - * @param $call + * @param CacheItemPoolInterface $pool */ - protected function addCall($call) + public function __construct(CacheItemPoolInterface $pool) { - $this->calls[] = $call; - - $this->writeLog($call); + $this->pool = $pool; } /** - * @param string $name - * @param array $arguments - * - * @return object + * {@inheritdoc} */ - protected function timeCall($name, array $arguments = []) - { - $start = microtime(true); - $result = call_user_func_array([$this->cachePool, $name], $arguments); - $time = microtime(true) - $start; - - $object = (object) compact('name', 'arguments', 'start', 'time', 'result'); - - return $object; - } - public function getItem($key) { - $call = $this->timeCall(__FUNCTION__, [$key]); - $result = $call->result; - $call->isHit = $result->isHit(); - - // Display the result in a good way depending on the data type - if ($call->isHit) { - $call->result = $this->getValueRepresentation($result->get()); + $event = $this->start(__FUNCTION__, $key); + try { + $item = $this->pool->getItem($key); + } finally { + $event->end = microtime(true); + } + if ($item->isHit()) { + ++$event->hits; } else { - $call->result = null; + ++$event->misses; } + $event->result = $item->get(); - $this->addCall($call); - - return $result; + return $item; } + /** + * {@inheritdoc} + */ public function hasItem($key) { - $call = $this->timeCall(__FUNCTION__, [$key]); - $this->addCall($call); + $event = $this->start(__FUNCTION__, $key); + try { + $event->result = $this->pool->hasItem($key); + } finally { + $event->end = microtime(true); + } + + if (!$event->result) { + ++$event->misses; + } - return $call->result; + return $event->result; } + /** + * {@inheritdoc} + */ public function deleteItem($key) { - $call = $this->timeCall(__FUNCTION__, [$key]); - $this->addCall($call); - - return $call->result; + $event = $this->start(__FUNCTION__, $key); + try { + return $event->result = $this->pool->deleteItem($key); + } finally { + $event->end = microtime(true); + } } + /** + * {@inheritdoc} + */ public function save(CacheItemInterface $item) { - $key = $item->getKey(); - $value = $this->getValueRepresentation($item->get()); - - $call = $this->timeCall(__FUNCTION__, [$item]); - $call->arguments = ['', $key, $value]; - $this->addCall($call); - - return $call->result; + $event = $this->start(__FUNCTION__, $item); + try { + return $event->result = $this->pool->save($item); + } finally { + $event->end = microtime(true); + } } + /** + * {@inheritdoc} + */ public function saveDeferred(CacheItemInterface $item) { - $key = $item->getKey(); - $value = $this->getValueRepresentation($item->get()); - - $call = $this->timeCall(__FUNCTION__, [$item]); - $call->arguments = ['', $key, $value]; - $this->addCall($call); - - return $call->result; + $event = $this->start(__FUNCTION__, $item); + try { + return $event->result = $this->pool->saveDeferred($item); + } finally { + $event->end = microtime(true); + } } + /** + * {@inheritdoc} + */ public function getItems(array $keys = []) { - $call = $this->timeCall(__FUNCTION__, [$keys]); - $result = $call->result; - $call->result = sprintf('', gettype($result)); - $this->addCall($call); - - return $result; + $event = $this->start(__FUNCTION__, $keys); + try { + $result = $this->pool->getItems($keys); + } finally { + $event->end = microtime(true); + } + $f = function () use ($result, $event) { + $event->result = []; + foreach ($result as $key => $item) { + if ($item->isHit()) { + ++$event->hits; + } else { + ++$event->misses; + } + $event->result[$key] = $item->get(); + yield $key => $item; + } + }; + + return $f(); } + /** + * {@inheritdoc} + */ public function clear() { - $call = $this->timeCall(__FUNCTION__, []); - $this->addCall($call); - - return $call->result; - } - - public function clearTags(array $tags) - { - $call = $this->timeCall(__FUNCTION__, [$tags]); - $this->addCall($call); - - return $call->result; + $event = $this->start(__FUNCTION__); + try { + return $event->result = $this->pool->clear(); + } finally { + $event->end = microtime(true); + } } + /** + * {@inheritdoc} + */ public function deleteItems(array $keys) { - $call = $this->timeCall(__FUNCTION__, [$keys]); - $this->addCall($call); - - return $call->result; + $event = $this->start(__FUNCTION__, $keys); + try { + return $event->result = $this->pool->deleteItems($keys); + } finally { + $event->end = microtime(true); + } } + /** + * {@inheritdoc} + */ public function commit() { - $call = $this->timeCall(__FUNCTION__); - $this->addCall($call); - - return $call->result; + $event = $this->start(__FUNCTION__); + try { + return $event->result = $this->pool->commit(); + } finally { + $event->end = microtime(true); + } } - /** - * @return array - */ public function getCalls() { return $this->calls; } - /** - * Get a string to represent the value. - * - * @param mixed $value - * - * @return string - */ - private function getValueRepresentation($value) - { - $type = gettype($value); - if (in_array($type, ['boolean', 'integer', 'double', 'string', 'NULL'])) { - $rep = $value; - } elseif ($type === 'array') { - $rep = json_encode($value); - } elseif ($type === 'object') { - $rep = get_class($value); - } else { - $rep = sprintf('', $type); - } - - return $rep; - } - - protected function writeLog($call) + protected function start($name, $argument = null) { - if (!$this->logger) { - return; - } + $this->calls[] = $event = new TraceableAdapterEvent(); + $event->name = $name; + $event->argument = $argument; + $event->start = microtime(true); - $data = [ - 'name' => $this->name, - 'method' => $call->name, - 'arguments' => json_encode($call->arguments), - 'hit' => isset($call->isHit) ? $call->isHit ? 'True' : 'False' : 'Invalid', - 'time' => round($call->time * 1000, 2), - 'result' => $call->result, - ]; - - $this->logger->log( - $this->level, - sprintf('[Cache] Provider: %s. Method: %s(%s). Hit: %s. Time: %sms. Result: %s', - $data['name'], - $data['method'], - $data['arguments'], - $data['hit'], - $data['time'], - $data['result'] - ), - $data - ); + return $event; } /** @@ -276,3 +245,17 @@ public function setLevel($level) return $this; } } + +/** + * @internal + */ +class TraceableAdapterEvent +{ + public $name; + public $argument; + public $start; + public $end; + public $result; + public $hits = 0; + public $misses = 0; +} diff --git a/src/Cache/Recording/Factory.php b/src/Cache/Recording/Factory.php index c09ec4f..a59385a 100644 --- a/src/Cache/Recording/Factory.php +++ b/src/Cache/Recording/Factory.php @@ -12,7 +12,6 @@ namespace Cache\CacheBundle\Cache\Recording; use Cache\Hierarchy\HierarchicalPoolInterface; -use Cache\Taggable\TaggablePoolInterface; use Psr\Cache\CacheItemPoolInterface; use Psr\Log\LoggerInterface; @@ -53,9 +52,9 @@ public function __construct(LoggerInterface $logger = null, $level = null) */ public function create($name, CacheItemPoolInterface $pool) { - if ($pool instanceof TaggablePoolInterface && $pool instanceof HierarchicalPoolInterface) { + if ($pool instanceof TaggableCacheItemPoolInterface && $pool instanceof HierarchicalPoolInterface) { $recorder = new HierarchyAndTaggablePool($pool); - } elseif ($pool instanceof TaggablePoolInterface) { + } elseif ($pool instanceof TaggableCacheItemPoolInterface) { $recorder = new TaggablePool($pool); } elseif ($pool instanceof HierarchicalPoolInterface) { $recorder = new HierarchyPool($pool); diff --git a/src/Cache/Recording/TaggablePool.php b/src/Cache/Recording/TaggablePool.php index b0f2a10..091e9fe 100644 --- a/src/Cache/Recording/TaggablePool.php +++ b/src/Cache/Recording/TaggablePool.php @@ -11,18 +11,36 @@ namespace Cache\CacheBundle\Cache\Recording; -use Cache\Taggable\TaggablePoolInterface; +use Cache\TagInterop\TaggableCacheItemPoolInterface; /** * @author Tobias Nyholm */ -class TaggablePool extends CachePool implements TaggablePoolInterface +class TaggablePool extends CachePool implements TaggableCacheItemPoolInterface { - public function clearTags(array $tags) + /** + * {@inheritdoc} + */ + public function invalidateTag($tag) { - $call = $this->timeCall(__FUNCTION__, [$tags]); - $this->addCall($call); + $event = $this->start(__FUNCTION__, $tag); + try { + return $event->result = $this->pool->invalidateTag($tag); + } finally { + $event->end = microtime(true); + } + } - return $call->result; + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) + { + $event = $this->start(__FUNCTION__, $tags); + try { + return $event->result = $this->pool->invalidateTags($tags); + } finally { + $event->end = microtime(true); + } } } diff --git a/src/DataCollector/CacheDataCollector.php b/src/DataCollector/CacheDataCollector.php index 282421b..39f469d 100644 --- a/src/DataCollector/CacheDataCollector.php +++ b/src/DataCollector/CacheDataCollector.php @@ -12,24 +12,17 @@ namespace Cache\CacheBundle\DataCollector; use Cache\CacheBundle\Cache\Recording\CachePool; +use Cache\CacheBundle\Cache\Recording\TraceableAdapterEvent; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollector; /** - * Class CacheDataCollector. - * * @author Aaron Scherer + * @author Tobias Nyholm */ class CacheDataCollector extends DataCollector { - /** - * Template name. - * - * @type string - */ - const TEMPLATE = 'CacheBundle:Collector:cache.html.twig'; - /** * @type CachePool[] */ @@ -45,13 +38,7 @@ public function addInstance($name, CachePool $instance) } /** - * Collects data for the given Request and Response. - * - * @param Request $request A Request instance - * @param Response $response A Response instance - * @param \Exception $exception An Exception instance - * - * @api + * {@inheritdoc} */ public function collect(Request $request, Response $response, \Exception $exception = null) { @@ -66,15 +53,11 @@ public function collect(Request $request, Response $response, \Exception $except } /** - * Returns the name of the collector. - * - * @return string The collector name - * - * @api + * {@inheritdoc} */ public function getName() { - return 'cache'; + return 'php-cache'; } /** @@ -118,36 +101,44 @@ private function calculateStatistics() 'calls' => 0, 'time' => 0, 'reads' => 0, - 'hits' => 0, - 'misses' => 0, 'writes' => 0, 'deletes' => 0, + 'hits' => 0, + 'misses' => 0, ]; + /** @type TraceableAdapterEvent $call */ foreach ($calls as $call) { $statistics[$name]['calls'] += 1; - $statistics[$name]['time'] += $call->time; - if ($call->name === 'getItem') { + $statistics[$name]['time'] += $call->end - $call->start; + if ('getItem' === $call->name) { $statistics[$name]['reads'] += 1; - if ($call->isHit) { + if ($call->hits) { $statistics[$name]['hits'] += 1; } else { $statistics[$name]['misses'] += 1; } - } elseif ($call->name === 'hasItem') { + } elseif ('getItems' === $call->name) { + $count = $call->hits + $call->misses; + $statistics[$name]['reads'] += $count; + $statistics[$name]['hits'] += $call->hits; + $statistics[$name]['misses'] += $count - $call->misses; + } elseif ('hasItem' === $call->name) { $statistics[$name]['reads'] += 1; - if ($call->result === false) { + if (false === $call->result) { $statistics[$name]['misses'] += 1; + } else { + $statistics[$name]['hits'] += 1; } - } elseif ($call->name === 'save') { + } elseif ('save' === $call->name) { $statistics[$name]['writes'] += 1; - } elseif ($call->name === 'deleteItem') { + } elseif ('deleteItem' === $call->name) { $statistics[$name]['deletes'] += 1; } } if ($statistics[$name]['reads']) { - $statistics[$name]['ratio'] = round(100 * $statistics[$name]['hits'] / $statistics[$name]['reads'], 2).'%'; + $statistics[$name]['hit_read_ratio'] = round(100 * $statistics[$name]['hits'] / $statistics[$name]['reads'], 2); } else { - $statistics[$name]['ratio'] = 'N/A'; + $statistics[$name]['hit_read_ratio'] = null; } } @@ -160,16 +151,24 @@ private function calculateStatistics() private function calculateTotalStatistics() { $statistics = $this->getStatistics(); - $totals = ['calls' => 0, 'time' => 0, 'reads' => 0, 'hits' => 0, 'misses' => 0, 'writes' => 0]; + $totals = [ + 'calls' => 0, + 'time' => 0, + 'reads' => 0, + 'writes' => 0, + 'deletes' => 0, + 'hits' => 0, + 'misses' => 0, + ]; foreach ($statistics as $name => $values) { foreach ($totals as $key => $value) { $totals[$key] += $statistics[$name][$key]; } } if ($totals['reads']) { - $totals['ratio'] = round(100 * $totals['hits'] / $totals['reads'], 2).'%'; + $totals['hit_read_ratio'] = round(100 * $totals['hits'] / $totals['reads'], 2); } else { - $totals['ratio'] = 'N/A'; + $totals['hit_read_ratio'] = null; } return $totals; diff --git a/src/DependencyInjection/CacheExtension.php b/src/DependencyInjection/CacheExtension.php index c3cdd7c..7840578 100644 --- a/src/DependencyInjection/CacheExtension.php +++ b/src/DependencyInjection/CacheExtension.php @@ -11,7 +11,7 @@ namespace Cache\CacheBundle\DependencyInjection; -use Cache\Bridge\DoctrineCacheBridge; +use Cache\Bridge\Doctrine\DoctrineCacheBridge; use Cache\CacheBundle\Bridge\SymfonyValidatorBridge; use Cache\CacheBundle\Factory\DoctrineBridgeFactory; use Cache\CacheBundle\Factory\SessionHandlerFactory; @@ -92,9 +92,9 @@ protected function findServiceIds(array $config, array &$serviceIds) */ private function verifyDoctrineBridgeExists($name) { - if (!class_exists('Cache\Bridge\DoctrineCacheBridge')) { + if (!class_exists('Cache\Bridge\Doctrine\DoctrineCacheBridge')) { throw new \Exception(sprintf( - 'You need the DoctrineBridge to be able to use "%s". Please run "composer require cache/psr-6-doctrine-bridge" to install the missing dependency.', + 'You need the DoctrineCacheBridge to be able to use "%s". Please run "composer require cache/psr-6-doctrine-bridge" to install the missing dependency.', $name )); } diff --git a/src/DependencyInjection/Compiler/DoctrineCompilerPass.php b/src/DependencyInjection/Compiler/DoctrineCompilerPass.php index 8af299d..b66fb33 100644 --- a/src/DependencyInjection/Compiler/DoctrineCompilerPass.php +++ b/src/DependencyInjection/Compiler/DoctrineCompilerPass.php @@ -11,7 +11,7 @@ namespace Cache\CacheBundle\DependencyInjection\Compiler; -use Cache\Bridge\DoctrineCacheBridge; +use Cache\Bridge\Doctrine\DoctrineCacheBridge; use Cache\CacheBundle\Factory\DoctrineBridgeFactory; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; diff --git a/src/Factory/DoctrineBridgeFactory.php b/src/Factory/DoctrineBridgeFactory.php index f7cde98..abe35f8 100644 --- a/src/Factory/DoctrineBridgeFactory.php +++ b/src/Factory/DoctrineBridgeFactory.php @@ -11,7 +11,7 @@ namespace Cache\CacheBundle\Factory; -use Cache\Bridge\DoctrineCacheBridge; +use Cache\Bridge\Doctrine\DoctrineCacheBridge; use Cache\CacheBundle\Cache\FixedTaggingCachePool; use Cache\Taggable\TaggablePSR6PoolAdapter; use Psr\Cache\CacheItemPoolInterface; diff --git a/src/Resources/config/data-collector.yml b/src/Resources/config/data-collector.yml index b921338..48d9fc3 100644 --- a/src/Resources/config/data-collector.yml +++ b/src/Resources/config/data-collector.yml @@ -2,4 +2,4 @@ services: cache.data_collector: class: Cache\CacheBundle\DataCollector\CacheDataCollector tags: - - { name: data_collector, template: 'CacheBundle:Collector:cache.html.twig', id: 'cache' } + - { name: data_collector, template: 'CacheBundle:Collector:cache.html.twig', id: 'php-cache' } diff --git a/src/Resources/views/Collector/cache.html.twig b/src/Resources/views/Collector/cache.html.twig index 6f46646..fbe8e83 100644 --- a/src/Resources/views/Collector/cache.html.twig +++ b/src/Resources/views/Collector/cache.html.twig @@ -7,16 +7,7 @@ # with this source code in the file LICENSE. #} -{% extends 'WebProfilerBundle:Profiler:layout.html.twig' %} - -{% block head %} - {{ parent() }} - -{% endblock head %} +{% extends '@WebProfiler/Profiler/layout.html.twig' %} {% block toolbar %} {% if collector.totals.calls > 0 %} @@ -30,22 +21,22 @@ {% endset %} {% set text %} -
- Cache Calls - {{ collector.totals.calls }} -
-
- Total time - {{ '%0.2f'|format(collector.totals.time * 1000) }} ms -
-
- Cache hits - {{ collector.totals.hits }}/{{ collector.totals.reads }} ({{ collector.totals.ratio }}) -
-
- Cache writes - {{ collector.totals.writes }} -
+
+ Cache Calls + {{ collector.totals.calls }} +
+
+ Total time + {{ '%0.2f'|format(collector.totals.time * 1000) }} ms +
+
+ Cache hits + {{ collector.totals.hits }}/{{ collector.totals.reads }}{% if collector.totals.hit_read_ratio is not null %} ({{ collector.totals.hit_read_ratio }}%){% endif %} +
+
+ Cache writes + {{ collector.totals.writes }} +
{% endset %} {% include 'WebProfilerBundle:Profiler:toolbar_item.html.twig' with { 'link': profiler_url } %} {% endif %} @@ -56,65 +47,128 @@ {{ include('@Cache/Icon/logo.svg') }} - Cache + PHPCache {{ collector.totals.calls }} - {{ '%0.0f'|format(collector.totals.time * 1000) }} ms + {{ '%0.2f'|format(collector.totals.time * 1000) }} ms {% endblock %} {% block panel %} -

Cache

- {% for name, calls in collector.calls %} -

Statistics for '{{ name }}'

- - - - {% for key, value in collector.statistics[name] %} - - {% endfor %} - - - - - {% for key, value in collector.statistics[name] %} - {% if key == 'time' %} - - {% else %} - - {% endif %} - {% endfor %} - - -
{{ key|capitalize }}
{{ '%0.2f'|format(value * 1000) }} ms{{ value }}
+

PHPCache

+
+
+ {{ collector.totals.calls }} + Total calls +
+
+ {{ '%0.2f'|format(collector.totals.time * 1000) }} ms + Total time +
+
+
+ {{ collector.totals.reads }} + Total reads +
+
+ {{ collector.totals.writes }} + Total writes +
+
+ {{ collector.totals.deletes }} + Total deletes +
+
+
+ {{ collector.totals.hits }} + Total hits +
+
+ {{ collector.totals.misses }} + Total misses +
+
+ + {% if collector.totals.hit_read_ratio is null %} + n/a + {% else %} + {{ collector.totals.hit_read_ratio }} % + {% endif %} + + Hits/reads +
+
+ +

Pools

+
+ {% for name, calls in collector.calls %} +
+

{{ name }} {{ collector.statistics[name].calls }}

-

Calls for '{{ name }}'

+
+

Statistics

+
+ {% for key, value in collector.statistics[name] %} +
+ + {% if key == 'time' %} + {{ '%0.2f'|format(1000 * value) }} ms + {% elseif key == 'hit_read_ratio' %} + {% if value is null %} + n/a + {% else %} + {{ value }} % + {% endif %} + {% else %} + {{ value }} + {% endif %} + + {{ key == 'hit_read_ratio' ? 'Hits/reads' : key|capitalize }} +
+ {% if key == 'time' or key == 'deletes' %} +
+ {% endif %} + {% endfor %} +
- {% if not collector.totals.calls %} -

- No calls. -

- {% else %} -
    - {% for i, call in calls %} -
  • -
    - Name: {{ call.name }}
    - Arguments: {{ call.arguments|json_encode[:140] }}
    - Results: {% if call.result == false %} - Miss - {% else %} - {{ call.result[:140] }} - {% endif %}
    +

    Calls

    + {% if calls|length == 0 %} +
    +

    No calls

    - - Time: {{ '%0.2f'|format(call.time * 1000) }} ms - -
  • - {% endfor %} -
- {% endif %} - {% endfor %} + {% else %} + + + + + + + + + + {% for call in calls %} + {% set separatorStyle = not loop.first ? ' style="border-top-width: medium;"' : '' %} + + + {{ call.name }} + {{ dump(call.argument) }} + + + + + + + + + + {% endfor %} + +
#KeyValue
{{ loop.index }}
Result{{ dump(call.result) }}
Time{{ '%0.2f'|format((call.end - call.start) * 1000) }} ms
+ {% endif %} +
+
+ {% endfor %} +
{% endblock %} diff --git a/tests/Functional/BaseTestCase.php b/tests/Functional/BaseTestCase.php deleted file mode 100644 index bb5a121..0000000 --- a/tests/Functional/BaseTestCase.php +++ /dev/null @@ -1,33 +0,0 @@ -, Tobias Nyholm - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Cache\CacheBundle\Tests\Functional; - -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; - -class BaseTestCase extends WebTestCase -{ - protected static function getKernelClass() - { - require_once __DIR__.'/app/AppKernel.php'; - - return 'Cache\CacheBundle\Tests\Functional\app\AppKernel'; - } - - protected static function createKernel(array $options = []) - { - $class = self::getKernelClass(); - - return new $class( - isset($options['config']) ? $options['config'] : 'default.yml' - ); - } -} diff --git a/tests/Functional/BundleInitializationTest.php b/tests/Functional/BundleInitializationTest.php index 38006e2..3c68720 100644 --- a/tests/Functional/BundleInitializationTest.php +++ b/tests/Functional/BundleInitializationTest.php @@ -11,10 +11,40 @@ namespace Cache\CacheBundle\Tests\Functional; -class BundleInitializationTest extends BaseTestCase +use Cache\Bridge\Doctrine\DoctrineCacheBridge; +use Cache\CacheBundle\Bridge\SymfonyValidatorBridge; +use Cache\CacheBundle\CacheBundle; +use Cache\CacheBundle\Routing\CachingRouter; +use Cache\SessionHandler\Psr6SessionHandler; +use Nyholm\BundleTest\BaseBundleTestCase; + +/** + * @author Tobias Nyholm + */ +class BundleInitializationTest extends BaseBundleTestCase { - public function testRegisterBundle() + protected function getBundleClass() + { + return CacheBundle::class; + } + + protected function setUp() { - static::createClient(); + parent::setUp(); + $kernel = $this->createKernel(); + $kernel->addConfigFile(__DIR__.'/config.yml'); + } + + public function testInitBundle() + { + $this->bootKernel(); + $container = $this->getContainer(); + + $this->assertTrue($container->hasParameter('cache.provider_service_ids')); + $this->assertInstanceOf(DoctrineCacheBridge::class, $container->get('cache.service.annotation')); + $this->assertInstanceOf(DoctrineCacheBridge::class, $container->get('cache.service.serializer')); + $this->assertInstanceOf(SymfonyValidatorBridge::class, $container->get('cache.service.validation')); + $this->assertInstanceOf(Psr6SessionHandler::class, $container->get('cache.service.session')); + $this->assertInstanceOf(CachingRouter::class, $container->get('cache.service.router')); } } diff --git a/tests/Functional/app/AppKernel.php b/tests/Functional/app/AppKernel.php deleted file mode 100644 index 6b76758..0000000 --- a/tests/Functional/app/AppKernel.php +++ /dev/null @@ -1,66 +0,0 @@ -, Tobias Nyholm - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -namespace Cache\CacheBundle\Tests\Functional\app; - -use Symfony\Component\Config\Loader\LoaderInterface; -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\HttpKernel\Kernel; - -class AppKernel extends Kernel -{ - private $config; - - public function __construct($config) - { - parent::__construct('test', true); - - $fs = new Filesystem(); - - if (!$fs->isAbsolutePath($config)) { - $config = __DIR__.'/config/'.$config; - } - - if (!file_exists($config)) { - throw new \RuntimeException(sprintf('The config file "%s" does not exist', $config)); - } - - $this->config = $config; - } - - public function registerBundles() - { - return [ - new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - new \Cache\CacheBundle\CacheBundle(), - ]; - } - - public function registerContainerConfiguration(LoaderInterface $loader) - { - $loader->load($this->config); - } - - public function getCacheDir() - { - return sys_get_temp_dir().'/TestBundle'; - } - - public function serialize() - { - return $this->config; - } - - public function unserialize($config) - { - $this->__construct($config); - } -} diff --git a/tests/Functional/app/config/default.yml b/tests/Functional/app/config/default.yml deleted file mode 100644 index 8ddd7ed..0000000 --- a/tests/Functional/app/config/default.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: framework.yml } diff --git a/tests/Functional/app/config/framework.yml b/tests/Functional/app/config/framework.yml deleted file mode 100644 index 962895c..0000000 --- a/tests/Functional/app/config/framework.yml +++ /dev/null @@ -1,11 +0,0 @@ -framework: - secret: test - test: ~ - session: - storage_id: session.storage.mock_file - form: false - csrf_protection: false - validation: - enabled: false - router: - resource: "%kernel.root_dir%/config/routing.yml" diff --git a/tests/Functional/app/config/routing.yml b/tests/Functional/app/config/routing.yml deleted file mode 100644 index e69de29..0000000 diff --git a/tests/Functional/config.yml b/tests/Functional/config.yml new file mode 100644 index 0000000..75d87b9 --- /dev/null +++ b/tests/Functional/config.yml @@ -0,0 +1,38 @@ +services: + array_cache: + class: Cache\Adapter\PHPArray\ArrayCachePool + +cache: + session: + enabled: true + service_id: 'array_cache' + use_tagging: true + ttl: 7200 + + router: + enabled: true + service_id: 'array_cache' + ttl: 86400 + + annotation: + enabled: true + service_id: 'array_cache' + use_tagging: true + + serializer: + enabled: true + service_id: 'array_cache' + use_tagging: true + + validation: + enabled: true + service_id: 'array_cache' + use_tagging: true + +framework: + annotations: + cache: 'cache.service.annotation' + serializer: + cache: 'cache.service.serializer' + validation: + cache: 'cache.service.validation'