mirror of
https://github.com/Mibew/mibew.git
synced 2024-11-15 08:34:11 +03:00
Add routes caching
This commit is contained in:
parent
30fd4bad7c
commit
094139dead
@ -24,27 +24,31 @@ use Mibew\Application;
|
||||
use Mibew\Authentication\AuthenticationManager;
|
||||
use Mibew\Mail\MailerFactory;
|
||||
use Mibew\Routing\Router;
|
||||
use Mibew\Routing\Loader\CacheLoader;
|
||||
use Mibew\Routing\Loader\PluginLoader;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Config\Loader\LoaderResolver;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Loader\YamlFileLoader;
|
||||
|
||||
// Prepare router
|
||||
$file_locator = new FileLocator(array(MIBEW_FS_ROOT));
|
||||
$route_loader = new YamlFileLoader($file_locator);
|
||||
$loader_resolver = new LoaderResolver(array(
|
||||
$route_loader,
|
||||
new PluginLoader(),
|
||||
));
|
||||
$router = new Router($route_loader, 'configs/routing.yml');
|
||||
|
||||
$application = new Application($router, new AuthenticationManager());
|
||||
|
||||
// Use custom files cache
|
||||
// Use custom cache
|
||||
$cache_driver = new \Stash\Driver\FileSystem();
|
||||
$cache_driver->setOptions(array('path' => MIBEW_FS_ROOT . '/cache/stash'));
|
||||
$cache = new \Stash\Pool($cache_driver);
|
||||
|
||||
// The main route loader which loads nothig but works as a cache proxy for other
|
||||
// loaders.
|
||||
$route_loader = new CacheLoader($cache);
|
||||
// Real loaders are attached via the resolver.
|
||||
$loader_resolver = new LoaderResolver(array(
|
||||
$route_loader,
|
||||
new YamlFileLoader(new FileLocator(array(MIBEW_FS_ROOT))),
|
||||
new PluginLoader(),
|
||||
));
|
||||
|
||||
$router = new Router($route_loader, 'configs/routing.yml');
|
||||
|
||||
$application = new Application($router, new AuthenticationManager());
|
||||
$application->setCache($cache);
|
||||
|
||||
// Use custom config-dependent mailer factory
|
||||
|
@ -87,6 +87,11 @@ class PluginController extends AbstractController
|
||||
return $this->indexAction($request);
|
||||
}
|
||||
|
||||
// Plugins can have own routing files and when the plugin becomes
|
||||
// enabled its routes should become enabled too. So the cache is cleared
|
||||
// to make sure the routes set is up to date.
|
||||
$this->getCache()->getItem('routing/resources')->clear();
|
||||
|
||||
return $this->redirect($this->generateUrl('plugins'));
|
||||
}
|
||||
|
||||
@ -121,6 +126,11 @@ class PluginController extends AbstractController
|
||||
return $this->indexAction($request);
|
||||
}
|
||||
|
||||
// Plugins can have own routing files and when the plugin becomes
|
||||
// disabled its routes should become disabled too. So the cache is
|
||||
// cleared to make sure the routes set is up to date.
|
||||
$this->getCache()->getItem('routing/resources')->clear();
|
||||
|
||||
return $this->redirect($this->generateUrl('plugins'));
|
||||
}
|
||||
|
||||
|
181
src/mibew/libs/classes/Mibew/Routing/Loader/CacheLoader.php
Normal file
181
src/mibew/libs/classes/Mibew/Routing/Loader/CacheLoader.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is a part of Mibew Messenger.
|
||||
*
|
||||
* Copyright 2005-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace Mibew\Routing\Loader;
|
||||
|
||||
use Stash\Interfaces\PoolInterface;
|
||||
use Stash\Invalidation;
|
||||
use Symfony\Component\Config\Loader\Loader;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* Loads routes from the cache.
|
||||
*/
|
||||
class CacheLoader extends Loader
|
||||
{
|
||||
/**
|
||||
* @var PoolInterface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* Maximum time in seconds the cache can be stored.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $cacheMaxAge;
|
||||
|
||||
/**
|
||||
* Constructor of the class.
|
||||
*
|
||||
* @param PoolInterface $cache An instance of cache pool.
|
||||
* @param int $max_age Maximum time in seconds the cache can be stored.
|
||||
* Notice that the cache can be invalidated before the max age timeout is
|
||||
* expired.
|
||||
*/
|
||||
public function __construct(PoolInterface $cache, $max_age = 600)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->cacheMaxAge = $max_age;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($resource, $type = null)
|
||||
{
|
||||
if (!is_string($resource)) {
|
||||
// Resources which names are not strings cannot be cached.
|
||||
return $this->import($resource, $type);
|
||||
}
|
||||
|
||||
$key = sprintf('routing/resources/%s/%s/', ($type ?: '-'), $resource);
|
||||
$item = $this->cache->getItem($key);
|
||||
$data = $item->get(Invalidation::VALUE, null);
|
||||
|
||||
if ($item->isMiss()) {
|
||||
// There is no value in the cache. We should read the target file
|
||||
// and cache the result.
|
||||
$item->lock();
|
||||
$collection = $this->import($resource, $type);
|
||||
|
||||
// Store routes and some extra info that needed for cache
|
||||
// invalidation.
|
||||
$item->set(
|
||||
array(
|
||||
'collection' => $this->serializeCollection($collection),
|
||||
// We need current timestamp to invalidate resources
|
||||
// manually if they are changed.
|
||||
'created' => time(),
|
||||
),
|
||||
$this->cacheMaxAge
|
||||
);
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
if (!$data) {
|
||||
// $item->isMiss() returs false but there are no data in the cache.
|
||||
// It seems that another script instance already lock the item and
|
||||
// generate the data. Just read the target file and return actuall
|
||||
// results without any caching.
|
||||
return $this->import($resource, $type);
|
||||
}
|
||||
|
||||
$collection = $this->unserializeCollection($data['collection']);
|
||||
|
||||
// Check if the cache should be invalidated.
|
||||
if (!$this->isCollectionFresh($collection, $data['created'])) {
|
||||
// The collection contains stale resources. The cache should be
|
||||
// cleared and fresh data should be return to the client. The other
|
||||
// call for the "load" method will regenerate the cache.
|
||||
$item->clear();
|
||||
|
||||
return $this->import($resource, $type);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports($resource, $type = null)
|
||||
{
|
||||
// The loader itself can load nothing.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a RoutesCollection instance.
|
||||
*
|
||||
* @param RouteCollection $collection A collection that should be
|
||||
* serialized.
|
||||
* @return string
|
||||
*/
|
||||
protected function serializeCollection(RouteCollection $collection)
|
||||
{
|
||||
return serialize(array(
|
||||
'routes' => $collection->all(),
|
||||
'resources' => $collection->getResources(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserializes a RoutesCollection instance.
|
||||
*
|
||||
* @param string $serialized_collection An output of
|
||||
* {@link CacheLoader::serializeCollection} method.
|
||||
* @return RouteCollection
|
||||
*/
|
||||
protected function unserializeCollection($serialized_collection)
|
||||
{
|
||||
$data = unserialize($serialized_collection);
|
||||
$collection = new RouteCollection();
|
||||
|
||||
foreach ($data['routes'] as $name => $route) {
|
||||
$collection->add($name, $route);
|
||||
}
|
||||
|
||||
foreach ($data['resources'] as $resource) {
|
||||
$collection->addResource($resource);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all resources related with the collection are fresh.
|
||||
*
|
||||
* @param RouteCollection $collection The collection which resources will be
|
||||
* checked.
|
||||
* @param int $timestamp The last time the collection was loaded.
|
||||
* @return boolean True if all resources are fresh and false otherwise.
|
||||
*/
|
||||
protected function isCollectionFresh(RouteCollection $collection, $timestamp)
|
||||
{
|
||||
foreach ($collection->getResources() as $resource) {
|
||||
if (!$resource->isFresh($timestamp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user