[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\WebAsset; 11 12 use Joomla\CMS\Event\AbstractEvent; 13 use Joomla\CMS\Filesystem\Path; 14 use Joomla\CMS\WebAsset\Exception\UnknownAssetException; 15 use Joomla\Event\Dispatcher as EventDispatcher; 16 use Joomla\Event\DispatcherAwareInterface; 17 use Joomla\Event\DispatcherAwareTrait; 18 19 // phpcs:disable PSR1.Files.SideEffects 20 \defined('JPATH_PLATFORM') or die; 21 // phpcs:enable PSR1.Files.SideEffects 22 23 /** 24 * Web Asset Registry class 25 * 26 * @since 4.0.0 27 */ 28 class WebAssetRegistry implements WebAssetRegistryInterface, DispatcherAwareInterface 29 { 30 use DispatcherAwareTrait; 31 32 /** 33 * Files with Asset info. File path should be relative. 34 * 35 * @var array 36 * @example of registry file: 37 * 38 * { 39 * "title" : "Example", 40 * "name" : "com_example", 41 * "author": "Joomla! CMS", 42 * "assets": [ 43 * { 44 * "name": "library1", 45 * "version": "3.5.0", 46 * "type": "script", 47 * "uri": "com_example/library1.min.js" 48 * }, 49 * { 50 * "name": "library2", 51 * "version": "3.5.0", 52 * "type": "script", 53 * "uri": "com_example/library2.min.js", 54 * "dependencies": [ 55 * "core", 56 * "library1" 57 * ], 58 * "attribute": { 59 * "attr-name": "attr value" 60 * "defer": true 61 * } 62 * }, 63 * { 64 * "name": "library1", 65 * "version": "3.5.0", 66 * "type": "style", 67 * "uri": "com_example/library1.min.css" 68 * "attribute": { 69 * "media": "all" 70 * } 71 * }, 72 * { 73 * "name": "library1", 74 * "type": "preset", 75 * "dependencies": { 76 * "library1#style", 77 * "library1#script" 78 * } 79 * }, 80 * ] 81 * } 82 * 83 * @since 4.0.0 84 */ 85 protected $dataFilesNew = []; 86 87 /** 88 * List of parsed files 89 * 90 * @var array 91 * 92 * @since 4.0.0 93 */ 94 protected $dataFilesParsed = []; 95 96 /** 97 * Registry of available Assets 98 * 99 * @var array 100 * 101 * @since 4.0.0 102 */ 103 protected $assets = []; 104 105 /** 106 * Registry constructor 107 * 108 * @since 4.0.0 109 */ 110 public function __construct() 111 { 112 // Use a dedicated dispatcher 113 $this->setDispatcher(new EventDispatcher()); 114 } 115 116 /** 117 * Get an existing Asset from a registry, by asset name. 118 * 119 * @param string $type Asset type, script or style 120 * @param string $name Asset name 121 * 122 * @return WebAssetItem 123 * 124 * @throws UnknownAssetException When Asset cannot be found 125 * 126 * @since 4.0.0 127 */ 128 public function get(string $type, string $name): WebAssetItemInterface 129 { 130 // Check if any new file was added 131 $this->parseRegistryFiles(); 132 133 if (empty($this->assets[$type][$name])) { 134 throw new UnknownAssetException(sprintf('There is no "%s" asset of a "%s" type in the registry.', $name, $type)); 135 } 136 137 return $this->assets[$type][$name]; 138 } 139 140 /** 141 * Add Asset to registry of known assets 142 * 143 * @param string $type Asset type, script or style 144 * @param WebAssetItemInterface $asset Asset instance 145 * 146 * @return self 147 * 148 * @since 4.0.0 149 */ 150 public function add(string $type, WebAssetItemInterface $asset): WebAssetRegistryInterface 151 { 152 $type = strtolower($type); 153 154 if (!array_key_exists($type, $this->assets)) { 155 $this->assets[$type] = []; 156 } 157 158 $eventChange = 'new'; 159 $eventAsset = $asset; 160 161 // Use "old" asset for "Changed" event, a "new" asset can be loaded by a name from the registry 162 if (!empty($this->assets[$type][$asset->getName()])) { 163 $eventChange = 'override'; 164 $eventAsset = $this->assets[$type][$asset->getName()]; 165 } 166 167 $this->assets[$type][$asset->getName()] = $asset; 168 169 $this->dispatchAssetChanged($type, $eventAsset, $eventChange); 170 171 return $this; 172 } 173 174 /** 175 * Remove Asset from registry. 176 * 177 * @param string $type Asset type, script or style 178 * @param string $name Asset name 179 * 180 * @return self 181 * 182 * @since 4.0.0 183 */ 184 public function remove(string $type, string $name): WebAssetRegistryInterface 185 { 186 if (!empty($this->assets[$type][$name])) { 187 $asset = $this->assets[$type][$name]; 188 189 unset($this->assets[$type][$name]); 190 191 $this->dispatchAssetChanged($type, $asset, 'remove'); 192 } 193 194 return $this; 195 } 196 197 /** 198 * Check whether the asset exists in the registry. 199 * 200 * @param string $type Asset type, script or style 201 * @param string $name Asset name 202 * 203 * @return boolean 204 * 205 * @since 4.0.0 206 */ 207 public function exists(string $type, string $name): bool 208 { 209 return !empty($this->assets[$type][$name]); 210 } 211 212 /** 213 * Prepare new Asset instance. 214 * 215 * @param string $name The asset name 216 * @param string $uri The URI for the asset 217 * @param array $options Additional options for the asset 218 * @param array $attributes Attributes for the asset 219 * @param array $dependencies Asset dependencies 220 * 221 * @return WebAssetItem 222 * 223 * @since 4.0.0 224 */ 225 public function createAsset( 226 string $name, 227 string $uri = null, 228 array $options = [], 229 array $attributes = [], 230 array $dependencies = [] 231 ): WebAssetItem { 232 $nameSpace = \array_key_exists('namespace', $options) ? $options['namespace'] : __NAMESPACE__ . '\\AssetItem'; 233 $className = \array_key_exists('class', $options) ? $options['class'] : null; 234 235 if ($className && class_exists($nameSpace . '\\' . $className)) { 236 $className = $nameSpace . '\\' . $className; 237 238 return new $className($name, $uri, $options, $attributes, $dependencies); 239 } 240 241 return new WebAssetItem($name, $uri, $options, $attributes, $dependencies); 242 } 243 244 /** 245 * Register new file with Asset(s) info 246 * 247 * @param string $path Relative path 248 * 249 * @return self 250 * 251 * @since 4.0.0 252 */ 253 public function addRegistryFile(string $path): self 254 { 255 $path = Path::clean($path); 256 257 if (isset($this->dataFilesNew[$path]) || isset($this->dataFilesParsed[$path])) { 258 return $this; 259 } 260 261 if (is_file(JPATH_ROOT . '/' . $path)) { 262 $this->dataFilesNew[$path] = $path; 263 } 264 265 return $this; 266 } 267 268 /** 269 * Get a list of the registry files 270 * 271 * @return array 272 * 273 * @since 4.0.0 274 */ 275 public function getRegistryFiles(): array 276 { 277 return array_values($this->dataFilesParsed + $this->dataFilesNew); 278 } 279 280 /** 281 * Helper method to register new file with Template Asset(s) info 282 * 283 * @param string $template The template name 284 * @param integer $client The application client id 285 * 286 * @return self 287 * 288 * @since 4.0.0 289 */ 290 public function addTemplateRegistryFile(string $template, int $client): self 291 { 292 switch ($client) { 293 case 0: 294 $this->addRegistryFile('templates/' . $template . '/joomla.asset.json'); 295 break; 296 case 1: 297 $this->addRegistryFile('administrator/templates/' . $template . '/joomla.asset.json'); 298 break; 299 default: 300 break; 301 } 302 303 return $this; 304 } 305 306 /** 307 * Helper method to register new file with Extension Asset(s) info 308 * 309 * @param string $name A full extension name, actually a name in the /media folder, eg: com_example, plg_system_example etc. 310 * 311 * @return self 312 * 313 * @since 4.0.0 314 */ 315 public function addExtensionRegistryFile(string $name): self 316 { 317 $this->addRegistryFile('media/' . $name . '/joomla.asset.json'); 318 319 return $this; 320 } 321 322 /** 323 * Parse registered files 324 * 325 * @return void 326 * 327 * @since 4.0.0 328 */ 329 protected function parseRegistryFiles() 330 { 331 if (!$this->dataFilesNew) { 332 return; 333 } 334 335 foreach ($this->dataFilesNew as $path) { 336 // Parse only if the file was not parsed already 337 if (empty($this->dataFilesParsed[$path])) { 338 $this->parseRegistryFile($path); 339 340 // Mark the file as parsed 341 $this->dataFilesParsed[$path] = $path; 342 } 343 344 // Remove the file from queue 345 unset($this->dataFilesNew[$path]); 346 } 347 } 348 349 /** 350 * Parse registry file 351 * 352 * @param string $path Relative path to the data file 353 * 354 * @return void 355 * 356 * @throws \RuntimeException If file is empty or invalid 357 * 358 * @since 4.0.0 359 */ 360 protected function parseRegistryFile($path) 361 { 362 $data = file_get_contents(JPATH_ROOT . '/' . $path); 363 $data = $data ? json_decode($data, true) : null; 364 365 if ($data === null) { 366 throw new \RuntimeException(sprintf('Asset registry file "%s" contains invalid JSON', $path)); 367 } 368 369 // Check if asset field exists and contains data. If it doesn't - we can just bail here. 370 if (empty($data['assets'])) { 371 return; 372 } 373 374 // Keep source info 375 $assetSource = [ 376 'registryFile' => $path, 377 ]; 378 379 $namespace = \array_key_exists('namespace', $data) ? $data['namespace'] : null; 380 381 // Prepare WebAssetItem instances 382 foreach ($data['assets'] as $i => $item) { 383 if (empty($item['name'])) { 384 throw new \RuntimeException( 385 sprintf('Failed parsing asset registry file "%s". Property "name" is required for asset index "%s"', $path, $i) 386 ); 387 } 388 389 if (empty($item['type'])) { 390 throw new \RuntimeException( 391 sprintf('Failed parsing asset registry file "%s". Property "type" is required for asset "%s"', $path, $item['name']) 392 ); 393 } 394 395 $item['type'] = strtolower($item['type']); 396 397 $name = $item['name']; 398 $uri = $item['uri'] ?? ''; 399 $options = $item; 400 $options['assetSource'] = $assetSource; 401 402 unset($options['uri'], $options['name']); 403 404 // Inheriting the Namespace 405 if ($namespace && !\array_key_exists('namespace', $options)) { 406 $options['namespace'] = $namespace; 407 } 408 409 $assetItem = $this->createAsset($name, $uri, $options); 410 $this->add($item['type'], $assetItem); 411 } 412 } 413 414 /** 415 * Dispatch an event to notify listeners about asset changes: new, remove, override 416 * Events: 417 * - onWebAssetRegistryChangedAssetNew When new asset added to the registry 418 * - onWebAssetRegistryChangedAssetOverride When the asset overridden 419 * - onWebAssetRegistryChangedAssetRemove When new asset was removed from the registry 420 * 421 * @param string $type Asset type, script or style 422 * @param WebAssetItemInterface $asset Asset instance 423 * @param string $change A type of change: new, remove, override 424 * 425 * @return void 426 * 427 * @since 4.0.0 428 */ 429 protected function dispatchAssetChanged(string $type, WebAssetItemInterface $asset, string $change) 430 { 431 // Trigger the event 432 $event = AbstractEvent::create( 433 'onWebAssetRegistryChangedAsset' . ucfirst($change), 434 [ 435 'eventClass' => 'Joomla\\CMS\\Event\\WebAsset\\WebAssetRegistryAssetChanged', 436 'subject' => $this, 437 'assetType' => $type, 438 'asset' => $asset, 439 'change' => $change, 440 ] 441 ); 442 443 $this->getDispatcher()->dispatch($event->getName(), $event); 444 } 445 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |