);
}
+ /**
+ * Modify the CiviCRM container - add new services, parameters, extensions, etc.
+ *
+ * @code
+ * use Symfony\Component\Config\Resource\FileResource;
+ * use Symfony\Component\DependencyInjection\Definition;
+ *
+ * function mymodule_civicrm_container($container) {
+ * $container->addResource(new FileResource(__FILE__));
+ * $container->setDefinition('mysvc', new Definition('My\Class', array()));
+ * }
+ * @endcode
+ *
+ * Tip: The container configuration will be compiled/cached. The default cache
+ * behavior is aggressive. When you first implement the hook, be sure to
+ * flush the cache. Additionally, you should relax caching during development.
+ * In `civicrm.settings.php`, set define('CIVICRM_CONTAINER_CACHE', 'auto').
+ *
+ * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+ * @see http://symfony.com/doc/current/components/dependency_injection/index.html
+ */
+ public static function container(\Symfony\Component\DependencyInjection\ContainerBuilder $container) {
+ self::singleton()->invoke(1, $container, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_container');
+ }
+
/**
* @param array <CRM_Core_FileSearchInterface> $fileSearches
* @return mixed
* @return bool
*/
public static function isInUpgradeMode() {
- $args = explode('/', $_GET['q']);
+ $args = explode('/', CRM_Utils_Array::value('q', $_GET));
$upgradeInProcess = CRM_Core_Session::singleton()->get('isUpgradePending');
if ((isset($args[1]) && $args[1] == 'upgrade') || $upgradeInProcess) {
return TRUE;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\ORM\Tools\Setup;
+use Symfony\Component\Config\ConfigCache;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
+use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
// TODO use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
public static function singleton($reset = FALSE) {
if ($reset || self::$singleton === NULL) {
$c = new self();
- self::$singleton = $c->createContainer();
+ self::$singleton = $c->loadContainer();
}
return self::$singleton;
}
/**
+ * Find a cached container definition or construct a new one.
+ *
+ * There are many weird contexts in which Civi initializes (eg different
+ * variations of multitenancy and different permutations of CMS/CRM bootstrap),
+ * and hook_container may fire a bit differently in each context. To mitigate
+ * risk of leaks between environments, we compute a unique envID
+ * (md5(DB_NAME, HTTP_HOST, SCRIPT_FILENAME, etc)) and use separate caches for
+ * each (eg "templates_c/CachedCiviContainer.$ENVID.php").
+ *
+ * Constants:
+ * - CIVICRM_CONTAINER_CACHE -- 'always' [default], 'never', 'auto'
+ * - CIVICRM_DSN
+ * - CIVICRM_DOMAIN_ID
+ * - CIVICRM_TEMPLATE_COMPILEDIR
+ *
+ * @return ContainerInterface
+ */
+ public function loadContainer() {
+ // Note: The container's raison d'etre is to manage construction of other
+ // services. Consequently, we assume a minimal service available -- the classloader
+ // has been setup, and civicrm.settings.php is loaded, but nothing else works.
+
+ $cacheMode = defined('CIVICRM_CONTAINER_CACHE') ? CIVICRM_CONTAINER_CACHE : 'always';
+
+ // In pre-installation environments, don't bother with caching.
+ if (!defined('CIVICRM_TEMPLATE_COMPILEDIR') || !defined('CIVICRM_DSN') || $cacheMode === 'never' || \CRM_Utils_System::isInUpgradeMode()) {
+ return $this->createContainer();
+ }
+
+ $envId = md5(implode(\CRM_Core_DAO::VALUE_SEPARATOR, array(
+ defined('CIVICRM_DOMAIN_ID') ? CIVICRM_DOMAIN_ID : 1, // e.g. one database, multi URL
+ parse_url(CIVICRM_DSN, PHP_URL_PATH), // e.g. one codebase, multi database
+ \CRM_Utils_Array::value('SCRIPT_FILENAME', $_SERVER, ''), // e.g. CMS vs extern vs installer
+ \CRM_Utils_Array::value('HTTP_HOST', $_SERVER, ''), // e.g. name-based vhosts
+ \CRM_Utils_Array::value('SERVER_PORT', $_SERVER, ''), // e.g. port-based vhosts
+ // Depending on deployment arch, these signals *could* be redundant, but who cares?
+ )));
+ $file = CIVICRM_TEMPLATE_COMPILEDIR . "/CachedCiviContainer.{$envId}.php";
+ $containerConfigCache = new ConfigCache($file, $cacheMode === 'auto');
+
+ if (!$containerConfigCache->isFresh()) {
+ $containerBuilder = $this->createContainer();
+ $containerBuilder->compile();
+ $dumper = new PhpDumper($containerBuilder);
+ $containerConfigCache->write(
+ $dumper->dump(array('class' => 'CachedCiviContainer')),
+ $containerBuilder->getResources()
+ );
+ }
+
+ require_once $file;
+ $c = new \CachedCiviContainer();
+ $c->set('service_container', $c);
+ return $c;
+ }
+
+ /**
+ * Construct a new container.
+ *
* @var ContainerBuilder
* @return \Symfony\Component\DependencyInjection\ContainerBuilder
*/
public function createContainer() {
$civicrm_base_path = dirname(dirname(__DIR__));
$container = new ContainerBuilder();
+ $container->addCompilerPass(new RegisterListenersPass('dispatcher'));
+ $container->addObjectResource($this);
$container->setParameter('civicrm_base_path', $civicrm_base_path);
- $container->set(self::SELF, $this);
+ //$container->set(self::SELF, $this);
+ $container->setDefinition(self::SELF, new Definition(
+ 'Civi\Core\Container',
+ array()
+ ));
// TODO Move configuration to an external file; define caching structure
// if (empty($configDirectories)) {
// }
$container->setDefinition('lockManager', new Definition(
- '\Civi\Core\Lock\LockManager',
+ 'Civi\Core\Lock\LockManager',
array()
))
->setFactoryService(self::SELF)->setFactoryMethod('createLockManager');
$container->setDefinition('angular', new Definition(
- '\Civi\Angular\Manager',
+ 'Civi\Angular\Manager',
array()
))
->setFactoryService(self::SELF)->setFactoryMethod('createAngularManager');
$container->setDefinition('dispatcher', new Definition(
- '\Symfony\Component\EventDispatcher\EventDispatcher',
- array()
+ 'Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher',
+ array(new Reference('service_container'))
))
->setFactoryService(self::SELF)->setFactoryMethod('createEventDispatcher');
$container->setDefinition('magic_function_provider', new Definition(
- '\Civi\API\Provider\MagicFunctionProvider',
+ 'Civi\API\Provider\MagicFunctionProvider',
array()
));
$container->setDefinition('civi_api_kernel', new Definition(
- '\Civi\API\Kernel',
+ 'Civi\API\Kernel',
array(new Reference('dispatcher'), new Reference('magic_function_provider'))
))
->setFactoryService(self::SELF)->setFactoryMethod('createApiKernel');
$container->setDefinition('cxn_reg_client', new Definition(
- '\Civi\Cxn\Rpc\RegistrationClient',
+ 'Civi\Cxn\Rpc\RegistrationClient',
array()
))
->setFactoryClass('CRM_Cxn_BAO_Cxn')->setFactoryMethod('createRegistrationClient');
->setFactoryClass($class)->setFactoryMethod('singleton');
}
+ \CRM_Utils_Hook::container($container);
+
return $container;
}
}
/**
+ * @param ContainerInterface $container
* @return \Symfony\Component\EventDispatcher\EventDispatcher
*/
- public function createEventDispatcher() {
- $dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
+ public function createEventDispatcher($container) {
+ $dispatcher = new ContainerAwareEventDispatcher($container);
$dispatcher->addListener('hook_civicrm_post::Activity', array('\Civi\CCase\Events', 'fireCaseChange'));
$dispatcher->addListener('hook_civicrm_post::Case', array('\Civi\CCase\Events', 'fireCaseChange'));
$dispatcher->addListener('hook_civicrm_caseChange', array('\Civi\CCase\Events', 'delegateToXmlListeners'));
},
"require": {
"dompdf/dompdf" : "0.6.*",
- "symfony/dependency-injection": "2.3.*",
- "symfony/event-dispatcher": "2.3.*",
- "symfony/process": "2.3.*",
- "psr/log": "~1.0.0",
- "symfony/finder": "2.3.*",
+ "symfony/config": "~2.5.0",
+ "symfony/dependency-injection": "~2.5.0",
+ "symfony/event-dispatcher": "~2.5.0",
+ "symfony/process": "~2.5.0",
+ "psr/log": "1.0.0",
+ "symfony/finder": "~2.5.0",
"totten/ca-config": "~13.02",
"civicrm/civicrm-cxn-rpc": "~0.15.07.27"
},
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "94145c3d8822e929bea514a67dd54f15",
+ "hash": "7ae864fa67ed95c56a70091935a19c37",
"packages": [
{
"name": "civicrm/civicrm-cxn-rpc",
],
"time": "2012-12-21 11:40:51"
},
+ {
+ "name": "symfony/config",
+ "version": "v2.5.12",
+ "target-dir": "Symfony/Component/Config",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Config.git",
+ "reference": "c7309e33b719433d5cf3845d0b5b9608609d8c8e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Config/zipball/c7309e33b719433d5cf3845d0b5b9608609d8c8e",
+ "reference": "c7309e33b719433d5cf3845d0b5b9608609d8c8e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "symfony/filesystem": "~2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.5-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Config\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ },
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "description": "Symfony Config Component",
+ "homepage": "http://symfony.com",
+ "time": "2015-01-03 08:01:13"
+ },
{
"name": "symfony/dependency-injection",
- "version": "v2.3.23",
+ "version": "v2.5.12",
"target-dir": "Symfony/Component/DependencyInjection",
"source": {
"type": "git",
"url": "https://github.com/symfony/DependencyInjection.git",
- "reference": "f165ee0e0b3522b5158def22622b2f171a8ecd59"
+ "reference": "c42aee05b466cc9c66b87ddf7d263402befb6962"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/f165ee0e0b3522b5158def22622b2f171a8ecd59",
- "reference": "f165ee0e0b3522b5158def22622b2f171a8ecd59",
+ "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/c42aee05b466cc9c66b87ddf7d263402befb6962",
+ "reference": "c42aee05b466cc9c66b87ddf7d263402befb6962",
"shasum": ""
},
"require": {
},
"require-dev": {
"symfony/config": "~2.2",
- "symfony/yaml": "~2.0"
+ "symfony/expression-language": "~2.4,>=2.4.10",
+ "symfony/yaml": "~2.1"
},
"suggest": {
"symfony/config": "",
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.5-dev"
}
},
"autoload": {
],
"description": "Symfony DependencyInjection Component",
"homepage": "http://symfony.com",
- "time": "2014-12-02 19:42:47"
+ "time": "2015-01-25 04:37:39"
},
{
"name": "symfony/event-dispatcher",
- "version": "v2.3.23",
+ "version": "v2.5.12",
"target-dir": "Symfony/Component/EventDispatcher",
"source": {
"type": "git",
"url": "https://github.com/symfony/EventDispatcher.git",
- "reference": "36a40695d94e948d7a85347db0b12ba446c400fa"
+ "reference": "af6eb6a9a1a3b411facfd8e7e3f82a6be7919c04"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/36a40695d94e948d7a85347db0b12ba446c400fa",
- "reference": "36a40695d94e948d7a85347db0b12ba446c400fa",
+ "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/af6eb6a9a1a3b411facfd8e7e3f82a6be7919c04",
+ "reference": "af6eb6a9a1a3b411facfd8e7e3f82a6be7919c04",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
- "symfony/dependency-injection": "~2.0"
+ "psr/log": "~1.0",
+ "symfony/config": "~2.0,>=2.0.5",
+ "symfony/dependency-injection": "~2.0,>=2.0.5,<2.6.0",
+ "symfony/stopwatch": "~2.3"
},
"suggest": {
"symfony/dependency-injection": "",
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.5-dev"
}
},
"autoload": {
],
"description": "Symfony EventDispatcher Component",
"homepage": "http://symfony.com",
- "time": "2014-11-30 13:33:44"
+ "time": "2015-01-29 18:20:43"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v2.7.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Filesystem.git",
+ "reference": "2d7b2ddaf3f548f4292df49a99d19c853d43f0b8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Filesystem/zipball/2d7b2ddaf3f548f4292df49a99d19c853d43f0b8",
+ "reference": "2d7b2ddaf3f548f4292df49a99d19c853d43f0b8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "~2.7"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Filesystem Component",
+ "homepage": "https://symfony.com",
+ "time": "2015-07-09 16:07:40"
},
{
"name": "symfony/finder",
- "version": "v2.3.23",
+ "version": "v2.5.12",
"target-dir": "Symfony/Component/Finder",
"source": {
"type": "git",
"url": "https://github.com/symfony/Finder.git",
- "reference": "d533aea3400dc463c4d0ba9c3ecf40bd80d49dbd"
+ "reference": "e527ebf47ff912a45e148b7d0b107b80ec0b3cc2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Finder/zipball/d533aea3400dc463c4d0ba9c3ecf40bd80d49dbd",
- "reference": "d533aea3400dc463c4d0ba9c3ecf40bd80d49dbd",
+ "url": "https://api.github.com/repos/symfony/Finder/zipball/e527ebf47ff912a45e148b7d0b107b80ec0b3cc2",
+ "reference": "e527ebf47ff912a45e148b7d0b107b80ec0b3cc2",
"shasum": ""
},
"require": {
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.5-dev"
}
},
"autoload": {
],
"description": "Symfony Finder Component",
"homepage": "http://symfony.com",
- "time": "2014-12-02 19:42:47"
+ "time": "2015-01-03 08:01:13"
},
{
"name": "symfony/process",
- "version": "v2.3.28",
+ "version": "v2.5.12",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
- "reference": "a8fe947ac58e081f8773e0d160807dcffbff7ed8"
+ "reference": "00a1308e8b5aec5eba7c8f1708426a78f929be8c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Process/zipball/a8fe947ac58e081f8773e0d160807dcffbff7ed8",
- "reference": "a8fe947ac58e081f8773e0d160807dcffbff7ed8",
+ "url": "https://api.github.com/repos/symfony/Process/zipball/00a1308e8b5aec5eba7c8f1708426a78f929be8c",
+ "reference": "00a1308e8b5aec5eba7c8f1708426a78f929be8c",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
- "require-dev": {
- "symfony/phpunit-bridge": "~2.7"
- },
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.5-dev"
}
},
"autoload": {
],
"authors": [
{
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
},
{
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
}
],
"description": "Symfony Process Component",
- "homepage": "https://symfony.com",
- "time": "2015-05-01 14:06:45"
+ "homepage": "http://symfony.com",
+ "time": "2015-02-08 07:07:45"
},
{
"name": "totten/ca-config",
<?php
define('CIVICRM_TEST', 1);
+define('CIVICRM_CONTAINER_CACHE', 'auto');
// This file is loaded on all systems running tests. To override settings on
// your local system, please create "civicrm.settings.local.php" and put