Implement caching for feature collections (#30) and maps (#4).

This commit is contained in:
David Molineus
2016-10-06 15:47:33 +02:00
parent 2e5139a756
commit 8c24f5e735
16 changed files with 398 additions and 75 deletions

View File

@@ -35,6 +35,17 @@ class ContaoAssets implements Assets
*/
private $assetsManager;
/**
* Cached assets.
*
* @var array
*/
private $cache = [
'stylesheets' => [],
'javascripts' => [],
'map' => []
];
/**
* ContaoAssets constructor.
*
@@ -52,6 +63,8 @@ class ContaoAssets implements Assets
*/
public function addJavascript($script, $type = self::TYPE_SOURCE)
{
$this->cache['javascripts'][] = [$script, $type];
switch ($type) {
case static::TYPE_SOURCE:
$GLOBALS['TL_HEAD'][] = sprintf('<script>%s</script>', $script);
@@ -70,6 +83,8 @@ class ContaoAssets implements Assets
*/
public function addStylesheet($stylesheet, $type = self::TYPE_FILE)
{
$this->cache['stylesheets'][] = [$stylesheet, $type];
switch ($type) {
case static::TYPE_SOURCE:
$GLOBALS['TL_HEAD'][] = sprintf('<style>%s</style>', $stylesheet);
@@ -94,8 +109,39 @@ class ContaoAssets implements Assets
*/
public function setMap($map)
{
$this->map = $map;
$this->cache['map'] = $map;
$this->map = $map;
return $this;
}
/**
* Export to array.
*
* @return array
*/
public function toArray()
{
return $this->cache;
}
/**
* From array.
*
* @param array $cache Cache.
*
* @return void
*/
public function fromArray(array $cache)
{
foreach ($cache['javascripts'] as $javascript) {
$this->addJavascript($javascript[0], $javascript[1]);
}
foreach ($cache['stylesheets'] as $stylesheet) {
$this->addStylesheet($stylesheet[0], $stylesheet[1]);
}
$this->map = $cache['map'];
}
}

View File

@@ -11,10 +11,8 @@
namespace Netzmacht\Contao\Leaflet\Dca;
use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper;
use Netzmacht\Contao\Leaflet\Mapper\MapMapper;
use Netzmacht\Contao\Leaflet\Model\LayerModel;
use Netzmacht\Contao\Leaflet\Model\MapModel;
use Netzmacht\Contao\Toolkit\Dca\Callback\CallbackFactory;
use Netzmacht\LeafletPHP\Value\LatLng;
/**
@@ -24,6 +22,35 @@ use Netzmacht\LeafletPHP\Value\LatLng;
*/
class LeafletCallbacks
{
/**
* File system.
*
* @var \Files
*/
private $fileSystem;
/**
* LeafletCallbacks constructor.
*
* @param \Files $fileSystem File system.
*/
public function __construct(\Files $fileSystem)
{
$this->fileSystem = $fileSystem;
}
/**
* Generate the callback definition.
*
* @param string $methodName Callback method name.
*
* @return callable
*/
public static function callback($methodName)
{
return CallbackFactory::service('leaflet.dca.common', $methodName);
}
/**
* Create the zoom range.
*
@@ -75,4 +102,18 @@ class LeafletCallbacks
return $options;
}
/**
* Clear the leaflet cache.
*
* @param mixed $value Value when used as save_callback.
*
* @return mixed
*/
public function clearCache($value = null)
{
$this->fileSystem->rrdir('system/cache/leaflet', true);
return $value;
}
}

View File

@@ -10,6 +10,7 @@
namespace Netzmacht\Contao\Leaflet\DependencyInjection;
use Doctrine\Common\Cache\Cache;
use Netzmacht\Contao\Leaflet\Boot;
use Netzmacht\Contao\Leaflet\Frontend\ValueFilter;
use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper;
@@ -40,6 +41,13 @@ class LeafletServices
*/
const BOOT = 'leaflet.boot';
/**
* Leaflet cache
*
* @return Cache
*/
const CACHE = 'leaflet.cache';
/**
* Service name of the definition builder.
*

View File

@@ -11,6 +11,7 @@
namespace Netzmacht\Contao\Leaflet;
use Doctrine\Common\Cache\Cache;
use Netzmacht\Contao\Leaflet\Event\GetJavascriptEvent;
use Netzmacht\Contao\Leaflet\Filter\Filter;
use Netzmacht\Contao\Leaflet\Frontend\DataController;
@@ -18,7 +19,6 @@ use Netzmacht\Contao\Leaflet\Frontend\RequestUrl;
use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper;
use Netzmacht\Contao\Leaflet\Model\LayerModel;
use Netzmacht\Contao\Leaflet\Model\MapModel;
use Netzmacht\LeafletPHP\Assets;
use Netzmacht\LeafletPHP\Value\GeoJson\FeatureCollection;
use Netzmacht\LeafletPHP\Definition\Map;
use Netzmacht\LeafletPHP\Leaflet;
@@ -62,7 +62,7 @@ class MapProvider
/**
* Map assets collector.
*
* @var Assets
* @var ContaoAssets
*/
private $assets;
@@ -80,6 +80,13 @@ class MapProvider
*/
private $displayErrors;
/**
* Cache.
*
* @var Cache
*/
private $cache;
/**
* Construct.
*
@@ -87,7 +94,8 @@ class MapProvider
* @param Leaflet $leaflet The Leaflet instance.
* @param EventDispatcher $eventDispatcher The Contao event dispatcher.
* @param \Input $input Thw request input.
* @param Assets $assets Assets handler.
* @param ContaoAssets $assets Assets handler.
* @param Cache $cache Cache.
* @param array $filters Request filters configuration.
* @param bool $displayErrors Display errors setting.
*/
@@ -96,7 +104,8 @@ class MapProvider
Leaflet $leaflet,
EventDispatcher $eventDispatcher,
\Input $input,
Assets $assets,
ContaoAssets $assets,
Cache $cache,
array $filters,
$displayErrors
) {
@@ -107,6 +116,7 @@ class MapProvider
$this->assets = $assets;
$this->filters = $filters;
$this->displayErrors = $displayErrors;
$this->cache = $cache;
}
/**
@@ -165,9 +175,6 @@ class MapProvider
*
* @return string
* @throws \Exception If generating went wrong.
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
*/
public function generate(
$mapId,
@@ -176,23 +183,38 @@ class MapProvider
$template = 'leaflet_map_js',
$style = ''
) {
$definition = $this->getDefinition($mapId, $filter, $elementId);
$template = \Controller::getTemplate($template);
if ($mapId instanceof MapModel) {
$model = $mapId;
$mapId = $mapId->id;
} else {
$model = $this->getModel($mapId);
}
// @codingStandardsIgnoreStart - Set for the template.
$javascript = $this->leaflet->build($definition, $this->assets);
$mapId = $definition->getId();
// @codingStandardsIgnoreEnd
if ($model->cache) {
$cacheKey = $this->getCacheKey($mapId, $filter, $elementId, $template, $style);
ob_start();
include $template;
$content = ob_get_contents();
ob_end_clean();
if ($this->cache->contains($cacheKey)) {
$cached = $this->cache->fetch($cacheKey);
$this->assets->fromArray($cached['assets']);
$event = new GetJavascriptEvent($definition, $content);
$this->eventDispatcher->dispatch($event::NAME, $event);
return $cached['javascript'];
}
}
return $event->getJavascript();
$buffer = $this->doGenerate($mapId, $filter, $elementId, $template, $model, $style);
if ($model->cache) {
$this->cache->save(
$cacheKey,
[
'assets' => $this->assets->toArray(),
'javascript' => $buffer
],
(int) $model->cacheLifeTime
);
}
return $buffer;
}
/**
@@ -217,7 +239,23 @@ class MapProvider
throw new \InvalidArgumentException(sprintf('Could not find layer "%s"', $layerId));
}
return $this->mapper->handleGeoJson($model, $filter);
if (!$model->cache) {
return $this->mapper->handleGeoJson($model, $filter);
}
$cacheKey = 'feature_layer_' . $model->id;
if ($filter) {
$cacheKey .= '.filter_' . md5($filter->toRequest());
}
if ($this->cache->contains($cacheKey)) {
return $this->cache->fetch($cacheKey);
}
$collection = $this->mapper->handleGeoJson($model, $filter);
$this->cache->save($cacheKey, $collection, $model->cacheLifeTime);
return $collection;
}
/**
@@ -230,7 +268,6 @@ class MapProvider
* @throws \RuntimeException IF the input data does not match.
*
* @SuppressWarnings(PHPMD.ExitExpression)
* @SuppressWarnings(PHPMD.Superglobals)
*/
public function handleAjaxRequest($identifier, $exit = true)
{
@@ -261,4 +298,75 @@ class MapProvider
}
}
}
/**
* Get the cache key.
*
* @param int $mapId The map database id.
* @param Filter|null $filter Optional request filter.
* @param string $elementId Optional element id. If none given the mapId or alias is used.
* @param string $template The template being used for generating.
* @param string $style Optional style attributes.
*
* @return string
*/
protected function getCacheKey($mapId, $filter, $elementId, $template, $style)
{
$cacheKey = 'map_' . $mapId;
if ($filter) {
$cacheKey .= '.filter_' . md5($filter->toRequest());
}
if ($elementId) {
$cacheKey .= '.element_' . $elementId;
}
$cacheKey .= '.template_' . $template;
if ($style) {
$cacheKey .= '.style_' . md5($style);
return $cacheKey;
}
return $cacheKey;
}
/**
* Do the generating of the map.
*
* @param MapModel $model Map model.
* @param Filter|null $filter Optional request filter.
* @param string $elementId Optional element id. If none given the mapId or alias is used.
* @param string $template The template being used for generating.
* @param string $style Optional style attributes.
*
* @return string
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
*/
protected function doGenerate($model, $filter, $elementId, $template, $style)
{
$definition = $this->getDefinition($model, $filter, $elementId);
$template = \Controller::getTemplate($template);
// @codingStandardsIgnoreStart - Set for the template.
$javascript = $this->leaflet->build($definition, $this->assets);
$mapId = $definition->getId();
// @codingStandardsIgnoreEnd
ob_start();
include $template;
$content = ob_get_contents();
ob_end_clean();
$event = new GetJavascriptEvent($definition, $content);
$this->eventDispatcher->dispatch($event::NAME, $event);
$buffer = $event->getJavascript();
return $buffer;
}
}

View File

@@ -11,6 +11,7 @@
namespace Netzmacht\Contao\Leaflet\Mapper\Layer;
use Netzmacht\Contao\Leaflet\ContaoAssets;
use Netzmacht\Contao\Leaflet\Filter\Filter;
use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper;
use Netzmacht\Contao\Leaflet\Model\LayerModel;
@@ -46,20 +47,20 @@ class MarkerClusterLayerMapper extends AbstractLayerMapper
/**
* Assets manager.
*
* @var AssetsManager
* @var ContaoAssets
*/
private $assetsManager;
private $assets;
/**
* MarkerClusterLayerMapper constructor.
*
* @param AssetsManager $assetsManager Assets manager.
* @param ContaoAssets $assets Assets manager.
*/
public function __construct(AssetsManager $assetsManager)
public function __construct(ContaoAssets $assets)
{
parent::__construct();
$this->assetsManager = $assetsManager;
$this->assets = $assets;
}
/**
@@ -102,7 +103,7 @@ class MarkerClusterLayerMapper extends AbstractLayerMapper
}
if (!$model->disableDefaultStyle) {
$this->assetsManager->addStylesheet('assets/leaflet/libs/leaflet-markercluster/MarkerCluster.Default.css');
$this->assets->addStylesheet('assets/leaflet/libs/leaflet-markercluster/MarkerCluster.Default.css');
}
$collection = LayerModel::findBy(

View File

@@ -12,6 +12,7 @@
namespace Netzmacht\Contao\Leaflet\Subscriber;
use ContaoCommunityAlliance\Contao\EventDispatcher\EventDispatcherInitializer;
use Netzmacht\Contao\Leaflet\ContaoAssets;
use Netzmacht\Contao\Leaflet\DependencyInjection\LeafletServices;
use Netzmacht\Contao\Leaflet\Event\GetJavascriptEvent;
use Netzmacht\Contao\Leaflet\Event\InitializeDefinitionMapperEvent;
@@ -59,9 +60,9 @@ class BootSubscriber implements EventSubscriberInterface
/**
* Assets manager.
*
* @var AssetsManager
* @var ContaoAssets
*/
private $assetsManager;
private $assets;
/**
* Definition mapper.
@@ -73,21 +74,21 @@ class BootSubscriber implements EventSubscriberInterface
/**
* BootSubscriber constructor.
*
* @param AssetsManager $assetsManager Assets manager.
* @param array $mappers Leaflet mapper configuration.
* @param array $encoders Leaflet encoder configuration.
* @param array $libraries Leaflet libraries configuration.
* @param ContaoAssets $assets Leaflet assets manager.
* @param array $mappers Leaflet mapper configuration.
* @param array $encoders Leaflet encoder configuration.
* @param array $libraries Leaflet libraries configuration.
*/
public function __construct(
AssetsManager $assetsManager,
ContaoAssets $assets,
array $mappers,
array $encoders,
array $libraries
) {
$this->assetsManager = $assetsManager;
$this->mappers = $mappers;
$this->encoders = $encoders;
$this->libraries = $libraries;
$this->assets = $assets;
$this->mappers = $mappers;
$this->encoders = $encoders;
$this->libraries = $libraries;
}
/**
@@ -188,7 +189,7 @@ class BootSubscriber implements EventSubscriberInterface
*/
public function loadAssets()
{
$this->assetsManager->addJavascript('assets/leaflet/maps/contao-leaflet.js');
$this->assets->addJavascript('assets/leaflet/maps/contao-leaflet.js', ContaoAssets::TYPE_FILE);
}
/**
@@ -229,7 +230,7 @@ class BootSubscriber implements EventSubscriberInterface
// @codingStandardsIgnoreStart
// TODO: Cache it.
// codingStandardsIgnoreEnd
$this->assetsManager->addJavascript('assets/leaflet/js/icons.js');
$this->assets->addJavascript('assets/leaflet/js/icons.js', ContaoAssets::TYPE_FILE);
}
}