Merge pull request #17714 from colemanw/jsDocblocks
[civicrm-core.git] / Civi / Angular / Page / Modules.php
CommitLineData
e5afbdad
TO
1<?php
2
3namespace Civi\Angular\Page;
4
5/**
27a90ef6
TO
6 * This page aggregates data from Angular modules.
7 *
8 * Example: Aggregate metadata about all modules in JSON format.
9 * civicrm/ajax/angular-modules?format=json
10 *
11 * Example: Aggregate metadata for crmUi and crmUtil modules.
12 * civicrm/ajax/angular-modules?format=json&modules=crmUi,crmUtil
13 *
14 * Example: Aggregate *.js files for all modules.
15 * civicrm/ajax/angular-modules?format=js
16 *
17 * Example: Aggregate *.css files for all modules.
18 * civicrm/ajax/angular-modules?format=css
e5afbdad
TO
19 */
20class Modules extends \CRM_Core_Page {
21
22 /**
466e4b29
TO
23 * Generate asset content (when accessed via older, custom
24 * "civicrm/ajax/anulgar-modules" route).
25 *
26 * @deprecated
ee3db087
SL
27 *
28 * @throws \CRM_Core_Exception
e5afbdad
TO
29 */
30 public function run() {
e5afbdad
TO
31 /**
32 * @var \Civi\Angular\Manager $angular
33 */
048222df 34 $angular = \Civi::service('angular');
27a90ef6
TO
35 $moduleNames = $this->parseModuleNames(\CRM_Utils_Request::retrieve('modules', 'String'), $angular);
36
37 switch (\CRM_Utils_Request::retrieve('format', 'String')) {
38 case 'json':
39 case '':
40 $this->send(
41 'application/javascript',
42 json_encode($this->getMetadata($moduleNames, $angular))
43 );
44 break;
45
46 case 'js':
47 $this->send(
48 'application/javascript',
ad295ca9 49 $this->digestJs($angular->getResources($moduleNames, 'js', 'path'))
27a90ef6
TO
50 );
51 break;
52
53 case 'css':
54 $this->send(
55 'text/css',
56 \CRM_Utils_File::concat($angular->getResources($moduleNames, 'css', 'path'), "\n")
57 );
58 break;
59
60 default:
ee3db087 61 throw new \CRM_Core_Exception("Unrecognized format");
27a90ef6
TO
62 }
63
64 \CRM_Utils_System::civiExit();
65 }
e5afbdad 66
466e4b29
TO
67 /**
68 * Generate asset content (when accessed via AssetBuilder).
69 *
70 * @param \Civi\Core\Event\GenericHookEvent $event
71 * @see CRM_Utils_hook::buildAsset()
72 * @see \Civi\Core\AssetBuilder
73 */
74 public static function buildAngularModules($event) {
75 $page = new Modules();
76 $angular = \Civi::service('angular');
77
78 switch ($event->asset) {
79 case 'angular-modules.json':
9e10fb6b 80 $moduleNames = $page->parseModuleNames($event->params['modules'] ?? NULL, $angular);
466e4b29
TO
81 $event->mimeType = 'application/json';
82 $event->content = json_encode($page->getMetadata($moduleNames, $angular));
83 break;
84
85 case 'angular-modules.js':
9e10fb6b 86 $moduleNames = $page->parseModuleNames($event->params['modules'] ?? NULL, $angular);
466e4b29
TO
87 $event->mimeType = 'application/javascript';
88 $event->content = $page->digestJs($angular->getResources($moduleNames, 'js', 'path'));
89 break;
90
91 case 'angular-modules.css':
9e10fb6b 92 $moduleNames = $page->parseModuleNames($event->params['modules'] ?? NULL, $angular);
466e4b29
TO
93 $event->mimeType = 'text/css';
94 $event->content = \CRM_Utils_File::concat($angular->getResources($moduleNames, 'css', 'path'), "\n");
95
96 default:
97 // Not our problem.
98 }
99 }
100
ad295ca9
TO
101 /**
102 * @param array $files
103 * File paths.
104 * @return string
105 */
106 public function digestJs($files) {
c64f69d9 107 $scripts = [];
ad295ca9
TO
108 foreach ($files as $file) {
109 $scripts[] = file_get_contents($file);
110 }
111 $scripts = \CRM_Utils_JS::dedupeClosures(
112 $scripts,
c64f69d9
CW
113 ['angular', '$', '_'],
114 ['angular', 'CRM.$', 'CRM._']
ad295ca9 115 );
b047e061
TO
116 // This impl of stripComments currently adds 10-20ms and cuts ~7%
117 return \CRM_Utils_JS::stripComments(implode("\n", $scripts));
ad295ca9
TO
118 }
119
27a90ef6
TO
120 /**
121 * @param string $modulesExpr
122 * Comma-separated list of module names.
123 * @param \Civi\Angular\Manager $angular
124 * @return array
125 * Any well-formed module names. All if moduleExpr is blank.
126 */
127 public function parseModuleNames($modulesExpr, $angular) {
e5afbdad
TO
128 if ($modulesExpr) {
129 $moduleNames = preg_grep(
130 '/^[a-zA-Z0-9\-_\.]+$/',
131 explode(',', $modulesExpr)
132 );
27a90ef6 133 return $moduleNames;
e5afbdad
TO
134 }
135 else {
27a90ef6
TO
136 $moduleNames = array_keys($angular->getModules());
137 return $moduleNames;
e5afbdad 138 }
27a90ef6 139 }
e5afbdad 140
27a90ef6
TO
141 /**
142 * @param array $moduleNames
143 * List of module names.
144 * @param \Civi\Angular\Manager $angular
145 * @return array
146 */
147 public function getMetadata($moduleNames, $angular) {
148 $modules = $angular->getModules();
c64f69d9 149 $result = [];
e5afbdad
TO
150 foreach ($moduleNames as $moduleName) {
151 if (isset($modules[$moduleName])) {
c64f69d9 152 $result[$moduleName] = [];
e3d90d6c 153 $result[$moduleName]['domain'] = $modules[$moduleName]['ext'];
27a90ef6
TO
154 $result[$moduleName]['js'] = $angular->getResources($moduleName, 'js', 'rawUrl');
155 $result[$moduleName]['css'] = $angular->getResources($moduleName, 'css', 'rawUrl');
e5afbdad
TO
156 $result[$moduleName]['partials'] = $angular->getPartials($moduleName);
157 $result[$moduleName]['strings'] = $angular->getTranslatedStrings($moduleName);
158 }
159 }
27a90ef6
TO
160 return $result;
161 }
e5afbdad 162
27a90ef6
TO
163 /**
164 * Send a response.
165 *
166 * @param string $type
167 * Content type.
168 * @param string $data
169 * Content.
170 */
171 public function send($type, $data) {
172 // Encourage browsers to cache for a long time - 1 year
173 $ttl = 60 * 60 * 24 * 364;
956d2f84
CW
174 \CRM_Utils_System::setHttpHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
175 \CRM_Utils_System::setHttpHeader("Content-Type", $type);
176 \CRM_Utils_System::setHttpHeader("Cache-Control", "max-age=$ttl, public");
27a90ef6 177 echo $data;
e5afbdad
TO
178 }
179
180}