Commit | Line | Data |
---|---|---|
25523059 CW |
1 | <?php |
2 | ||
3 | class CRM_Search_Page_Build extends CRM_Core_Page { | |
4 | /** | |
5 | * @var string[] | |
6 | */ | |
7 | private $loadOptions = ['id', 'name', 'label', 'description', 'color', 'icon']; | |
8 | ||
9 | /** | |
10 | * @var array | |
11 | */ | |
12 | private $schema = []; | |
13 | ||
14 | /** | |
15 | * @var string[] | |
16 | */ | |
17 | private $allowedEntities = []; | |
18 | ||
19 | public function run() { | |
20 | $breadCrumb = [ | |
21 | 'title' => ts('Search'), | |
22 | 'url' => CRM_Utils_System::url('civicrm/search'), | |
23 | ]; | |
24 | CRM_Utils_System::appendBreadCrumb([$breadCrumb]); | |
25 | ||
26 | $this->getSchema(); | |
27 | ||
28 | // If user does not have permission to search any entity, bye bye. | |
29 | if (!$this->allowedEntities) { | |
30 | CRM_Utils_System::permissionDenied(); | |
31 | } | |
32 | ||
33 | // Add client-side vars for the search UI | |
34 | $vars = [ | |
35 | 'operators' => \CRM_Core_DAO::acceptedSQLOperators(), | |
36 | 'schema' => $this->schema, | |
37 | 'links' => $this->getLinks(), | |
38 | 'loadOptions' => $this->loadOptions, | |
39 | 'actions' => $this->getActions(), | |
40 | 'functions' => CRM_Api4_Page_Api4Explorer::getSqlFunctions(), | |
41 | ]; | |
42 | ||
43 | Civi::resources() | |
44 | ->addPermissions(['edit groups', 'administer reserved groups']) | |
45 | ->addVars('search', $vars); | |
46 | ||
47 | // Load angular module | |
48 | $loader = new Civi\Angular\AngularLoader(); | |
49 | $loader->setModules(['search']); | |
50 | $loader->setPageName('civicrm/search'); | |
51 | $loader->useApp([ | |
52 | 'defaultRoute' => '/Contact', | |
53 | ]); | |
54 | $loader->load(); | |
55 | parent::run(); | |
56 | } | |
57 | ||
58 | /** | |
59 | * Populates $this->schema & $this->allowedEntities | |
60 | */ | |
61 | private function getSchema() { | |
62 | $schema = \Civi\Api4\Entity::get() | |
63 | ->addSelect('name', 'title', 'description', 'icon') | |
64 | ->addWhere('name', '!=', 'Entity') | |
65 | ->addOrderBy('title') | |
66 | ->setChain([ | |
67 | 'get' => ['$name', 'getActions', ['where' => [['name', '=', 'get']]], ['params']], | |
68 | ])->execute(); | |
69 | $getFields = ['name', 'title', 'description', 'options', 'input_type', 'input_attrs', 'data_type', 'serialize']; | |
70 | foreach ($schema as $entity) { | |
71 | // Skip if entity doesn't have a 'get' action or the user doesn't have permission to use get | |
72 | if ($entity['get']) { | |
73 | // Get fields and pre-load options for certain prominent entities | |
74 | $loadOptions = in_array($entity['name'], ['Contact', 'Group']) ? $this->loadOptions : FALSE; | |
75 | if ($loadOptions) { | |
76 | $entity['optionsLoaded'] = TRUE; | |
77 | } | |
78 | $entity['fields'] = civicrm_api4($entity['name'], 'getFields', [ | |
79 | 'select' => $getFields, | |
80 | 'where' => [['permission', 'IS NULL']], | |
81 | 'orderBy' => ['title'], | |
82 | 'loadOptions' => $loadOptions, | |
83 | ]); | |
84 | // Get the names of params this entity supports (minus some obvious ones) | |
85 | $params = $entity['get'][0]; | |
86 | CRM_Utils_Array::remove($params, 'checkPermissions', 'debug', 'chain', 'language'); | |
87 | unset($entity['get']); | |
88 | $this->schema[] = ['params' => array_keys($params)] + array_filter($entity); | |
89 | $this->allowedEntities[] = $entity['name']; | |
90 | } | |
91 | } | |
92 | } | |
93 | ||
94 | /** | |
95 | * @return array | |
96 | */ | |
97 | private function getLinks() { | |
98 | $results = []; | |
99 | $keys = array_flip(['alias', 'entity', 'joinType']); | |
100 | foreach (civicrm_api4('Entity', 'getLinks', ['where' => [['entity', 'IN', $this->allowedEntities]]], ['entity' => 'links']) as $entity => $links) { | |
101 | $entityLinks = []; | |
102 | foreach ($links as $link) { | |
103 | if (!empty($link['entity']) && in_array($link['entity'], $this->allowedEntities)) { | |
104 | // Use entity.alias as array key to avoid duplicates | |
105 | $entityLinks[$link['entity'] . $link['alias']] = array_intersect_key($link, $keys); | |
106 | } | |
107 | } | |
108 | $results[$entity] = array_values($entityLinks); | |
109 | } | |
110 | return array_filter($results); | |
111 | } | |
112 | ||
113 | /** | |
114 | * @return array[] | |
115 | */ | |
116 | private function getActions() { | |
117 | // Note: the placeholder %1 will be replaced with entity name on the clientside | |
118 | $actions = [ | |
119 | 'export' => [ | |
120 | 'title' => ts('Export %1'), | |
121 | 'icon' => 'fa-file-excel-o', | |
122 | 'entities' => array_keys(CRM_Export_BAO_Export::getComponents()), | |
123 | 'crmPopup' => [ | |
124 | 'path' => "'civicrm/export/standalone'", | |
125 | 'query' => "{entity: entity, id: ids.join(',')}", | |
126 | ], | |
127 | ], | |
128 | 'update' => [ | |
129 | 'title' => ts('Update %1'), | |
130 | 'icon' => 'fa-save', | |
131 | 'entities' => [], | |
132 | 'uiDialog' => ['templateUrl' => '~/search/crmSearchActions/crmSearchActionUpdate.html'], | |
133 | ], | |
134 | 'delete' => [ | |
135 | 'title' => ts('Delete %1'), | |
136 | 'icon' => 'fa-trash', | |
137 | 'entities' => [], | |
138 | 'uiDialog' => ['templateUrl' => '~/search/crmSearchActions/crmSearchActionDelete.html'], | |
139 | ], | |
140 | ]; | |
141 | ||
142 | // Check permissions for update & delete actions | |
143 | foreach ($this->allowedEntities as $entity) { | |
144 | $result = civicrm_api4($entity, 'getActions', [ | |
145 | 'where' => [['name', 'IN', ['update', 'delete']]], | |
146 | ], ['name']); | |
147 | foreach ($result as $action) { | |
148 | // Contacts have their own delete action | |
149 | if (!($entity === 'Contact' && $action === 'delete')) { | |
150 | $actions[$action]['entities'][] = $entity; | |
151 | } | |
152 | } | |
153 | } | |
154 | ||
155 | // Add contact tasks which support standalone mode (with a 'url' property) | |
156 | $contactTasks = CRM_Contact_Task::permissionedTaskTitles(CRM_Core_Permission::getPermission()); | |
157 | foreach (CRM_Contact_Task::tasks() as $id => $task) { | |
158 | if (isset($contactTasks[$id]) && !empty($task['url'])) { | |
159 | $actions['contact.' . $id] = [ | |
160 | 'title' => $task['title'], | |
161 | 'entities' => ['Contact'], | |
162 | 'icon' => $task['icon'] ?? 'fa-gear', | |
163 | 'crmPopup' => [ | |
164 | 'path' => "'{$task['url']}'", | |
165 | 'query' => "{cids: ids.join(',')}", | |
166 | ], | |
167 | ]; | |
168 | } | |
169 | } | |
170 | ||
171 | return $actions; | |
172 | } | |
173 | ||
174 | } |