[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/Installer/Adapter/ -> TemplateAdapter.php (source)

   1  <?php
   2  
   3  /**
   4   * Joomla! Content Management System
   5   *
   6   * @copyright  (C) 2005 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\Installer\Adapter;
  11  
  12  use Joomla\CMS\Application\ApplicationHelper;
  13  use Joomla\CMS\Factory;
  14  use Joomla\CMS\Filesystem\Folder;
  15  use Joomla\CMS\Installer\Installer;
  16  use Joomla\CMS\Installer\InstallerAdapter;
  17  use Joomla\CMS\Language\Text;
  18  use Joomla\CMS\Log\Log;
  19  use Joomla\CMS\Table\Table;
  20  use Joomla\CMS\Table\Update;
  21  use Joomla\Database\ParameterType;
  22  
  23  // phpcs:disable PSR1.Files.SideEffects
  24  \defined('JPATH_PLATFORM') or die;
  25  // phpcs:enable PSR1.Files.SideEffects
  26  
  27  /**
  28   * Template installer
  29   *
  30   * @since  3.1
  31   */
  32  class TemplateAdapter extends InstallerAdapter
  33  {
  34      /**
  35       * The install client ID
  36       *
  37       * @var    integer
  38       * @since  3.4
  39       */
  40      protected $clientId;
  41  
  42      /**
  43       * Method to check if the extension is already present in the database
  44       *
  45       * @return  void
  46       *
  47       * @since   3.4
  48       * @throws  \RuntimeException
  49       */
  50      protected function checkExistingExtension()
  51      {
  52          try {
  53              $this->currentExtensionId = $this->extension->find(
  54                  array(
  55                      'element'   => $this->element,
  56                      'type'      => $this->type,
  57                      'client_id' => $this->clientId,
  58                  )
  59              );
  60          } catch (\RuntimeException $e) {
  61              // Install failed, roll back changes
  62              throw new \RuntimeException(
  63                  Text::sprintf(
  64                      'JLIB_INSTALLER_ABORT_ROLLBACK',
  65                      Text::_('JLIB_INSTALLER_' . $this->route),
  66                      $e->getMessage()
  67                  ),
  68                  $e->getCode(),
  69                  $e
  70              );
  71          }
  72      }
  73  
  74      /**
  75       * Method to copy the extension's base files from the `<files>` tag(s) and the manifest file
  76       *
  77       * @return  void
  78       *
  79       * @since   3.4
  80       * @throws  \RuntimeException
  81       */
  82      protected function copyBaseFiles()
  83      {
  84          // Copy all the necessary files
  85          if ($this->parent->parseFiles($this->getManifest()->files, -1) === false) {
  86              throw new \RuntimeException(
  87                  Text::sprintf(
  88                      'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES',
  89                      'files'
  90                  )
  91              );
  92          }
  93  
  94          if ($this->parent->parseFiles($this->getManifest()->images, -1) === false) {
  95              throw new \RuntimeException(
  96                  Text::sprintf(
  97                      'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES',
  98                      'images'
  99                  )
 100              );
 101          }
 102  
 103          if ($this->parent->parseFiles($this->getManifest()->css, -1) === false) {
 104              throw new \RuntimeException(
 105                  Text::sprintf(
 106                      'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES',
 107                      'css'
 108                  )
 109              );
 110          }
 111  
 112          // If there is a manifest script, let's copy it.
 113          if ($this->manifest_script) {
 114              $path['src']  = $this->parent->getPath('source') . '/' . $this->manifest_script;
 115              $path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script;
 116  
 117              if ($this->parent->isOverwrite() || !file_exists($path['dest'])) {
 118                  if (!$this->parent->copyFiles(array($path))) {
 119                      throw new \RuntimeException(
 120                          Text::sprintf(
 121                              'JLIB_INSTALLER_ABORT_MANIFEST',
 122                              Text::_('JLIB_INSTALLER_' . strtoupper($this->getRoute()))
 123                          )
 124                      );
 125                  }
 126              }
 127          }
 128      }
 129  
 130      /**
 131       * Method to finalise the installation processing
 132       *
 133       * @return  void
 134       *
 135       * @since   3.1
 136       * @throws  \RuntimeException
 137       */
 138      protected function finaliseInstall()
 139      {
 140          // Clobber any possible pending updates
 141          /** @var Update $update */
 142          $update = Table::getInstance('update');
 143  
 144          $uid = $update->find(
 145              array(
 146                  'element'   => $this->element,
 147                  'type'      => $this->type,
 148                  'client_id' => $this->clientId,
 149              )
 150          );
 151  
 152          if ($uid) {
 153              $update->delete($uid);
 154          }
 155  
 156          // Lastly, we will copy the manifest file to its appropriate place.
 157          if ($this->route !== 'discover_install') {
 158              if (!$this->parent->copyManifest(-1)) {
 159                  // Install failed, rollback changes
 160                  throw new \RuntimeException(
 161                      Text::sprintf(
 162                          'JLIB_INSTALLER_ABORT_COPY_SETUP',
 163                          Text::_('JLIB_INSTALLER_' . strtoupper($this->route))
 164                      )
 165                  );
 166              }
 167          }
 168      }
 169  
 170      /**
 171       * Method to finalise the uninstallation processing
 172       *
 173       * @return  boolean
 174       *
 175       * @since   4.0.0
 176       * @throws  \RuntimeException
 177       */
 178      protected function finaliseUninstall(): bool
 179      {
 180          $db    = $this->getDatabase();
 181          $query = $db->getQuery(true);
 182  
 183          $element     = $this->extension->element;
 184          $clientId    = $this->extension->client_id;
 185          $extensionId = $this->extension->extension_id;
 186  
 187          // Set menu that assigned to the template back to default template
 188          $subQuery = $db->getQuery(true)
 189              ->select($db->quoteName('s.id'))
 190              ->from($db->quoteName('#__template_styles', 's'))
 191              ->where(
 192                  [
 193                      $db->quoteName('s.template') . ' = :element',
 194                      $db->quoteName('s.client_id') . ' = :clientId',
 195                  ]
 196              );
 197  
 198          $query->bind(':element', $element)
 199              ->bind(':clientId', $clientId, ParameterType::INTEGER);
 200  
 201          $query->update($db->quoteName('#__menu'))
 202              ->set($db->quoteName('template_style_id') . ' = 0')
 203              ->where($db->quoteName('template_style_id') . ' IN (' . (string) $subQuery . ')');
 204  
 205          $db->setQuery($query);
 206          $db->execute();
 207  
 208          // Remove the template's styles
 209          $query = $db->getQuery(true)
 210              ->delete($db->quoteName('#__template_styles'))
 211              ->where(
 212                  [
 213                      $db->quoteName('template') . ' = :template',
 214                      $db->quoteName('client_id') . ' = :client_id',
 215                  ]
 216              )
 217              ->bind(':template', $element)
 218              ->bind(':client_id', $clientId, ParameterType::INTEGER);
 219          $db->setQuery($query);
 220          $db->execute();
 221  
 222          // Remove the schema version
 223          $query = $db->getQuery(true)
 224              ->delete($db->quoteName('#__schemas'))
 225              ->where($db->quoteName('extension_id') . ' = :extension_id')
 226              ->bind(':extension_id', $extensionId, ParameterType::INTEGER);
 227          $db->setQuery($query);
 228          $db->execute();
 229  
 230          // Clobber any possible pending updates
 231          $update = Table::getInstance('update');
 232          $uid    = $update->find(
 233              [
 234                  'element'   => $this->extension->element,
 235                  'type'      => $this->type,
 236                  'client_id' => $this->extension->client_id,
 237              ]
 238          );
 239  
 240          if ($uid) {
 241              $update->delete($uid);
 242          }
 243  
 244          $this->extension->delete();
 245  
 246          return true;
 247      }
 248  
 249      /**
 250       * Custom loadLanguage method
 251       *
 252       * @param   string  $path  The path where to find language files.
 253       *
 254       * @return  void
 255       *
 256       * @since   3.1
 257       */
 258      public function loadLanguage($path = null)
 259      {
 260          $source   = $this->parent->getPath('source');
 261          $basePath = $this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE;
 262  
 263          if (!$source) {
 264              $this->parent->setPath('source', $basePath . '/templates/' . $this->parent->extension->element);
 265          }
 266  
 267          $this->setManifest($this->parent->getManifest());
 268  
 269          $client = (string) $this->getManifest()->attributes()->client;
 270  
 271          // Load administrator language if not set.
 272          if (!$client) {
 273              $client = 'ADMINISTRATOR';
 274          }
 275  
 276          $base = \constant('JPATH_' . strtoupper($client));
 277          $extension = 'tpl_' . $this->getName();
 278          $source    = $path ?: $base . '/templates/' . $this->getName();
 279  
 280          $this->doLoadLanguage($extension, $source, $base);
 281      }
 282  
 283      /**
 284       * Method to parse optional tags in the manifest
 285       *
 286       * @return  void
 287       *
 288       * @since   3.4
 289       */
 290      protected function parseOptionalTags()
 291      {
 292          $this->parent->parseMedia($this->getManifest()->media);
 293          $this->parent->parseLanguages($this->getManifest()->languages, $this->clientId);
 294      }
 295  
 296      /**
 297       * Overloaded method to parse queries for template installations
 298       *
 299       * @return  void
 300       *
 301       * @since   3.4
 302       * @throws  \RuntimeException
 303       */
 304      protected function parseQueries()
 305      {
 306          if (\in_array($this->route, array('install', 'discover_install'))) {
 307              $db    = $this->getDatabase();
 308              $query = $db->getQuery(true);
 309              $lang  = Factory::getLanguage();
 310              $debug = $lang->setDebug(false);
 311  
 312              $columns = [
 313                  $db->quoteName('template'),
 314                  $db->quoteName('client_id'),
 315                  $db->quoteName('home'),
 316                  $db->quoteName('title'),
 317                  $db->quoteName('params'),
 318                  $db->quoteName('inheritable'),
 319                  $db->quoteName('parent'),
 320              ];
 321  
 322              $values = $query->bindArray(
 323                  [
 324                      $this->extension->element,
 325                      $this->extension->client_id,
 326                      '0',
 327                      Text::sprintf('JLIB_INSTALLER_DEFAULT_STYLE', Text::_($this->extension->name)),
 328                      $this->extension->params,
 329                      (int) $this->manifest->inheritable,
 330                      (string) $this->manifest->parent ?: '',
 331                  ],
 332                  [
 333                      ParameterType::STRING,
 334                      ParameterType::INTEGER,
 335                      ParameterType::STRING,
 336                      ParameterType::STRING,
 337                      ParameterType::STRING,
 338                      ParameterType::INTEGER,
 339                      ParameterType::STRING,
 340                  ]
 341              );
 342  
 343              $lang->setDebug($debug);
 344  
 345              // Insert record in #__template_styles
 346              $query->insert($db->quoteName('#__template_styles'))
 347                  ->columns($columns)
 348                  ->values(implode(',', $values));
 349  
 350              // There is a chance this could fail but we don't care...
 351              $db->setQuery($query)->execute();
 352          }
 353      }
 354  
 355      /**
 356       * Prepares the adapter for a discover_install task
 357       *
 358       * @return  void
 359       *
 360       * @since   3.4
 361       */
 362      public function prepareDiscoverInstall()
 363      {
 364          $client                 = ApplicationHelper::getClientInfo($this->extension->client_id);
 365          $manifestPath           = $client->path . '/templates/' . $this->extension->element . '/templateDetails.xml';
 366          $this->parent->manifest = $this->parent->isManifest($manifestPath);
 367          $this->parent->setPath('manifest', $manifestPath);
 368          $this->setManifest($this->parent->getManifest());
 369      }
 370  
 371      /**
 372       * Removes this extension's files
 373       *
 374       * @return  void
 375       *
 376       * @since   4.0.0
 377       * @throws  \RuntimeException
 378       */
 379      protected function removeExtensionFiles()
 380      {
 381          // Remove files
 382          $this->parent->removeFiles($this->getManifest()->media);
 383          $this->parent->removeFiles($this->getManifest()->languages, $this->extension->client_id);
 384  
 385          // Delete the template directory
 386          if (Folder::exists($this->parent->getPath('extension_root'))) {
 387              Folder::delete($this->parent->getPath('extension_root'));
 388          } else {
 389              Log::add(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DIRECTORY'), Log::WARNING, 'jerror');
 390          }
 391      }
 392  
 393      /**
 394       * Method to do any prechecks and setup the install paths for the extension
 395       *
 396       * @return  void
 397       *
 398       * @since   3.4
 399       * @throws  \RuntimeException
 400       */
 401      protected function setupInstallPaths()
 402      {
 403          // Get the client application target
 404          $cname = (string) $this->getManifest()->attributes()->client;
 405  
 406          if ($cname) {
 407              // Attempt to map the client to a base path
 408              $client = ApplicationHelper::getClientInfo($cname, true);
 409  
 410              if ($client === false) {
 411                  throw new \RuntimeException(Text::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_UNKNOWN_CLIENT', $cname));
 412              }
 413  
 414              $basePath       = $client->path;
 415              $this->clientId = $client->id;
 416          } else {
 417              // No client attribute was found so we assume the site as the client
 418              $basePath       = JPATH_SITE;
 419              $this->clientId = 0;
 420          }
 421  
 422          // Set the template root path
 423          if (empty($this->element)) {
 424              throw new \RuntimeException(
 425                  Text::sprintf(
 426                      'JLIB_INSTALLER_ABORT_MOD_INSTALL_NOFILE',
 427                      Text::_('JLIB_INSTALLER_' . strtoupper($this->route))
 428                  )
 429              );
 430          }
 431  
 432          $this->parent->setPath('extension_root', $basePath . '/templates/' . $this->element);
 433      }
 434  
 435      /**
 436       * Method to do any prechecks and setup the uninstall job
 437       *
 438       * @return  void
 439       *
 440       * @since   4.0.0
 441       */
 442      protected function setupUninstall()
 443      {
 444          $this->parent->extension = $this->extension;
 445  
 446          $db       = $this->getDatabase();
 447          $name     = $this->extension->element;
 448          $clientId = $this->extension->client_id;
 449  
 450          // For a template the id will be the template name which represents the subfolder of the templates folder that the template resides in.
 451          if (!$name) {
 452              throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_ID_EMPTY'));
 453          }
 454  
 455          // Deny removing a parent template if there are children
 456          $query = $db->getQuery(true)
 457              ->select('COUNT(*)')
 458              ->from($db->quoteName('#__template_styles'))
 459              ->where(
 460                  [
 461                      $db->quoteName('parent') . ' = :template',
 462                      $db->quoteName('client_id') . ' = :client_id',
 463                  ]
 464              )
 465              ->bind(':template', $name)
 466              ->bind(':client_id', $clientId);
 467          $db->setQuery($query);
 468  
 469          if ($db->loadResult() != 0) {
 470              throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_PARENT_TEMPLATE'));
 471          }
 472  
 473          // Deny remove default template
 474          $query = $db->getQuery(true)
 475              ->select('COUNT(*)')
 476              ->from($db->quoteName('#__template_styles'))
 477              ->where(
 478                  [
 479                      $db->quoteName('home') . ' = ' . $db->quote('1'),
 480                      $db->quoteName('template') . ' = :template',
 481                      $db->quoteName('client_id') . ' = :client_id',
 482                  ]
 483              )
 484              ->bind(':template', $name)
 485              ->bind(':client_id', $clientId);
 486          $db->setQuery($query);
 487  
 488          if ($db->loadResult() != 0) {
 489              throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DEFAULT'));
 490          }
 491  
 492          // Get the template root path
 493          $client = ApplicationHelper::getClientInfo($clientId);
 494  
 495          if (!$client) {
 496              throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_CLIENT'));
 497          }
 498  
 499          $this->parent->setPath('extension_root', $client->path . '/templates/' . strtolower($name));
 500          $this->parent->setPath('source', $this->parent->getPath('extension_root'));
 501  
 502          // We do findManifest to avoid problem when uninstalling a list of extensions: getManifest cache its manifest file
 503          $this->parent->findManifest();
 504          $manifest = $this->parent->getManifest();
 505  
 506          if (!($manifest instanceof \SimpleXMLElement)) {
 507              // Kill the extension entry
 508              $this->extension->delete($this->extension->extension_id);
 509  
 510              // Make sure we delete the folders
 511              Folder::delete($this->parent->getPath('extension_root'));
 512  
 513              throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_NOTFOUND_MANIFEST'));
 514          }
 515  
 516          // Attempt to load the language file; might have uninstall strings
 517          $this->loadLanguage();
 518      }
 519  
 520      /**
 521       * Method to store the extension to the database
 522       *
 523       * @return  void
 524       *
 525       * @since   3.4
 526       * @throws  \RuntimeException
 527       */
 528      protected function storeExtension()
 529      {
 530          // Discover installs are stored a little differently
 531          if ($this->route === 'discover_install') {
 532              $manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest'));
 533  
 534              $this->extension->manifest_cache = json_encode($manifest_details);
 535              $this->extension->state = 0;
 536              $this->extension->name = $manifest_details['name'];
 537              $this->extension->enabled = 1;
 538              $this->extension->params = $this->parent->getParams();
 539  
 540              if (!$this->extension->store()) {
 541                  // Install failed, roll back changes
 542                  throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_DISCOVER_STORE_DETAILS'));
 543              }
 544  
 545              return;
 546          }
 547  
 548          // Was there a template already installed with the same name?
 549          if ($this->currentExtensionId) {
 550              if (!$this->parent->isOverwrite()) {
 551                  // Install failed, roll back changes
 552                  throw new \RuntimeException(
 553                      Text::_('JLIB_INSTALLER_ABORT_TPL_INSTALL_ALREADY_INSTALLED')
 554                  );
 555              }
 556  
 557              // Load the entry and update the manifest_cache
 558              $this->extension->load($this->currentExtensionId);
 559          } else {
 560              $this->extension->type    = 'template';
 561              $this->extension->element = $this->element;
 562  
 563              // There is no folder for templates
 564              $this->extension->folder       = '';
 565              $this->extension->enabled      = 1;
 566              $this->extension->protected    = 0;
 567              $this->extension->access       = 1;
 568              $this->extension->client_id    = $this->clientId;
 569              $this->extension->params       = $this->parent->getParams();
 570              $this->extension->changelogurl = $this->changelogurl;
 571          }
 572  
 573          // Name might change in an update
 574          $this->extension->name = $this->name;
 575  
 576          // Update the manifest cache for the entry
 577          $this->extension->manifest_cache = $this->parent->generateManifestCache();
 578  
 579          $this->extension->changelogurl = $this->changelogurl;
 580  
 581          if (!$this->extension->store()) {
 582              // Install failed, roll back changes
 583              throw new \RuntimeException(
 584                  Text::sprintf(
 585                      'JLIB_INSTALLER_ABORT_ROLLBACK',
 586                      Text::_('JLIB_INSTALLER_' . strtoupper($this->route)),
 587                      $this->extension->getError()
 588                  )
 589              );
 590          }
 591      }
 592  
 593      /**
 594       * Discover existing but uninstalled templates
 595       *
 596       * @return  array  Extension list
 597       */
 598      public function discover()
 599      {
 600          $results    = array();
 601          $site_list  = Folder::folders(JPATH_SITE . '/templates');
 602          $admin_list = Folder::folders(JPATH_ADMINISTRATOR . '/templates');
 603          $site_info  = ApplicationHelper::getClientInfo('site', true);
 604          $admin_info = ApplicationHelper::getClientInfo('administrator', true);
 605  
 606          foreach ($site_list as $template) {
 607              if (file_exists(JPATH_SITE . "/templates/$template/templateDetails.xml")) {
 608                  if ($template === 'system') {
 609                      // Ignore special system template
 610                      continue;
 611                  }
 612  
 613                  $manifest_details = Installer::parseXMLInstallFile(JPATH_SITE . "/templates/$template/templateDetails.xml");
 614                  $extension        = Table::getInstance('extension');
 615                  $extension->set('type', 'template');
 616                  $extension->set('client_id', $site_info->id);
 617                  $extension->set('element', $template);
 618                  $extension->set('folder', '');
 619                  $extension->set('name', $template);
 620                  $extension->set('state', -1);
 621                  $extension->set('manifest_cache', json_encode($manifest_details));
 622                  $extension->set('params', '{}');
 623                  $results[] = $extension;
 624              }
 625          }
 626  
 627          foreach ($admin_list as $template) {
 628              if (file_exists(JPATH_ADMINISTRATOR . "/templates/$template/templateDetails.xml")) {
 629                  if ($template === 'system') {
 630                      // Ignore special system template
 631                      continue;
 632                  }
 633  
 634                  $manifest_details = Installer::parseXMLInstallFile(JPATH_ADMINISTRATOR . "/templates/$template/templateDetails.xml");
 635                  $extension        = Table::getInstance('extension');
 636                  $extension->set('type', 'template');
 637                  $extension->set('client_id', $admin_info->id);
 638                  $extension->set('element', $template);
 639                  $extension->set('folder', '');
 640                  $extension->set('name', $template);
 641                  $extension->set('state', -1);
 642                  $extension->set('manifest_cache', json_encode($manifest_details));
 643                  $extension->set('params', '{}');
 644                  $results[] = $extension;
 645              }
 646          }
 647  
 648          return $results;
 649      }
 650  
 651      /**
 652       * Refreshes the extension table cache
 653       *
 654       * @return  boolean  Result of operation, true if updated, false on failure
 655       *
 656       * @since   3.1
 657       */
 658      public function refreshManifestCache()
 659      {
 660          // Need to find to find where the XML file is since we don't store this normally.
 661          $client                 = ApplicationHelper::getClientInfo($this->parent->extension->client_id);
 662          $manifestPath           = $client->path . '/templates/' . $this->parent->extension->element . '/templateDetails.xml';
 663          $this->parent->manifest = $this->parent->isManifest($manifestPath);
 664          $this->parent->setPath('manifest', $manifestPath);
 665  
 666          $manifest_details                        = Installer::parseXMLInstallFile($this->parent->getPath('manifest'));
 667          $this->parent->extension->manifest_cache = json_encode($manifest_details);
 668          $this->parent->extension->name           = $manifest_details['name'];
 669  
 670          try {
 671              return $this->parent->extension->store();
 672          } catch (\RuntimeException $e) {
 673              Log::add(Text::_('JLIB_INSTALLER_ERROR_TPL_REFRESH_MANIFEST_CACHE'), Log::WARNING, 'jerror');
 674  
 675              return false;
 676          }
 677      }
 678  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer