mirror of
				https://github.com/Mibew/mibew.git
				synced 2025-11-04 04:15:19 +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\Authentication\AuthenticationManager;
 | 
				
			||||||
use Mibew\Mail\MailerFactory;
 | 
					use Mibew\Mail\MailerFactory;
 | 
				
			||||||
use Mibew\Routing\Router;
 | 
					use Mibew\Routing\Router;
 | 
				
			||||||
 | 
					use Mibew\Routing\Loader\CacheLoader;
 | 
				
			||||||
use Mibew\Routing\Loader\PluginLoader;
 | 
					use Mibew\Routing\Loader\PluginLoader;
 | 
				
			||||||
use Symfony\Component\Config\FileLocator;
 | 
					use Symfony\Component\Config\FileLocator;
 | 
				
			||||||
use Symfony\Component\Config\Loader\LoaderResolver;
 | 
					use Symfony\Component\Config\Loader\LoaderResolver;
 | 
				
			||||||
use Symfony\Component\HttpFoundation\Request;
 | 
					use Symfony\Component\HttpFoundation\Request;
 | 
				
			||||||
use Symfony\Component\Routing\Loader\YamlFileLoader;
 | 
					use Symfony\Component\Routing\Loader\YamlFileLoader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Prepare router
 | 
					// Use custom cache
 | 
				
			||||||
$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
 | 
					 | 
				
			||||||
$cache_driver = new \Stash\Driver\FileSystem();
 | 
					$cache_driver = new \Stash\Driver\FileSystem();
 | 
				
			||||||
$cache_driver->setOptions(array('path' => MIBEW_FS_ROOT . '/cache/stash'));
 | 
					$cache_driver->setOptions(array('path' => MIBEW_FS_ROOT . '/cache/stash'));
 | 
				
			||||||
$cache = new \Stash\Pool($cache_driver);
 | 
					$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);
 | 
					$application->setCache($cache);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Use custom config-dependent mailer factory
 | 
					// Use custom config-dependent mailer factory
 | 
				
			||||||
 | 
				
			|||||||
@ -87,6 +87,11 @@ class PluginController extends AbstractController
 | 
				
			|||||||
            return $this->indexAction($request);
 | 
					            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'));
 | 
					        return $this->redirect($this->generateUrl('plugins'));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -121,6 +126,11 @@ class PluginController extends AbstractController
 | 
				
			|||||||
            return $this->indexAction($request);
 | 
					            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'));
 | 
					        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