Implement custom route for data request to prevent partial rendering of the page and it's possible issues (f.e. form captcha changes) (Close #49).

This commit is contained in:
David Molineus
2018-10-29 16:02:50 +01:00
parent 7ec2ee0d96
commit 0ba725ed38
14 changed files with 321 additions and 14 deletions

View File

@@ -22,7 +22,7 @@
"source": "https://github.com/netzmacht/contao-leaflet-maps" "source": "https://github.com/netzmacht/contao-leaflet-maps"
}, },
"require": { "require": {
"php": ">=7.0", "php": ">=7.1",
"ext-json": "*", "ext-json": "*",
"ext-pdo": "*", "ext-pdo": "*",
"contao/core-bundle": "~4.4", "contao/core-bundle": "~4.4",
@@ -39,6 +39,7 @@
"netzmacht/php-javascript-builder": "^1.0", "netzmacht/php-javascript-builder": "^1.0",
"netzmacht/php-leaflet": "^1.0.2", "netzmacht/php-leaflet": "^1.0.2",
"netzmacht/contao-toolkit": "~3.0", "netzmacht/contao-toolkit": "~3.0",
"netzmacht/contao-page-context": "~1.0",
"contao-community-alliance/meta-palettes": "^2.0 || ^1.5", "contao-community-alliance/meta-palettes": "^2.0 || ^1.5",
"menatwork/contao-multicolumnwizard": "^3.2", "menatwork/contao-multicolumnwizard": "^3.2",
"doctrine/cache": "^1.0" "doctrine/cache": "^1.0"

View File

@@ -138,7 +138,7 @@ L.Contao = L.Evented.extend({
* @param customLayer optional custom layer. * @param customLayer optional custom layer.
* @param map Pass a map object so that the data loading events are passed to the map. * @param map Pass a map object so that the data loading events are passed to the map.
*/ */
loadFile: function (url, type, options, customLayer, map) { loadUrl: function (url, type, options, customLayer, map) {
var layer = omnivore[type](url, options, customLayer); var layer = omnivore[type](url, options, customLayer);
if (map) { if (map) {
@@ -172,6 +172,19 @@ L.Contao = L.Evented.extend({
return layer; return layer;
}, },
/**
* Load data from an url into a layer using omnivore.
*
* @param url A file url.
* @param type The response content format.
* @param options Parser options
* @param customLayer optional custom layer.
* @param map Pass a map object so that the data loading events are passed to the map.
*/
loadFile: function (url, type, options, customLayer, map) {
return this.loadUrl(url, type, options, customLayer, map);
},
/** /**
* Point to layer callback. Adds a geo json point to the layer. * Point to layer callback. Adds a geo json point to the layer.
* *

View File

@@ -18,15 +18,20 @@ use Contao\CoreBundle\ContaoCoreBundle;
use Contao\ManagerPlugin\Bundle\BundlePluginInterface; use Contao\ManagerPlugin\Bundle\BundlePluginInterface;
use Contao\ManagerPlugin\Bundle\Config\BundleConfig; use Contao\ManagerPlugin\Bundle\Config\BundleConfig;
use Contao\ManagerPlugin\Bundle\Parser\ParserInterface; use Contao\ManagerPlugin\Bundle\Parser\ParserInterface;
use Contao\ManagerPlugin\Routing\RoutingPluginInterface;
use Netzmacht\Contao\Leaflet\Bundle\NetzmachtContaoLeafletBundle; use Netzmacht\Contao\Leaflet\Bundle\NetzmachtContaoLeafletBundle;
use Netzmacht\Contao\PageContext\NetzmachtContaoPageContextBundle;
use Netzmacht\Contao\Toolkit\Bundle\NetzmachtContaoToolkitBundle; use Netzmacht\Contao\Toolkit\Bundle\NetzmachtContaoToolkitBundle;
use Symfony\Component\Config\Loader\LoaderResolverInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\RouteCollection;
/** /**
* Contao manager plugin. * Contao manager plugin.
* *
* @package Netzmacht\Contao\Leaflet\ContaoManager * @package Netzmacht\Contao\Leaflet\ContaoManager
*/ */
class Plugin implements BundlePluginInterface class Plugin implements BundlePluginInterface, RoutingPluginInterface
{ {
/** /**
* {@inheritdoc} * {@inheritdoc}
@@ -35,8 +40,32 @@ class Plugin implements BundlePluginInterface
{ {
return [ return [
BundleConfig::create(NetzmachtContaoLeafletBundle::class) BundleConfig::create(NetzmachtContaoLeafletBundle::class)
->setLoadAfter([ContaoCoreBundle::class, NetzmachtContaoToolkitBundle::class]) ->setLoadAfter(
[
ContaoCoreBundle::class,
NetzmachtContaoToolkitBundle::class,
NetzmachtContaoPageContextBundle::class
]
)
->setReplace(['leaflet']), ->setReplace(['leaflet']),
]; ];
} }
/**
* {@inheritdoc}
*/
public function getRouteCollection(LoaderResolverInterface $resolver, KernelInterface $kernel): ?RouteCollection
{
$loader = $resolver->resolve(__DIR__ . '/../Resources/config/routing.yml');
if (!$loader) {
return null;
}
$collection = $loader->load(__DIR__ . '/../Resources/config/routing.yml');
if ($collection instanceof RouteCollection) {
$collection->addPrefix('leaflet/api');
}
return $collection;
}
} }

View File

@@ -32,6 +32,7 @@ services:
class: Netzmacht\Contao\Leaflet\Mapper\Layer\MarkersLayerMapper class: Netzmacht\Contao\Leaflet\Mapper\Layer\MarkersLayerMapper
arguments: arguments:
- '@netzmacht.contao_toolkit.repository_manager' - '@netzmacht.contao_toolkit.repository_manager'
- '@router'
tags: tags:
- { name: netzmacht.contao_leaflet.mapper } - { name: netzmacht.contao_leaflet.mapper }
@@ -46,6 +47,7 @@ services:
class: Netzmacht\Contao\Leaflet\Mapper\Layer\VectorsLayerMapper class: Netzmacht\Contao\Leaflet\Mapper\Layer\VectorsLayerMapper
arguments: arguments:
- '@netzmacht.contao_toolkit.repository_manager' - '@netzmacht.contao_toolkit.repository_manager'
- '@router'
tags: tags:
- { name: netzmacht.contao_leaflet.mapper } - { name: netzmacht.contao_leaflet.mapper }

View File

@@ -0,0 +1,11 @@
leaflet_layer:
path: /layer/{layerId}
controller: Netzmacht\Contao\Leaflet\Frontend\Action\LayerDataAction
defaults:
_leaflet_scope: page
_format: geojson
_scope: frontend
requirements:
_format: geojson
context: \w+
contextId: \d+

View File

@@ -122,3 +122,12 @@ services:
arguments: arguments:
- '@netzmacht.contao_leaflet.filter_factory' - '@netzmacht.contao_leaflet.filter_factory'
- '%kernel.debug%' - '%kernel.debug%'
Netzmacht\Contao\Leaflet\Frontend\PageIdDeterminator:
tags:
- { name: Netzmacht\Contao\PageContext\Request\PageIdDeterminator }
Netzmacht\Contao\Leaflet\Frontend\Action\LayerDataAction:
arguments:
- '@netzmacht.contao_leaflet.map.provider'
- '@netzmacht.contao_leaflet.filter_factory'

File diff suppressed because one or more lines are too long

View File

@@ -90,7 +90,7 @@ class EncoderSubscriber implements EventSubscriberInterface
$value = $event->getValue(); $value = $event->getValue();
$encoder = $event->getEncoder(); $encoder = $event->getEncoder();
$template = 'L.contao.%s(%s, %s, %s, %s, map);'; $template = 'L.contao.%s(%s, %s, %s, %s, map);';
$method = 'loadFile'; $method = 'loadUrl';
if ($value instanceof OmnivoreLayer) { if ($value instanceof OmnivoreLayer) {
$url = $value->getUrl(); $url = $value->getUrl();

View File

@@ -0,0 +1,103 @@
<?php
/**
* Leaflet maps for Contao CMS.
*
* @package contao-leaflet-maps
* @author David Molineus <david.molineus@netzmacht.de>
* @copyright 2014-2018 netzmacht David Molineus. All rights reserved.
* @license LGPL-3.0 https://github.com/netzmacht/contao-leaflet-maps/blob/master/LICENSE
* @filesource
*/
declare(strict_types=1);
namespace Netzmacht\Contao\Leaflet\Frontend\Action;
use Netzmacht\Contao\Leaflet\Filter\Filter;
use Netzmacht\Contao\Leaflet\Filter\FilterFactory;
use Netzmacht\Contao\Leaflet\MapProvider;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* Request action which handles request for layer data
*/
final class LayerDataAction
{
/**
* Map provider.
*
* @var MapProvider
*/
private $mapProvider;
/**
* Filter factory.
*
* @var FilterFactory
*/
private $filterFactory;
/**
* LayerDataAction constructor.
*
* @param MapProvider $mapProvider Map provider.
* @param FilterFactory $filterFactory Filter factory.
*/
public function __construct(MapProvider $mapProvider, FilterFactory $filterFactory)
{
$this->mapProvider = $mapProvider;
$this->filterFactory = $filterFactory;
}
/**
* Handle the request.
*
* @param int $layerId The layer id.
* @param string $_format The requested output format.
* @param Request $request The request.
*
* @return Response
*
* @throws BadRequestHttpException When unsupported format is given.
*
* @SuppressWarnings(PHPMD.CamelCaseParameterName)
* @SuppressWarnings(PHPMD.CamelCaseVariableName)
*/
public function __invoke(int $layerId, string $_format, Request $request): Response
{
$filter = $this->createFilter($request);
$data = $this->mapProvider->getFeatureCollection($layerId, $filter);
if ($_format === 'geojson') {
$response = new JsonResponse($data);
$response->setEncodingOptions(JSON_UNESCAPED_SLASHES);
return $response;
}
throw new BadRequestHttpException(sprintf('Unsupported format "%s"', $_format));
}
/**
* Create the filter if defined in the request.
*
* @param Request $request The request.
*
* @return Filter|null
*/
private function createFilter(Request $request): ?Filter
{
if (!$request->query->has('filter')) {
return null;
}
$filter = (string) $request->query->get('filter');
$values = (string) $request->query->get('values');
return $this->filterFactory->create($filter, $values);
}
}

View File

@@ -12,14 +12,18 @@
namespace Netzmacht\Contao\Leaflet\Frontend; namespace Netzmacht\Contao\Leaflet\Frontend;
use const E_USER_DEPRECATED;
use Netzmacht\Contao\Leaflet\Filter\Filter; use Netzmacht\Contao\Leaflet\Filter\Filter;
use Netzmacht\Contao\Leaflet\Filter\FilterFactory; use Netzmacht\Contao\Leaflet\Filter\FilterFactory;
use Netzmacht\Contao\Leaflet\MapProvider; use Netzmacht\Contao\Leaflet\MapProvider;
use function trigger_error;
/** /**
* The data controller handles ajax request for sub data. * The data controller handles ajax request for sub data.
* *
* @package Netzmacht\Contao\Leaflet\Frontend * @package Netzmacht\Contao\Leaflet\Frontend
*
* @deprecated
*/ */
class DataController class DataController
{ {
@@ -60,6 +64,13 @@ class DataController
{ {
$this->debugMode = $debugMode; $this->debugMode = $debugMode;
$this->filterFactory = $filterFactory; $this->filterFactory = $filterFactory;
// @codingStandardsIgnoreStart
@trigger_error(
'Deprecated since 3.1.0 and will be removed in 4.0.0 - Use properly route instead.',
E_USER_DEPRECATED
);
// @codingStandardsIgnoreEnd
} }
/** /**

View File

@@ -0,0 +1,47 @@
<?php
/**
* Leaflet maps for Contao CMS.
*
* @package contao-leaflet-maps
* @author David Molineus <david.molineus@netzmacht.de>
* @copyright 2014-2018 netzmacht David Molineus. All rights reserved.
* @license LGPL-3.0 https://github.com/netzmacht/contao-leaflet-maps/blob/master/LICENSE
* @filesource
*/
declare(strict_types=1);
namespace Netzmacht\Contao\Leaflet\Frontend;
use Netzmacht\Contao\PageContext\Exception\DeterminePageIdFailed;
use Netzmacht\Contao\PageContext\Request\PageIdDeterminator as PageContextPageIdDeterminator;
use Symfony\Component\HttpFoundation\Request;
/**
* Class ApiPageIdDeterminator
*/
final class PageIdDeterminator implements PageContextPageIdDeterminator
{
/**
* {@inheritDoc}
*/
public function match(Request $request): bool
{
return ($request->attributes->get('_leaflet_scope') === 'page' && $request->query->get('context') === 'page');
}
/**
* {@inheritDoc}
*
* @throws DeterminePageIdFailed When no context id is given.
*/
public function determinate(Request $request): int
{
if (!$request->query->has('contextId')) {
throw new DeterminePageIdFailed('Could not determine page id for from request.');
}
return $request->query->getInt('contextId');
}
}

View File

@@ -21,6 +21,8 @@ use Netzmacht\Contao\Leaflet\Mapper\Request;
* Class RequestUrl creates the request url. * Class RequestUrl creates the request url.
* *
* @package Netzmacht\Contao\Leaflet\Request * @package Netzmacht\Contao\Leaflet\Request
*
* @deprecated
*/ */
class RequestUrl implements \JsonSerializable class RequestUrl implements \JsonSerializable
{ {
@@ -89,6 +91,13 @@ class RequestUrl implements \JsonSerializable
{ {
$this->url = $url; $this->url = $url;
$this->hash = $hash; $this->hash = $hash;
// @codingStandardsIgnoreStart
@trigger_error(
'Deprecated since 3.1.0 and will be removed in 4.0.0. Use The router instead.',
E_USER_DEPRECATED
);
// @codingStandardsIgnoreEnd
} }
/** /**

View File

@@ -13,7 +13,6 @@
namespace Netzmacht\Contao\Leaflet\Mapper\Layer; namespace Netzmacht\Contao\Leaflet\Mapper\Layer;
use Contao\Model; use Contao\Model;
use Netzmacht\Contao\Leaflet\Frontend\RequestUrl;
use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper; use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper;
use Netzmacht\Contao\Leaflet\Mapper\GeoJsonMapper; use Netzmacht\Contao\Leaflet\Mapper\GeoJsonMapper;
use Netzmacht\Contao\Leaflet\Mapper\Request; use Netzmacht\Contao\Leaflet\Mapper\Request;
@@ -24,6 +23,7 @@ use Netzmacht\LeafletPHP\Definition;
use Netzmacht\LeafletPHP\Definition\Group\GeoJson; use Netzmacht\LeafletPHP\Definition\Group\GeoJson;
use Netzmacht\LeafletPHP\Plugins\Omnivore\GeoJson as OmnivoreGeoJson; use Netzmacht\LeafletPHP\Plugins\Omnivore\GeoJson as OmnivoreGeoJson;
use Netzmacht\LeafletPHP\Value\GeoJson\FeatureCollection; use Netzmacht\LeafletPHP\Value\GeoJson\FeatureCollection;
use Symfony\Component\Routing\RouterInterface;
/** /**
* Class MarkersLayerMapper maps the layer model to the markers definition. * Class MarkersLayerMapper maps the layer model to the markers definition.
@@ -46,14 +46,23 @@ class MarkersLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
*/ */
private $repositoryManager; private $repositoryManager;
/**
* Router.
*
* @var RouterInterface
*/
private $router;
/** /**
* Construct. * Construct.
* *
* @param RepositoryManager $repositoryManager Repository manager. * @param RepositoryManager $repositoryManager Repository manager.
* @param RouterInterface $router Router.
*/ */
public function __construct(RepositoryManager $repositoryManager) public function __construct(RepositoryManager $repositoryManager, RouterInterface $router)
{ {
$this->repositoryManager = $repositoryManager; $this->repositoryManager = $repositoryManager;
$this->router = $router;
parent::__construct(); parent::__construct();
} }
@@ -93,7 +102,7 @@ class MarkersLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
return [ return [
$this->getElementId($model, $elementId), $this->getElementId($model, $elementId),
RequestUrl::create($model->id, null, null, $request), $this->generateUrl((int) $model->id, $request),
[], [],
$layer, $layer,
]; ];
@@ -101,7 +110,7 @@ class MarkersLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
return [ return [
$this->getElementId($model, $elementId), $this->getElementId($model, $elementId),
RequestUrl::create($model->id, null, null, $request), $this->generateUrl((int) $model->id, $request),
]; ];
} }
@@ -182,4 +191,31 @@ class MarkersLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
return $repository->findByFilter($model->id); return $repository->findByFilter($model->id);
} }
/**
* Generate the data url for a layer.
*
* @param int $layerId The layer id.
* @param Request|null $request The request.
*
* @return string
*
* @SuppressWarnings(PHPMD.Superglobals)
*/
private function generateUrl(int $layerId, ?Request $request = null): string
{
$params = ['layerId' => $layerId];
if ($request && ($filter = $request->getFilter())) {
$params['filter'] = $filter::getName();
$params['values'] = $filter->toRequest();
}
if (isset($GLOBALS['objPage'])) {
$params['context'] = 'page';
$params['contextId'] = $GLOBALS['objPage']->id;
}
return $this->router->generate('leaflet_layer', $params, RouterInterface::ABSOLUTE_URL);
}
} }

View File

@@ -14,7 +14,6 @@ namespace Netzmacht\Contao\Leaflet\Mapper\Layer;
use Contao\Model; use Contao\Model;
use Contao\Model\Collection; use Contao\Model\Collection;
use Netzmacht\Contao\Leaflet\Frontend\RequestUrl;
use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper; use Netzmacht\Contao\Leaflet\Mapper\DefinitionMapper;
use Netzmacht\Contao\Leaflet\Mapper\GeoJsonMapper; use Netzmacht\Contao\Leaflet\Mapper\GeoJsonMapper;
use Netzmacht\Contao\Leaflet\Mapper\Request; use Netzmacht\Contao\Leaflet\Mapper\Request;
@@ -25,6 +24,7 @@ use Netzmacht\LeafletPHP\Definition;
use Netzmacht\LeafletPHP\Definition\Group\GeoJson; use Netzmacht\LeafletPHP\Definition\Group\GeoJson;
use Netzmacht\LeafletPHP\Plugins\Omnivore\GeoJson as OmnivoreGeoJson; use Netzmacht\LeafletPHP\Plugins\Omnivore\GeoJson as OmnivoreGeoJson;
use Netzmacht\LeafletPHP\Value\GeoJson\FeatureCollection; use Netzmacht\LeafletPHP\Value\GeoJson\FeatureCollection;
use Symfony\Component\Routing\RouterInterface;
/** /**
* Class VectorsLayerMapper maps the layer model for the Vectors layer definition. * Class VectorsLayerMapper maps the layer model for the Vectors layer definition.
@@ -47,14 +47,23 @@ class VectorsLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
*/ */
private $repositoryManager; private $repositoryManager;
/**
* Router.
*
* @var RouterInterface
*/
private $router;
/** /**
* Construct. * Construct.
* *
* @param RepositoryManager $repositoryManager Repository manager. * @param RepositoryManager $repositoryManager Repository manager.
* @param RouterInterface $router Router
*/ */
public function __construct(RepositoryManager $repositoryManager) public function __construct(RepositoryManager $repositoryManager, RouterInterface $router)
{ {
$this->repositoryManager = $repositoryManager; $this->repositoryManager = $repositoryManager;
$this->router = $router;
parent::__construct(); parent::__construct();
} }
@@ -101,7 +110,7 @@ class VectorsLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
return [ return [
$this->getElementId($model, $elementId), $this->getElementId($model, $elementId),
RequestUrl::create($model->id, null, null, $request), $this->generateUrl((int) $model->id, $request),
[], [],
$layer, $layer,
]; ];
@@ -109,7 +118,7 @@ class VectorsLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
return [ return [
$this->getElementId($model, $elementId), $this->getElementId($model, $elementId),
RequestUrl::create($model->id, null, null, $request), $this->generateUrl((int) $model->id, $request),
]; ];
} }
@@ -202,4 +211,31 @@ class VectorsLayerMapper extends AbstractLayerMapper implements GeoJsonMapper
$definition->setOnEachFeature(new Expression($model->onEachFeature)); $definition->setOnEachFeature(new Expression($model->onEachFeature));
} }
} }
/**
* Generate the data url for a layer.
*
* @param int $layerId The layer id.
* @param Request|null $request The request.
*
* @return string
*
* @SuppressWarnings(PHPMD.Superglobals)
*/
private function generateUrl(int $layerId, ?Request $request = null): string
{
$params = ['layerId' => $layerId];
if ($request && ($filter = $request->getFilter())) {
$params['filter'] = $filter::getName();
$params['values'] = $filter->toRequest();
}
if (isset($GLOBALS['objPage'])) {
$params['context'] = 'page';
$params['contextId'] = $GLOBALS['objPage']->id;
}
return $this->router->generate('leaflet_layer', $params, RouterInterface::ABSOLUTE_URL);
}
} }