| 1 | <?php |
| 2 | namespace Civi\Core; |
| 3 | |
| 4 | use Civi\Core\Lock\LockManager; |
| 5 | use Doctrine\Common\Annotations\AnnotationReader; |
| 6 | use Doctrine\Common\Annotations\AnnotationRegistry; |
| 7 | use Doctrine\Common\Annotations\FileCacheReader; |
| 8 | use Doctrine\Common\Cache\FilesystemCache; |
| 9 | use Doctrine\ORM\EntityManager; |
| 10 | use Doctrine\ORM\Mapping\Driver\AnnotationDriver; |
| 11 | use Doctrine\ORM\Tools\Setup; |
| 12 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
| 13 | use Symfony\Component\DependencyInjection\ContainerInterface; |
| 14 | use Symfony\Component\DependencyInjection\Definition; |
| 15 | use Symfony\Component\DependencyInjection\Reference; |
| 16 | |
| 17 | // TODO use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; |
| 18 | |
| 19 | /** |
| 20 | * Class Container |
| 21 | * @package Civi\Core |
| 22 | */ |
| 23 | class Container { |
| 24 | |
| 25 | const SELF = 'civi_container_factory'; |
| 26 | |
| 27 | /** |
| 28 | * @var ContainerBuilder |
| 29 | */ |
| 30 | private static $singleton; |
| 31 | |
| 32 | /** |
| 33 | * @param bool $reset |
| 34 | * Whether to forcibly rebuild the entire container. |
| 35 | * @return \Symfony\Component\DependencyInjection\TaggedContainerInterface |
| 36 | */ |
| 37 | public static function singleton($reset = FALSE) { |
| 38 | if ($reset || self::$singleton === NULL) { |
| 39 | $c = new self(); |
| 40 | self::$singleton = $c->createContainer(); |
| 41 | } |
| 42 | return self::$singleton; |
| 43 | } |
| 44 | |
| 45 | /** |
| 46 | * @var ContainerBuilder |
| 47 | * @return \Symfony\Component\DependencyInjection\ContainerBuilder |
| 48 | */ |
| 49 | public function createContainer() { |
| 50 | $civicrm_base_path = dirname(dirname(__DIR__)); |
| 51 | $container = new ContainerBuilder(); |
| 52 | $container->setParameter('civicrm_base_path', $civicrm_base_path); |
| 53 | $container->set(self::SELF, $this); |
| 54 | |
| 55 | // TODO Move configuration to an external file; define caching structure |
| 56 | // if (empty($configDirectories)) { |
| 57 | // throw new \Exception(__CLASS__ . ': Missing required properties (civicrmRoot, configDirectories)'); |
| 58 | // } |
| 59 | // $locator = new FileLocator($configDirectories); |
| 60 | // $loaderResolver = new LoaderResolver(array( |
| 61 | // new YamlFileLoader($container, $locator) |
| 62 | // )); |
| 63 | // $delegatingLoader = new DelegatingLoader($loaderResolver); |
| 64 | // foreach (array('services.yml') as $file) { |
| 65 | // $yamlUserFiles = $locator->locate($file, NULL, FALSE); |
| 66 | // foreach ($yamlUserFiles as $file) { |
| 67 | // $delegatingLoader->load($file); |
| 68 | // } |
| 69 | // } |
| 70 | |
| 71 | $container->setDefinition('lockManager', new Definition( |
| 72 | '\Civi\Core\Lock\LockManager', |
| 73 | array() |
| 74 | )) |
| 75 | ->setFactoryService(self::SELF)->setFactoryMethod('createLockManager'); |
| 76 | |
| 77 | $container->setDefinition('angular', new Definition( |
| 78 | '\Civi\Angular\Manager', |
| 79 | array() |
| 80 | )) |
| 81 | ->setFactoryService(self::SELF)->setFactoryMethod('createAngularManager'); |
| 82 | |
| 83 | $container->setDefinition('dispatcher', new Definition( |
| 84 | '\Symfony\Component\EventDispatcher\EventDispatcher', |
| 85 | array() |
| 86 | )) |
| 87 | ->setFactoryService(self::SELF)->setFactoryMethod('createEventDispatcher'); |
| 88 | |
| 89 | $container->setDefinition('magic_function_provider', new Definition( |
| 90 | '\Civi\API\Provider\MagicFunctionProvider', |
| 91 | array() |
| 92 | )); |
| 93 | |
| 94 | $container->setDefinition('civi_api_kernel', new Definition( |
| 95 | '\Civi\API\Kernel', |
| 96 | array(new Reference('dispatcher'), new Reference('magic_function_provider')) |
| 97 | )) |
| 98 | ->setFactoryService(self::SELF)->setFactoryMethod('createApiKernel'); |
| 99 | |
| 100 | // Expose legacy singletons as services in the container. |
| 101 | $singletons = array( |
| 102 | 'resources' => 'CRM_Core_Resources', |
| 103 | 'httpClient' => 'CRM_Utils_HttpClient', |
| 104 | // Maybe? 'config' => 'CRM_Core_Config', |
| 105 | // Maybe? 'smarty' => 'CRM_Core_Smarty', |
| 106 | ); |
| 107 | foreach ($singletons as $name => $class) { |
| 108 | $container->setDefinition($name, new Definition( |
| 109 | $class |
| 110 | )) |
| 111 | ->setFactoryClass($class)->setFactoryMethod('singleton'); |
| 112 | } |
| 113 | |
| 114 | return $container; |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * @return \Civi\Angular\Manager |
| 119 | */ |
| 120 | public function createAngularManager() { |
| 121 | return new \Civi\Angular\Manager(\CRM_Core_Resources::singleton()); |
| 122 | } |
| 123 | |
| 124 | /** |
| 125 | * @return \Symfony\Component\EventDispatcher\EventDispatcher |
| 126 | */ |
| 127 | public function createEventDispatcher() { |
| 128 | $dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher(); |
| 129 | $dispatcher->addListener('hook_civicrm_post::Activity', array('\Civi\CCase\Events', 'fireCaseChange')); |
| 130 | $dispatcher->addListener('hook_civicrm_post::Case', array('\Civi\CCase\Events', 'fireCaseChange')); |
| 131 | $dispatcher->addListener('hook_civicrm_caseChange', array('\Civi\CCase\Events', 'delegateToXmlListeners')); |
| 132 | $dispatcher->addListener('hook_civicrm_caseChange', array('\Civi\CCase\SequenceListener', 'onCaseChange_static')); |
| 133 | $dispatcher->addListener('DAO::post-insert', array('\CRM_Core_BAO_RecurringEntity', 'triggerInsert')); |
| 134 | $dispatcher->addListener('DAO::post-update', array('\CRM_Core_BAO_RecurringEntity', 'triggerUpdate')); |
| 135 | $dispatcher->addListener('DAO::post-delete', array('\CRM_Core_BAO_RecurringEntity', 'triggerDelete')); |
| 136 | $dispatcher->addListener('hook_civicrm_unhandled_exception', array( |
| 137 | 'CRM_Core_LegacyErrorHandler', |
| 138 | 'handleException', |
| 139 | )); |
| 140 | return $dispatcher; |
| 141 | } |
| 142 | |
| 143 | /** |
| 144 | * @return LockManager |
| 145 | */ |
| 146 | public function createLockManager() { |
| 147 | // Ideally, downstream implementers could override any definitions in |
| 148 | // the container. For now, we'll make-do with some define()s. |
| 149 | $lm = new LockManager(); |
| 150 | $lm |
| 151 | ->register('/^cache\./', defined('CIVICRM_CACHE_LOCK') ? CIVICRM_CACHE_LOCK : array('CRM_Core_Lock', 'createScopedLock')) |
| 152 | ->register('/^data\./', defined('CIVICRM_DATA_LOCK') ? CIVICRM_DATA_LOCK : array('CRM_Core_Lock', 'createScopedLock')) |
| 153 | ->register('/^worker\.mailing\.send\./', defined('CIVICRM_WORK_LOCK') ? CIVICRM_WORK_LOCK : array('CRM_Core_Lock', 'createCivimailLock')) |
| 154 | ->register('/^worker\./', defined('CIVICRM_WORK_LOCK') ? CIVICRM_WORK_LOCK : array('CRM_Core_Lock', 'createScopedLock')); |
| 155 | |
| 156 | // Registrations may use complex resolver expressions, but (as a micro-optimization) |
| 157 | // the default factory is specified as an array. |
| 158 | |
| 159 | return $lm; |
| 160 | } |
| 161 | |
| 162 | /** |
| 163 | * @param \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher |
| 164 | * @param $magicFunctionProvider |
| 165 | * |
| 166 | * @return \Civi\API\Kernel |
| 167 | */ |
| 168 | public function createApiKernel($dispatcher, $magicFunctionProvider) { |
| 169 | $dispatcher->addSubscriber(new \Civi\API\Subscriber\ChainSubscriber()); |
| 170 | $dispatcher->addSubscriber(new \Civi\API\Subscriber\TransactionSubscriber()); |
| 171 | $dispatcher->addSubscriber(new \Civi\API\Subscriber\I18nSubscriber()); |
| 172 | $dispatcher->addSubscriber($magicFunctionProvider); |
| 173 | $dispatcher->addSubscriber(new \Civi\API\Subscriber\PermissionCheck()); |
| 174 | $dispatcher->addSubscriber(new \Civi\API\Subscriber\APIv3SchemaAdapter()); |
| 175 | $dispatcher->addSubscriber(new \Civi\API\Subscriber\WrapperAdapter(array( |
| 176 | \CRM_Utils_API_HTMLInputCoder::singleton(), |
| 177 | \CRM_Utils_API_NullOutputCoder::singleton(), |
| 178 | \CRM_Utils_API_ReloadOption::singleton(), |
| 179 | \CRM_Utils_API_MatchOption::singleton(), |
| 180 | ))); |
| 181 | $dispatcher->addSubscriber(new \Civi\API\Subscriber\XDebugSubscriber()); |
| 182 | $kernel = new \Civi\API\Kernel($dispatcher); |
| 183 | |
| 184 | $reflectionProvider = new \Civi\API\Provider\ReflectionProvider($kernel); |
| 185 | $dispatcher->addSubscriber($reflectionProvider); |
| 186 | |
| 187 | $dispatcher->addSubscriber(new \Civi\API\Subscriber\DynamicFKAuthorization( |
| 188 | $kernel, |
| 189 | 'Attachment', |
| 190 | array('create', 'get', 'delete'), |
| 191 | // Given a file ID, determine the entity+table it's attached to. |
| 192 | 'SELECT if(cf.id,1,0) as is_valid, cef.entity_table, cef.entity_id |
| 193 | FROM civicrm_file cf |
| 194 | LEFT JOIN civicrm_entity_file cef ON cf.id = cef.file_id |
| 195 | WHERE cf.id = %1', |
| 196 | // Get a list of custom fields (field_name,table_name,extends) |
| 197 | 'SELECT concat("custom_",fld.id) as field_name, |
| 198 | grp.table_name as table_name, |
| 199 | grp.extends as extends |
| 200 | FROM civicrm_custom_field fld |
| 201 | INNER JOIN civicrm_custom_group grp ON fld.custom_group_id = grp.id |
| 202 | WHERE fld.data_type = "File" |
| 203 | ', |
| 204 | array('civicrm_activity', 'civicrm_mailing', 'civicrm_contact', 'civicrm_grant') |
| 205 | )); |
| 206 | |
| 207 | $kernel->setApiProviders(array( |
| 208 | $reflectionProvider, |
| 209 | $magicFunctionProvider, |
| 210 | )); |
| 211 | |
| 212 | return $kernel; |
| 213 | } |
| 214 | |
| 215 | } |