3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 +--------------------------------------------------------------------+
14 class ExampleDataLoader
{
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()`.
23 const HEAVY_FIELDS
= 'data,asserts';
31 * Get a list of all examples, including basic metadata (name, title, workflow).
34 * Ex: ['my_example' => ['title' => ..., 'workflow' => ..., 'tags' => ...]]
35 * @throws \ReflectionException
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
);
51 public function getMeta(string $name): ?
array {
52 $all = $this->getMetas();
53 return $all[$name] ??
NULL;
61 public function getFull(string $name): ?
array {
62 $example = $this->getMeta($name);
63 if ($example === NULL) {
67 $obj = $this->createObj($example['file'], $example['class']);
68 $obj->build($example);
73 * Get a list of all examples, including basic metadata (name, title, workflow).
76 * Ex: ['my_example' => ['title' => ..., 'workflow' => ..., 'tags' => ...]]
77 * @throws \ReflectionException
79 protected function findMetas(): array {
80 $classes = array_merge(
81 // This scope of search is decidedly narrow - it should probably be expanded.
82 $this->scanExampleClasses(\Civi
::paths()->getPath('[civicrm.root]/'), 'Civi/Test/ExampleData', '\\'),
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', '\\')
91 foreach ($classes as $file => $class) {
92 $obj = $this->createObj($file, $class);
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;
100 $all[$example['name']] = $example;
112 * Folder to search (within the parent).
114 * Namespace separator, eg underscore or backslash.
116 * Array(string $includeFile => string $className).
118 private function scanExampleClasses($classRoot, $classDir, $classDelim): array {
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;
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);
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$/', '',
133 $r[$includeFile] = $class;
139 private function createObj(?
string $file, ?
string $class): ExampleDataInterface
{
143 if (!class_exists($class)) {
144 throw new \
CRM_Core_Exception("Failed to read example (class '{$class}' in file '{$file}')");