Commit | Line | Data |
---|---|---|
2cc4b0c0 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
4 | | Copyright CiviCRM LLC. All rights reserved. | | |
5 | | | | |
6 | | This work is published under the GNU AGPLv3 license with some | | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
9 | +--------------------------------------------------------------------+ | |
10 | */ | |
11 | ||
12 | namespace Civi\Test; | |
13 | ||
14 | class ExampleDataLoader { | |
15 | ||
16 | /** | |
17 | * These are "heavy" properties which are not cached. i.e. | |
18 | * - They are generated by `$ex->build($example);` | |
19 | * - They are not generated by '$ex->getExamples();' | |
20 | * - They are returned by `$this->getFull()` | |
21 | * - They are not returned by `$this->getMeta()`. | |
22 | */ | |
23 | const HEAVY_FIELDS = 'data,asserts'; | |
24 | ||
25 | /** | |
26 | * @var array|null | |
27 | */ | |
28 | private $metas; | |
29 | ||
30 | /** | |
31 | * Get a list of all examples, including basic metadata (name, title, workflow). | |
32 | * | |
33 | * @return array | |
34 | * Ex: ['my_example' => ['title' => ..., 'workflow' => ..., 'tags' => ...]] | |
35 | * @throws \ReflectionException | |
36 | */ | |
37 | public function getMetas(): array { | |
38 | if ($this->metas === NULL) { | |
39 | // $cache = new \CRM_Utils_Cache_NoCache([]); | |
40 | $cache = \CRM_Utils_Constant::value('CIVICRM_TEST') ? new \CRM_Utils_Cache_NoCache([]) : \Civi::cache('long'); | |
41 | $cacheKey = \CRM_Utils_String::munge(__CLASS__); | |
42 | $this->metas = $cache->get($cacheKey); | |
43 | if ($this->metas === NULL) { | |
44 | $this->metas = $this->findMetas(); | |
45 | $cache->set($cacheKey, $this->metas); | |
46 | } | |
47 | } | |
48 | return $this->metas; | |
49 | } | |
50 | ||
51 | public function getMeta(string $name): ?array { | |
52 | $all = $this->getMetas(); | |
53 | return $all[$name] ?? NULL; | |
54 | } | |
55 | ||
56 | /** | |
57 | * @param string $name | |
58 | * | |
59 | * @return array|null | |
60 | */ | |
61 | public function getFull(string $name): ?array { | |
62 | $example = $this->getMeta($name); | |
63 | if ($example === NULL) { | |
64 | return NULL; | |
65 | } | |
66 | ||
10282496 | 67 | $obj = $this->createObj($example['file'], $example['class']); |
2cc4b0c0 TO |
68 | $obj->build($example); |
69 | return $example; | |
70 | } | |
71 | ||
72 | /** | |
73 | * Get a list of all examples, including basic metadata (name, title, workflow). | |
74 | * | |
75 | * @return array | |
76 | * Ex: ['my_example' => ['title' => ..., 'workflow' => ..., 'tags' => ...]] | |
77 | * @throws \ReflectionException | |
78 | */ | |
79 | protected function findMetas(): array { | |
80 | $classes = array_merge( | |
81 | // This scope of search is decidedly narrow - it should probably be expanded. | |
1b4483d0 | 82 | $this->scanExampleClasses(\Civi::paths()->getPath('[civicrm.root]/'), 'Civi/Test/ExampleData', '\\'), |
2cc4b0c0 TO |
83 | $this->scanExampleClasses(\Civi::paths()->getPath('[civicrm.root]/'), 'CRM/*/WorkflowMessage', '_'), |
84 | $this->scanExampleClasses(\Civi::paths()->getPath('[civicrm.root]/'), 'Civi/*/WorkflowMessage', '\\'), | |
85 | $this->scanExampleClasses(\Civi::paths()->getPath('[civicrm.root]/'), 'Civi/WorkflowMessage', '\\'), | |
86 | $this->scanExampleClasses(\Civi::paths()->getPath('[civicrm.root]/tests/phpunit/'), 'CRM/*/WorkflowMessage', '_'), | |
87 | $this->scanExampleClasses(\Civi::paths()->getPath('[civicrm.root]/tests/phpunit/'), 'Civi/*/WorkflowMessage', '\\') | |
88 | ); | |
89 | ||
90 | $all = []; | |
91 | foreach ($classes as $file => $class) { | |
10282496 | 92 | $obj = $this->createObj($file, $class); |
2cc4b0c0 TO |
93 | $offset = 0; |
94 | foreach ($obj->getExamples() as $example) { | |
95 | $example['file'] = $file; | |
96 | $example['class'] = $class; | |
97 | if (!isset($example['name'])) { | |
98 | $example['name'] = $example['class'] . '#' . $offset; | |
99 | } | |
100 | $all[$example['name']] = $example; | |
101 | $offset++; | |
102 | } | |
103 | } | |
104 | ||
105 | return $all; | |
106 | } | |
107 | ||
108 | /** | |
109 | * @param $classRoot | |
110 | * Ex: Civi root dir. | |
111 | * @param $classDir | |
112 | * Folder to search (within the parent). | |
113 | * @param $classDelim | |
114 | * Namespace separator, eg underscore or backslash. | |
115 | * @return array | |
78b3c6d0 | 116 | * Array(string $includeFile => string $className). |
2cc4b0c0 TO |
117 | */ |
118 | private function scanExampleClasses($classRoot, $classDir, $classDelim): array { | |
78b3c6d0 TO |
119 | $civiRoot = \Civi::paths()->getPath('[civicrm.root]/'); |
120 | $classRoot = \CRM_Utils_File::addTrailingSlash($classRoot, '/'); | |
121 | // Prefer include-paths relative to civiRoot - eg make tests/phpunit/* loadable at runtime. | |
122 | $includeRoot = \CRM_Utils_File::isChildPath($civiRoot, $classRoot) ? $civiRoot : $classRoot; | |
123 | ||
2cc4b0c0 TO |
124 | $r = []; |
125 | $exDirs = (array) glob($classRoot . $classDir); | |
126 | foreach ($exDirs as $exDir) { | |
127 | foreach (\CRM_Utils_File::findFiles($exDir, '*.ex.php') as $file) { | |
128 | $file = str_replace(DIRECTORY_SEPARATOR, '/', $file); | |
78b3c6d0 TO |
129 | $includeFile = \CRM_Utils_File::relativize($file, $includeRoot); |
130 | $classFile = \CRM_Utils_File::relativize($file, $classRoot); | |
131 | $class = str_replace('/', $classDelim, preg_replace('/\.ex\.php$/', '', | |
132 | $classFile)); | |
133 | $r[$includeFile] = $class; | |
2cc4b0c0 TO |
134 | } |
135 | } | |
136 | return $r; | |
137 | } | |
138 | ||
10282496 TO |
139 | private function createObj(?string $file, ?string $class): ExampleDataInterface { |
140 | if ($file) { | |
141 | include_once $file; | |
142 | } | |
143 | if (!class_exists($class)) { | |
144 | throw new \CRM_Core_Exception("Failed to read example (class '{$class}' in file '{$file}')"); | |
145 | } | |
146 | ||
147 | return new $class(); | |
148 | } | |
149 | ||
2cc4b0c0 | 150 | } |