SinSquare/silex-doctrine-cache-provider

View on GitHub
src/Sins/Cache/DoctrineCacheServiceProvider.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

namespace SinSquare\Cache;

use Doctrine\Common\Cache\ApcCache;
use Doctrine\Common\Cache\ApcuCache;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\ChainCache;
use Doctrine\Common\Cache\FilesystemCache;
use Doctrine\Common\Cache\MemcacheCache;
use Doctrine\Common\Cache\MemcachedCache;
use Doctrine\Common\Cache\PhpFileCache;
use Doctrine\Common\Cache\VoidCache;
use Pimple\Container;
use Pimple\ServiceProviderInterface;

class DoctrineCacheServiceProvider implements ServiceProviderInterface
{
    public function register(Container $app)
    {
        //initialize and validate options
        $app['doctrine.cache.options.initializer'] = $app->protect(function () use ($app) {
            static $initialized = false;

            if ($initialized) {
                return;
            }

            $initialized = true;

            if (!isset($app['doctrine.cache.options'])) {
                return;
            }

            $tmp = $app['doctrine.cache.options'];

            if (!is_array($tmp['providers'])) {
                throw new \Exception("'doctrine.cache.options => providers' not set or not array, can't initialize!");
            } else {
                foreach ($tmp['providers'] as $name => &$options) {
                    if (!is_array($options)) {
                        throw new \Exception("'doctrine.cache.options => providers => {$name}' not set or not array, can't initialize!");
                    } elseif (!isset($options['type']) || !is_string($options['type'])) {
                        throw new \Exception("'doctrine.cache.options => providers => {$name} => type' not set or not string, can't initialize!");
                    }
                }
            }

            if (!isset($tmp['aliases'])) {
                $tmp['aliases'] = array();
            } elseif (!is_array($tmp['aliases'])) {
                throw new \Exception("'doctrine.cache.options => aliases' not array, can't initialize!");
            } else {
                foreach ($tmp['aliases'] as $name => $alias) {
                    if (!is_string($name)) {
                        throw new \Exception("'doctrine.cache.options => aliases' contains not string name, can't initialize!");
                    } elseif (!is_string($alias)) {
                        throw new \Exception("'doctrine.cache.options => aliases' contains not string alias, can't initialize!");
                    } elseif (!isset($tmp['providers'][$name])) {
                        throw new \Exception("'doctrine.cache.options => aliases => {$name}' no provider found, can't initialize!");
                    }
                }
            }

            $app['doctrine.cache.options'] = $tmp;
        });

        //cache locator
        $app['doctrine.cache.locator'] = $app->protect(function ($cacheName, $options) use ($app) {
            if (!isset($options['type'])) {
                throw new \RuntimeException("No type specified for '{$cacheName}'");
            }

            $cache = $app['doctrine.cache.factory']($options);

            if (isset($options['namespace']) && $cache instanceof CacheProvider) {
                $cache->setNamespace($options['namespace']);
            }

            return $cache;
        });

        $app['doctrine.cache.factory.apc'] = $app->protect(function ($cacheOptions) {
            return new ApcCache();
        });

        $app['doctrine.cache.factory.apcu'] = $app->protect(function ($cacheOptions) {
            return new ApcuCache();
        });

        $app['doctrine.cache.factory.array'] = $app->protect(function ($cacheOptions) {
            return new ArrayCache();
        });

        $app['doctrine.cache.factory.chain'] = $app->protect(function ($cacheOptions) use ($app) {
            if (empty($cacheOptions['caches']) || !is_array($cacheOptions['caches'])) {
                throw new \RuntimeException('Host and port options need to be specified for memcache cache');
            }

            $caches = array();

            foreach ($cacheOptions['caches'] as $cacheName) {
                $caches[] = $app['doctrine.cache.'.$cacheName];
            }

            return new ChainCache($caches);
        });

        $app['doctrine.cache.factory.filesystem'] = $app->protect(function ($cacheOptions) {
            
            if (empty($cacheOptions['directory'])) {
                throw new \RuntimeException('FilesystemCache directory not defined');
            }

            $directory = $cacheOptions['directory'];
            $extension = empty($cacheOptions['extension']) ? FilesystemCache::EXTENSION : $cacheOptions['extension'];
            $umask = empty($cacheOptions['umask']) ? 0002 : $cacheOptions['umask'];

            return new FilesystemCache($directory, $extension, $umask);
        });

        $app['doctrine.cache.factory.backing_memcache'] = $app->protect(function () {
            return new \Memcache();
        });

        $app['doctrine.cache.factory.memcache'] = $app->protect(function ($cacheOptions) {
            if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
                throw new \RuntimeException('Host and port options need to be specified for memcache cache');
            }

            /** @var \Memcache $memcache */
            $memcache = $app['doctrine.cache.factory.backing_memcache']();
            $memcache->connect($cacheOptions['host'], $cacheOptions['port']);

            $cache = new MemcacheCache();
            $cache->setMemcache($memcache);

            return $cache;
        });

        $app['doctrine.cache.factory.backing_memcached'] = $app->protect(function () {
            return new \Memcached();
        });

        $app['doctrine.cache.factory.memcached'] = $app->protect(function ($cacheOptions) {
            if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
                throw new \RuntimeException('Host and port options need to be specified for memcached cache');
            }

            /** @var \Memcached $memcached */
            $memcached = $app['doctrine.cache.factory.backing_memcached']();
            $memcached->addServer($cacheOptions['host'], $cacheOptions['port']);

            $cache = new MemcachedCache();
            $cache->setMemcached($memcached);

            return $cache;
        });

        $app['doctrine.cache.factory.phpfile'] = $app->protect(function ($cacheOptions) {

            if (empty($cacheOptions['directory'])) {
                throw new \RuntimeException('FilesystemCache directory not defined');
            }

            $directory = $cacheOptions['directory'];
            $extension = empty($cacheOptions['extension']) ? FilesystemCache::EXTENSION : $cacheOptions['extension'];
            $umask = empty($cacheOptions['umask']) ? 0002 : $cacheOptions['umask'];
            
            return new PhpFileCache($directory, $extension, $umask);
        });

        $app['doctrine.cache.factory.void'] = $app->protect(function ($cacheOptions) {
            return new VoidCache();
        });

        $app['doctrine.cache.factory'] = $app->protect(function ($cacheOptions) use ($app) {
            $driver = $cacheOptions['type'];

            $cacheFactoryKey = 'doctrine.cache.factory.'.$driver;

            if (!isset($app[$cacheFactoryKey])) {
                throw new \RuntimeException("Factory '{$cacheFactoryKey}' for cache type '$driver' not defined (is it spelled correctly?)");
            }

            return $app[$cacheFactoryKey]($cacheOptions);
        });

        //initilazie cache config
        $app['doctrine.cache.options.initializer']();
        if(empty($app['doctrine.cache.options'])) {
            return;
        }
        foreach ($app['doctrine.cache.options']['aliases'] as $name => $alias) {
            $options = $app['doctrine.cache.options']['providers'][$name];
            if (is_array($options)) {
                $app[$alias] = function ($app) use ($name) {
                    $cache = $app['doctrine.caches'][$name];

                    return $cache;
                };
            }
        }
        //initilaize caches
        foreach ($app['doctrine.cache.options']['providers'] as $name => $options) {
            $app['doctrine.cache.'.$name] = function () use ($app, $name, $options) {
                return $app['doctrine.cache.locator']($name, $options);
            };
        }
        //cache container
        $app['doctrine.caches'] = function ($app) {
            $caches = new Container();

            foreach ($app['doctrine.cache.options']['providers'] as $name => $options) {
                $caches[$name] = function () use ($app, $name) {
                    return $app['doctrine.cache.'.$name];
                };
            }

            return $caches;
        };
    }
}