fba89627dd9b027d97754ac9712e0437a0907d6d
[civicrm-core.git] / CRM / Api4 / Services.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
6 | |
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
10 +--------------------------------------------------------------------+
11 */
12
13 /**
14 *
15 * @package CRM
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 * $Id$
18 *
19 */
20
21
22 use Symfony\Component\DependencyInjection\Reference;
23 use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
24 use Symfony\Component\Config\FileLocator;
25
26 class CRM_Api4_Services {
27
28 /**
29 * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
30 */
31 public static function hook_container($container) {
32 $loader = new XmlFileLoader($container, new FileLocator(dirname(dirname(__DIR__))));
33 $loader->load('Civi/Api4/services.xml');
34
35 self::loadServices('Civi\Api4\Service\Spec\Provider', 'spec_provider', $container);
36 self::loadServices('Civi\Api4\Event\Subscriber', 'event_subscriber', $container);
37
38 $container->getDefinition('civi_api_kernel')->addMethodCall(
39 'registerApiProvider',
40 [new Reference('action_object_provider')]
41 );
42
43 // add event subscribers$container->get(
44 $dispatcher = $container->getDefinition('dispatcher');
45 $subscribers = $container->findTaggedServiceIds('event_subscriber');
46
47 foreach (array_keys($subscribers) as $subscriber) {
48 $dispatcher->addMethodCall(
49 'addSubscriber',
50 [new Reference($subscriber)]
51 );
52 }
53
54 // add spec providers
55 $providers = $container->findTaggedServiceIds('spec_provider');
56 $gatherer = $container->getDefinition('spec_gatherer');
57
58 foreach (array_keys($providers) as $provider) {
59 $gatherer->addMethodCall(
60 'addSpecProvider',
61 [new Reference($provider)]
62 );
63 }
64
65 if (defined('CIVICRM_UF') && CIVICRM_UF === 'UnitTests') {
66 $loader->load('tests/phpunit/api/v4/services.xml');
67 }
68 }
69
70 /**
71 * Load all services in a given directory
72 *
73 * @param string $namespace
74 * @param string $tag
75 * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
76 */
77 public static function loadServices($namespace, $tag, $container) {
78 $namespace = \CRM_Utils_File::addTrailingSlash($namespace, '\\');
79 $locations = array_merge([\Civi::paths()->getPath('[civicrm.root]/Civi.php')],
80 array_column(\CRM_Extension_System::singleton()->getMapper()->getActiveModuleFiles(), 'filePath')
81 );
82 foreach ($locations as $location) {
83 $path = \CRM_Utils_File::addTrailingSlash(dirname($location)) . str_replace('\\', DIRECTORY_SEPARATOR, $namespace);
84 if (!file_exists($path) || !is_dir($path)) {
85 $resource = new \Symfony\Component\Config\Resource\FileExistenceResource($path);
86 $container->addResource($resource);
87 continue;
88 }
89
90 try {
91 $resource = new \Symfony\Component\Config\Resource\DirectoryResource($path, ';\.php$;');
92 foreach (glob("$path*.php") as $file) {
93 $matches = [];
94 preg_match('/(\w*)\.php$/', $file, $matches);
95 $serviceName = $namespace . array_pop($matches);
96 $serviceClass = new \ReflectionClass($serviceName);
97 if ($serviceClass->isInstantiable()) {
98 $definition = $container->register(str_replace('\\', '_', $serviceName), $serviceName);
99 $definition->addTag($tag);
100 }
101 }
102 $container->addResource($resource);
103 }
104 catch (\InvalidArgumentException $e) {
105 //Directory is not found so lets not do anything i suppose.
106
107 // FIXME: The above comment implies that the try/catch is specifically
108 // about the directory's existence, which would make it redundant with the
109 // newer "file_exists()" guard. However, the actual "catch()" seems broader,
110 // and I don't see anything in DirectoryResource that throws the exception.
111 // So... maybe it's not needed, or maybe there's some additional purpose.
112 }
113 }
114 }
115
116 }