SinSquare/silex-doctrine-orm-provider

View on GitHub
src/Sins/Doctrine/DoctrineOrmServiceProvider.php

Summary

Maintainability
D
1 day
Test Coverage
<?php

namespace SinSquare\Doctrine;

use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;
use Doctrine\ORM\Mapping\DefaultNamingStrategy;
use Doctrine\ORM\Mapping\DefaultQuoteStrategy;
use Doctrine\ORM\Mapping\Driver\Driver;
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
use Pimple\Container;
use Pimple\ServiceProviderInterface;

class DoctrineOrmServiceProvider implements ServiceProviderInterface
{
    public function register(Container $app)
    {
        $app['doctrine.orm.em_default_options'] = array(
            'query_cache_driver' => array(
                'type' => 'array',
            ),
            'metadata_cache_driver' => array(
                'type' => 'array',
            ),
            'result_cache_driver' => array(
                'type' => 'array',
            ),
            'hydration_cache_driver' => array(
                'type' => 'array',
            ),
            'connection' => 'default',
            'class_metadata_factory_name' => ClassMetadataFactory::class,
            'default_repository_class' => EntityRepository::class,
            'auto_mapping' => false,
            'hydrators' => array(
                // An array of hydrator names
            ),
            'mappings' => array(
                // An array of mappings, which may be a bundle name or something else
            ),
            'dql' => array(
                // a collection of string functions
                'string_functions' => array(),
                // a collection of numeric functions
                'numeric_functions' => array(),
                // a collection of datetime functions
                'datetime_functions' => array(),
            ),
            // Register SQL Filters in the entity manager
            'filters' => array(
                // An array of filters
            ),
        );

        $app['doctrine.orm.default_options'] = array(
            'default_entity_manager' => null,
            'auto_generate_proxy_classes' => false,
            'proxy_dir' => null,
            'proxy_namespace' => 'Proxies',
            'entity_managers' => array(),
        );

        $app['doctrine.orm.options.initializer'] = $app->protect(function () use ($app) {
            static $initialized = false;

            if ($initialized) {
                return;
            }

            $initialized = true;

            if (!isset($app['doctrine.orm.options'])) {
                $app['doctrine.orm.options'] = $app['doctrine.orm.default_options'];
            } else {
                $app['doctrine.orm.options'] = array_replace($app['doctrine.orm.default_options'], $app['doctrine.orm.options']);
            }

            $tmp = $app['doctrine.orm.options'];
            foreach ($tmp['entity_managers'] as $name => &$options) {
                $options = array_replace($app['doctrine.orm.em_default_options'], $options);

                if (empty($tmp['default_entity_manager'])) {
                    $tmp['default_entity_manager'] = $name;
                    $app['doctrine.orm.default'] = $name;
                } else {
                    $app['doctrine.orm.default'] = $tmp['default_entity_manager'];
                }
            }
            $app['doctrine.orm.options'] = $tmp;
        });

        $app['doctrine.orm.em.factory'] = $app->protect(function ($options) {
        });

        $app['doctrine.orm.em.config.factory'] = $app->protect(function ($options) {
        });

        $app['doctrine.orm.cache.locator'] = $app->protect(function ($cacheName, $options) use ($app) {
            if (isset($options['name'])) {
                $name = $options['name'];
                if (isset($app['doctrine.cache.'.$name])) {
                    return $app['doctrine.cache.'.$name];
                }
                if (isset($app[$name])) {
                    return $app[$name];
                }
                throw new \LogicException(sprintf("There is no cache registered with the name '%s'."));
            }

            $cacheInstanceKey = 'doctrine.orm.cache.instances.'.$cacheName;

            if (isset($app[$cacheInstanceKey])) {
                return $app[$cacheInstanceKey];
            }

            $cache = $app['doctrine.cache.locator']($cacheName, $options);

            return $app[$cacheInstanceKey] = $cache;
        });

        $app['doctrine.orm.strategy.naming'] = function ($app) {
            return new DefaultNamingStrategy();
        };

        $app['doctrine.orm.strategy.quote'] = function ($app) {
            return new DefaultQuoteStrategy();
        };

        $app['doctrine.orm.entity_listener_resolver'] = function ($app) {
            return new DefaultEntityListenerResolver();
        };

        $app['doctrine.orm.repository_factory'] = function ($app) {
            return new DefaultRepositoryFactory();
        };

        $app['doctrine.manager_registry'] = function ($app) {
            return new ManagerRegistry($app);
        };

        //entity manager config
        $app['doctrine.orm.em.config'] = $app->protect(function ($name, $options) use ($app) {
            $config = new Configuration();

            //cache
            $config->setMetadataCacheImpl(
                $app['doctrine.orm.cache.locator']('metadata', $options['metadata_cache_driver'])
            );
            $config->setQueryCacheImpl(
                $app['doctrine.orm.cache.locator']('query', $options['query_cache_driver'])
            );
            $config->setResultCacheImpl(
                $app['doctrine.orm.cache.locator']('result', $options['result_cache_driver'])
            );
            $config->setHydrationCacheImpl(
                $app['doctrine.orm.cache.locator']('hydration', $options['hydration_cache_driver'])
            );

            //proxy
            if (isset($options['proxy_dir'])) {
                $proxyDir = $options['proxy_dir'];
            } else {
                $proxyDir = $app['doctrine.orm.options']['proxy_dir'];
            }
            $config->setProxyDir($proxyDir);

            if (isset($options['proxy_namespace'])) {
                $proxyNamespace = $options['proxy_namespace'];
            } else {
                $proxyNamespace = $app['doctrine.orm.options']['proxy_namespace'];
            }
            $config->setProxyNamespace($proxyNamespace);

            if (isset($options['auto_generate_proxy_classes'])) {
                $autoProxy = $options['auto_generate_proxy_classes'];
            } else {
                $autoProxy = $app['doctrine.orm.options']['auto_generate_proxy_classes'];
            }
            $config->setAutoGenerateProxyClasses($autoProxy);

            //custom hydrator
            $config->setCustomHydrationModes($options['hydrators']);

            //custom functions
            $config->setCustomStringFunctions($options['dql']['string_functions']);
            $config->setCustomNumericFunctions($options['dql']['numeric_functions']);
            $config->setCustomDatetimeFunctions($options['dql']['datetime_functions']);

            //filters
            if (is_array($options['filters']) && count($options['filters'])) {
                foreach ($options['filters'] as $filterName => $filterClass) {
                    $config->addFilter($filterName, $filterClass);
                }
            }

            $config->setClassMetadataFactoryName($options['class_metadata_factory_name']);
            $config->setDefaultRepositoryClassName($options['default_repository_class']);

            $config->setEntityListenerResolver($app['doctrine.orm.entity_listener_resolver']);
            $config->setRepositoryFactory($app['doctrine.orm.repository_factory']);

            $config->setNamingStrategy($app['doctrine.orm.strategy.naming']);
            $config->setQuoteStrategy($app['doctrine.orm.strategy.quote']);

            $chain = new MappingDriverChain();

            foreach ((array) $options['mappings'] as $entity) {
                if (!is_array($entity)) {
                    throw new \InvalidArgumentException(
                        "The 'doctrine.orm.em.options' option 'mappings' should be a nested array."
                    );
                }

                if (isset($entity['alias'])) {
                    $config->addEntityNamespace($entity['alias'], $entity['namespace']);
                }

                $driver = $app['doctrine.orm.mappingdriver.locator']($entity, $config);
                $chain->addDriver($driver, $entity['namespace']);
            }

            $config->setMetadataDriverImpl($chain);

            return $config;
        });

        //mapping driver
        $app['doctrine.orm.mappingdriver.locator'] = $app->protect(function ($options, $config) use ($app) {
            if (!isset($options['type'])) {
                throw new \InvalidArgumentException("Mapping 'type' must be set.");
            }

            $mappingName = 'doctrine.orm.mappingdriver._'.$options['type'];
            if (!isset($app[$mappingName])) {
                throw new \InvalidArgumentException(sprintf('"%s" is not a recognized mapping driver', $options['type']));
            }

            return $app[$mappingName]($options, $config);
        });

        $app['doctrine.orm.mappingdriver._annotation'] = $app->protect(function ($options, Configuration $config) {
            $useSimpleAnnotationReader =
                isset($options['use_simple_annotation_reader'])
                ? (bool) $options['use_simple_annotation_reader']
                : true;

            return $config->newDefaultAnnotationDriver(array($options['path']), $useSimpleAnnotationReader);
        });

        $app['doctrine.orm.em_factory'] = $app->protect(function ($name, $options) use ($app) {
            $config = $app['doctrine.orm.em.config']($name, $options);

            $em = EntityManager::create(
                $app['dbs'][$options['connection']],
                $config,
                $app['dbs.event_manager'][$options['connection']]
            );

            return $app['doctrine.orm.em_factory.postinit']($name, $options, $em);
        });

        $app['doctrine.orm.em_factory.postinit'] = $app->protect(function ($name, $options, $manager) use ($app) {
            //to be able to attach traits, etc
            return $manager;
        });

        //initilazie config
        $app['doctrine.orm.options.initializer']();

        //default entity manager
        $app['doctrine.orm.em'] = function ($app) {
            $name = 'doctrine.orm.em.'.$app['doctrine.orm.options']['default_entity_manager'];

            return $app[$name];
        };

        //named entity managers
        foreach ($app['doctrine.orm.options']['entity_managers'] as $name => $options) {
            $app['doctrine.orm.em.'.$name] = function () use ($app, $name, $options) {
                return $app['doctrine.orm.em_factory']($name, $options);
            };
        }

        //ems container
        $app['doctrine.orm.ems'] = function ($app) {
            $ems = new Container();
            foreach ($app['doctrine.orm.options']['entity_managers'] as $name => $options) {
                $ems[$name] = function () use ($app, $name, $options) {
                    return $app['doctrine.orm.em.'.$name];
                };
            }

            return $ems;
        };
    }
}