[DoctrineBundle] made the ORM integration of DoctrineBundle usable

This commit is contained in:
Jonathan H. Wage 2010-02-20 10:10:18 -05:00 committed by Fabien Potencier
parent 0dcaabfc8c
commit f87f890b7a
14 changed files with 654 additions and 23 deletions

View File

@ -22,11 +22,36 @@ use Symfony\Framework\DoctrineBundle\DependencyInjection\DoctrineExtension;
*
* @package symfony
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class Bundle extends BaseBundle
{
public function buildContainer(ContainerInterface $container)
{
Loader::registerExtension(new DoctrineExtension());
$metadataDirs = array();
$entityDirs = array();
$bundleDirs = $container->getParameter('kernel.bundle_dirs');
foreach ($container->getParameter('kernel.bundles') as $className)
{
$tmp = dirname(str_replace('\\', '/', $className));
$namespace = dirname($tmp);
$class = basename($tmp);
if (isset($bundleDirs[$namespace]))
{
if (is_dir($dir = $bundleDirs[$namespace].'/'.$class.'/Resources/config/doctrine/metadata'))
{
$metadataDirs[] = $dir;
}
if (is_dir($dir = $bundleDirs[$namespace].'/'.$class.'/Entities'))
{
$entityDirs[] = $dir;
}
}
}
$container->setParameter('doctrine.orm.metadata_driver_impl.dirs', $metadataDirs);
$container->setParameter('doctrine.entity_dirs', $entityDirs);
}
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace Symfony\Framework\DoctrineBundle\Command;
use Symfony\Components\Console\Input\InputArgument;
use Symfony\Components\Console\Input\InputOption;
use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Manage the cache clearing of the Doctrine ORM.
*
* @package symfony
* @subpackage console
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class ClearCacheDoctrineCommand extends DoctrineCommand
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('doctrine:clear-cache')
->setDescription('Clear cache from configured query, result and metadata drivers.')
->setAliases(array('doctrine:cc'))
->addOption('query', null, null, 'Clear the query cache.')
->addOption('metadata', null, null, 'Clear the metadata cache.')
->addOption('result', null, null, 'Clear the result cache.')
->addOption('id', null, null, 'Clear a cache entry by its id.')
->addOption('regex', null, null, 'Clear cache entries that match a regular expression.')
->addOption('prefix', null, null, 'Clear cache entries that match a prefix.')
->addOption('suffix', null, null, 'Clear cache entries that match a suffix.')
;
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$options = $this->buildDoctrineCliTaskOptions($input, array(
'query', 'metadata', 'result', 'id', 'regex', 'prefix', 'suffix'
));
$this->runDoctrineCliTask('orm:clear-cache', $options);
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace Symfony\Framework\DoctrineBundle\Command;
use Symfony\Components\Console\Input\InputArgument;
use Symfony\Components\Console\Input\InputOption;
use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Convert Doctrine ORM metadata mapping information between the various supported
* formats.
*
* @package symfony
* @subpackage console
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class ConvertMappingDoctrineCommand extends DoctrineCommand
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('doctrine:convert-mapping')
->setDescription('Convert mapping information between supported formats.')
->addOption('from', null, null, 'The source to convert from.')
->addOption('to', null, null, 'The type of mapping to convert to.')
->addOption('dest', null, null, 'Where to output the converted source.')
;
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$options = $this->buildDoctrineCliTaskOptions($input, array(
'from', 'to', 'dest'
));
$this->runDoctrineCliTask('orm:convert-mapping', $options);
}
}

View File

@ -10,6 +10,7 @@ use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
@ -21,7 +22,7 @@ use Doctrine\Common\Cli\Configuration;
*/
/**
*
* Base class for Doctrine consol commands to extend from.
*
* @package symfony
* @subpackage console
@ -29,4 +30,46 @@ use Doctrine\Common\Cli\Configuration;
*/
abstract class DoctrineCommand extends Command
{
}
protected $cli;
protected function getDoctrineCli()
{
if ($this->cli === null)
{
$configuration = new Configuration();
$configuration->setAttribute('em', $this->container->getDoctrine_Orm_EntityManagerService());
$this->cli = new DoctrineCliController($configuration);
}
return $this->cli;
}
protected function runDoctrineCliTask($name, $options = array())
{
$builtOptions = array();
foreach ($options as $key => $value)
{
if ($value === null)
{
$builtOptions[] = sprintf('--%s', $key);
}
else
{
$builtOptions[] = sprintf('--%s=%s', $key, $value);
}
}
return $this->getDoctrineCli()->run(array_merge(array('doctrine', $name), $builtOptions));
}
public function buildDoctrineCliTaskOptions(InputInterface $input, array $options)
{
$taskOptions = array();
foreach ($options as $option)
{
if ($value = $input->getOption($option))
{
$options[$option] = $value;
}
}
return $options;
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace Symfony\Framework\DoctrineBundle\Command;
use Symfony\Components\Console\Input\InputArgument;
use Symfony\Components\Console\Input\InputOption;
use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Ensure the Doctrine ORM is configured properly for a production environment.
*
* @package symfony
* @subpackage console
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class EnsureProductionSettingsDoctrineCommand extends DoctrineCommand
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('doctrine:ensure-production-settings')
->setDescription('Verify that Doctrine is properly configured for a production environment.')
;
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->runDoctrineCliTask('orm:ensure-production-settings');
}
}

View File

@ -8,8 +8,6 @@ use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
@ -21,7 +19,7 @@ use Doctrine\Common\Cli\CliController as DoctrineCliController;
*/
/**
*
* Generate the Doctrine ORM entity proxies to your cache directory.
*
* @package symfony
* @subpackage console
@ -36,6 +34,7 @@ class GenerateProxiesDoctrineCommand extends DoctrineCommand
{
$this
->setName('doctrine:generate-proxies')
->setDescription('Generates proxy classes for entity classes.')
;
}
@ -44,9 +43,6 @@ class GenerateProxiesDoctrineCommand extends DoctrineCommand
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$configuration = new Configuration();
$configuration->setAttribute('em', $this->container->getDoctrine_Orm_ManagerService());
$dirs = array();
$bundleDirs = $this->container->getKernelService()->getBundleDirs();
foreach ($this->container->getKernelService()->getBundles() as $bundle)
@ -55,7 +51,7 @@ class GenerateProxiesDoctrineCommand extends DoctrineCommand
$namespace = dirname($tmp);
$class = basename($tmp);
if (isset($bundleDirs[$namespace]) && is_dir($dir = $bundleDirs[$namespace].'/'.$class.'/Model/Doctrine'))
if (isset($bundleDirs[$namespace]) && is_dir($dir = $bundleDirs[$namespace].'/'.$class.'/Entities'))
{
$dirs[] = $dir;
}
@ -66,10 +62,9 @@ class GenerateProxiesDoctrineCommand extends DoctrineCommand
mkdir($dir, 0777, true);
}
$cli = new DoctrineCliController($configuration);
foreach ($dirs as $dir)
{
$cli->run(array('doctrine', 'orm:generate-proxies', '--class-dir='.$dir));
$this->runDoctrineCliTask('orm:generate-proxies', array('class-dir' => $dir));
}
}
}
}

View File

@ -0,0 +1,157 @@
<?php
namespace Symfony\Framework\DoctrineBundle\Command;
use Symfony\Components\Console\Input\InputArgument;
use Symfony\Components\Console\Input\InputOption;
use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Symfony\Framework\WebBundle\Util\Finder;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Internal\CommitOrderCalculator;
/*
* This file is part of the symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Load data fixtures from bundles
*
* @package symfony
* @subpackage console
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class LoadDataFixturesDoctrineCommand extends DoctrineCommand
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('doctrine:load-data-fixtures')
->setDescription('Load data fixtures to your database.')
->addOption('dir_or_file', null, null, 'The directory or file to load data fixtures from.')
->addOption('append', null, InputOption::PARAMETER_OPTIONAL, 'Whether or not to append the data fixtures.', false)
;
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$em = $this->container->getDoctrine_ORM_EntityManagerService();
if (!$input->getOption('append'))
{
$classes = array();
$metadatas = $em->getMetadataFactory()->getAllMetadata();
foreach ($metadatas as $metadata)
{
if (!$metadata->isMappedSuperclass)
{
$classes[] = $metadata;
}
}
$cmf = $em->getMetadataFactory();
$classes = $this->getCommitOrder($em, $classes);
for ($i = count($classes) - 1; $i >= 0; --$i)
{
$class = $classes[$i];
if ($cmf->hasMetadataFor($class->name))
{
try {
$em->createQuery('DELETE FROM '.$class->name.' a')->execute();
} catch (Exception $e) {}
}
}
}
$dirOrFile = $input->getOption('dir_or_file');
if ($dirOrFile)
{
$paths = $dirOrFile;
} else {
$paths = array();
$bundleDirs = $this->container->getKernelService()->getBundleDirs();
foreach ($this->container->getKernelService()->getBundles() as $bundle)
{
$tmp = dirname(str_replace('\\', '/', get_class($bundle)));
$namespace = dirname($tmp);
$class = basename($tmp);
if (isset($bundleDirs[$namespace]) && is_dir($dir = $bundleDirs[$namespace].'/'.$class.'/Resources/data/fixtures/doctrine'))
{
$paths[] = $dir;
}
}
}
$files = array();
foreach ($paths as $path)
{
if (is_dir($path))
{
$found = Finder::type('file')
->name('*.php')
->in($path);
} else {
$found = array($path);
}
$files = array_merge($files, $found);
}
$files = array_unique($files);
foreach ($files as $file)
{
$before = array_keys(get_defined_vars());
include($file);
$after = array_keys(get_defined_vars());
$new = array_diff($after, $before);
$entities = array_values($new);
unset($entities[array_search('before', $entities)]);
foreach ($entities as $entity) {
$em->persist($$entity);
}
$em->flush();
}
}
protected function getCommitOrder(EntityManager $em, array $classes)
{
$calc = new CommitOrderCalculator;
foreach ($classes as $class)
{
$calc->addClass($class);
foreach ($class->associationMappings as $assoc)
{
if ($assoc->isOwningSide) {
$targetClass = $em->getClassMetadata($assoc->targetEntityName);
if ( ! $calc->hasClass($targetClass->name)) {
$calc->addClass($targetClass);
}
// add dependency ($targetClass before $class)
$calc->addDependency($targetClass, $class);
}
}
}
return $calc->getCommitOrder();
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace Symfony\Framework\DoctrineBundle\Command;
use Symfony\Components\Console\Input\InputArgument;
use Symfony\Components\Console\Input\InputOption;
use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Execute a Doctrine DQL query and output the results
*
* @package symfony
* @subpackage console
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class RunDqlDoctrineCommand extends DoctrineCommand
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('doctrine:run-dql')
->setDescription('Executes arbitrary DQL directly from the command line.')
->addOption('dql', null, null, 'The DQL query to run.')
->addOption('depth', null, null, 'The depth to output the data to.')
;
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$options = $this->buildDoctrineCliTaskOptions($input, array(
'dql', 'depth'
));
$this->runDoctrineCliTask('orm:run-dql', $options);
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace Symfony\Framework\DoctrineBundle\Command;
use Symfony\Components\Console\Input\InputArgument;
use Symfony\Components\Console\Input\InputOption;
use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Execute a SQL query and output the results
*
* @package symfony
* @subpackage console
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class RunSqlDoctrineCommand extends DoctrineCommand
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('doctrine:run-sql')
->setDescription('Executes arbitrary SQL from a file or directly from the command line.')
->addOption('sql', null, null, 'The SQL query to run.')
->addOption('file', null, null, 'Path to a SQL file to run.')
->addOption('depth', null, null, 'The depth to output the data to.')
;
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$options = $this->buildDoctrineCliTaskOptions($input, array(
'sql', 'file', 'depth'
));
$this->runDoctrineCliTask('dbal:run-sql', $options);
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace Symfony\Framework\DoctrineBundle\Command;
use Symfony\Components\Console\Input\InputArgument;
use Symfony\Components\Console\Input\InputOption;
use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Create, drop, and update your Doctrine ORM schema in the DBMS.
*
* @package symfony
* @subpackage console
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class SchemaToolDoctrineCommand extends DoctrineCommand
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('doctrine:schema-tool')
->setDescription('Processes the schema and either apply it directly on EntityManager or generate the SQL output.')
->addOption('create', null, null, 'Create your database schema.')
->addOption('drop', null, null, 'Drop your database schema.')
->addOption('update', null, null, 'Update your database schema and add anything that is not in your database but exists in your schema.')
->addOption('complete-update', null, null, 'Complete update and drop anything that is not in your schema.')
->addOption('re-create', null, null, 'Drop and re-create your database schema.')
->addOption('dump-sql', null, null, 'Dump the SQL instead of executing it.')
;
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$options = $this->buildDoctrineCliTaskOptions($input, array(
'create', 'drop', 'update', 'complete-update', 're-create', 'dump-sql'
));
$entityDirs = $this->container->getParameter('doctrine.entity_dirs');
$options['class-dir'] = implode(', ', $entityDirs);
$this->runDoctrineCliTask('orm:schema-tool', $options);
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace Symfony\Framework\DoctrineBundle\Command;
use Symfony\Components\Console\Input\InputArgument;
use Symfony\Components\Console\Input\InputOption;
use Symfony\Components\Console\Input\InputInterface;
use Symfony\Components\Console\Output\OutputInterface;
use Symfony\Components\Console\Output\Output;
use Symfony\Framework\WebBundle\Util\Filesystem;
use Doctrine\Common\Cli\Configuration;
use Doctrine\Common\Cli\CliController as DoctrineCliController;
/*
* This file is part of the symfony framework.
*
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
/**
* Check what version of the Doctrine ORM being used.
*
* @package symfony
* @subpackage console
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class VersionDoctrineCommand extends DoctrineCommand
{
/**
* @see Command
*/
protected function configure()
{
$this
->setName('doctrine:version')
->setDescription('Displays the current installed Doctrine version.')
;
}
/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->runDoctrineCliTask('orm:version');
}
}

View File

@ -23,18 +23,18 @@ use Symfony\Components\RequestHandler\Exception\NotFoundHttpException;
*/
class DoctrineController extends Controller
{
protected function getManager()
protected function getEntityManager()
{
return $this->container->getDoctrine_ORM_ManagerService();
return $this->container->getDoctrine_ORM_EntityManagerService();
}
public function createQueryBuilder()
{
return $this->getManager()->createQueryBuilder();
return $this->getEntityManager()->createQueryBuilder();
}
public function createQuery($dql = '')
{
return $this->getManager()->createQuery($dql);
return $this->getEntityManager()->createQuery($dql);
}
}

View File

@ -97,6 +97,14 @@ class DoctrineExtension extends LoaderExtension
$loader = new XmlFileLoader(__DIR__.'/../Resources/config');
$configuration->merge($loader->load($this->resources['orm']));
foreach (array('entity_manager.class', 'metadata_driver_impl.class', 'cache.class') as $key)
{
if (isset($config[$key]))
{
$configuration->setParameter('doctrine.orm.'.$key, $config[$key]);
}
}
return $configuration;
}

View File

@ -5,25 +5,31 @@
xsi:schemaLocation="http://www.symfony-project.org/schema/dic/services http://www.symfony-project.org/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="doctrine.entity_manager.class">Doctrine\ORM\EntityManager</parameter>
<parameter key="doctrine.orm.entity_manager.class">Doctrine\ORM\EntityManager</parameter>
<parameter key="doctrine.orm.metadata_driver_impl.class">Doctrine\ORM\Mapping\Driver\XmlDriver</parameter>
<parameter key="doctrine.orm.cache.class">Doctrine\Common\Cache\ArrayCache</parameter>
</parameters>
<services>
<service id="doctrine.orm.manager" class="%doctrine.entity_manager.class%" constructor="create">
<service id="doctrine.orm.entity_manager" class="%doctrine.orm.entity_manager.class%" constructor="create">
<argument type="service" id="doctrine.dbal.connection" />
<argument type="service" id="doctrine.orm.configuration" />
</service>
<service id="doctrine.orm.metadata_driver_impl" class="%doctrine.orm.metadata_driver_impl.class%">
<argument>%doctrine.orm.metadata_driver_impl.dirs%</argument>
</service>
<service id="doctrine.orm.cache" class="%doctrine.orm.cache.class%" />
<service id="doctrine.orm.configuration" class="Doctrine\ORM\Configuration">
<!--
<call method="setMetadataCacheImpl"><argument type="service" id="doctrine.orm.cache" /></call>
<call method="setQueryCacheImpl"><argument type="service" id="doctrine.orm.cache" /></call>
//-->
<call method="setResultCacheImpl"><argument type="service" id="doctrine.orm.cache" /></call>
<call method="setMetadataDriverImpl"><argument type="service" id="doctrine.orm.metadata_driver_impl" /></call>
<call method="setProxyDir"><argument>%kernel.cache_dir%/doctrine/Proxies</argument></call>
<call method="setProxyNamespace"><argument>Proxies</argument></call>
<call method="setAutoGenerateProxyClasses"><argument>true</argument></call>
</service>
<service id="doctrine.orm.cache" class="Doctrine\Common\Cache\ApcCache" />
</services>
</container>