[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/src/MVC/Model/ -> BaseDatabaseModel.php (source)

   1  <?php
   2  
   3  /**
   4   * Joomla! Content Management System
   5   *
   6   * @copyright  (C) 2006 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\MVC\Model;
  11  
  12  use Joomla\CMS\Cache\CacheControllerFactoryAwareInterface;
  13  use Joomla\CMS\Cache\CacheControllerFactoryAwareTrait;
  14  use Joomla\CMS\Cache\Controller\CallbackController;
  15  use Joomla\CMS\Cache\Exception\CacheExceptionInterface;
  16  use Joomla\CMS\Component\ComponentHelper;
  17  use Joomla\CMS\Extension\ComponentInterface;
  18  use Joomla\CMS\Factory;
  19  use Joomla\CMS\Language\Text;
  20  use Joomla\CMS\MVC\Factory\LegacyFactory;
  21  use Joomla\CMS\MVC\Factory\MVCFactoryAwareTrait;
  22  use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
  23  use Joomla\CMS\MVC\Factory\MVCFactoryServiceInterface;
  24  use Joomla\CMS\Table\Table;
  25  use Joomla\CMS\User\CurrentUserInterface;
  26  use Joomla\CMS\User\CurrentUserTrait;
  27  use Joomla\Database\DatabaseAwareInterface;
  28  use Joomla\Database\DatabaseAwareTrait;
  29  use Joomla\Database\DatabaseInterface;
  30  use Joomla\Database\DatabaseQuery;
  31  use Joomla\Database\Exception\DatabaseNotFoundException;
  32  use Joomla\Event\DispatcherAwareInterface;
  33  use Joomla\Event\DispatcherAwareTrait;
  34  use Joomla\Event\DispatcherInterface;
  35  use Joomla\Event\Event;
  36  use Joomla\Event\EventInterface;
  37  
  38  // phpcs:disable PSR1.Files.SideEffects
  39  \defined('JPATH_PLATFORM') or die;
  40  // phpcs:enable PSR1.Files.SideEffects
  41  
  42  /**
  43   * Base class for a database aware Joomla Model
  44   *
  45   * Acts as a Factory class for application specific objects and provides many supporting API functions.
  46   *
  47   * @since  2.5.5
  48   */
  49  abstract class BaseDatabaseModel extends BaseModel implements
  50      DatabaseModelInterface,
  51      DispatcherAwareInterface,
  52      CurrentUserInterface,
  53      CacheControllerFactoryAwareInterface,
  54      DatabaseAwareInterface
  55  {
  56      use DatabaseAwareTrait;
  57      use MVCFactoryAwareTrait;
  58      use DispatcherAwareTrait;
  59      use CurrentUserTrait;
  60      use CacheControllerFactoryAwareTrait;
  61  
  62      /**
  63       * The URL option for the component.
  64       *
  65       * @var    string
  66       * @since  3.0
  67       */
  68      protected $option = null;
  69  
  70      /**
  71       * The event to trigger when cleaning cache.
  72       *
  73       * @var    string
  74       * @since  3.0
  75       */
  76      protected $event_clean_cache = null;
  77  
  78      /**
  79       * Constructor
  80       *
  81       * @param   array                $config   An array of configuration options (name, state, dbo, table_path, ignore_request).
  82       * @param   MVCFactoryInterface  $factory  The factory.
  83       *
  84       * @since   3.0
  85       * @throws  \Exception
  86       */
  87      public function __construct($config = array(), MVCFactoryInterface $factory = null)
  88      {
  89          parent::__construct($config);
  90  
  91          // Guess the option from the class name (Option)Model(View).
  92          if (empty($this->option)) {
  93              $r = null;
  94  
  95              if (!preg_match('/(.*)Model/i', \get_class($this), $r)) {
  96                  throw new \Exception(Text::sprintf('JLIB_APPLICATION_ERROR_GET_NAME', __METHOD__), 500);
  97              }
  98  
  99              $this->option = ComponentHelper::getComponentName($this, $r[1]);
 100          }
 101  
 102          /**
 103           * @deprecated 5.0 Database instance is injected through the setter function,
 104           *                 subclasses should not use the db instance in constructor anymore
 105           */
 106          $db = \array_key_exists('dbo', $config) ? $config['dbo'] : Factory::getDbo();
 107  
 108          if ($db) {
 109              @trigger_error(sprintf('Database is not available in constructor in 5.0.'), E_USER_DEPRECATED);
 110              $this->setDatabase($db);
 111  
 112              // Is needed, when models use the deprecated MVC DatabaseAwareTrait, as the trait is overriding the local functions
 113              $this->setDbo($db);
 114          }
 115  
 116          // Set the default view search path
 117          if (\array_key_exists('table_path', $config)) {
 118              $this->addTablePath($config['table_path']);
 119          } elseif (\defined('JPATH_COMPONENT_ADMINISTRATOR')) {
 120              $this->addTablePath(JPATH_COMPONENT_ADMINISTRATOR . '/tables');
 121              $this->addTablePath(JPATH_COMPONENT_ADMINISTRATOR . '/table');
 122          }
 123  
 124          // Set the clean cache event
 125          if (isset($config['event_clean_cache'])) {
 126              $this->event_clean_cache = $config['event_clean_cache'];
 127          } elseif (empty($this->event_clean_cache)) {
 128              $this->event_clean_cache = 'onContentCleanCache';
 129          }
 130  
 131          if ($factory) {
 132              $this->setMVCFactory($factory);
 133  
 134              return;
 135          }
 136  
 137          $component = Factory::getApplication()->bootComponent($this->option);
 138  
 139          if ($component instanceof MVCFactoryServiceInterface) {
 140              $this->setMVCFactory($component->getMVCFactory());
 141          }
 142      }
 143  
 144      /**
 145       * Gets an array of objects from the results of database query.
 146       *
 147       * @param   string   $query       The query.
 148       * @param   integer  $limitstart  Offset.
 149       * @param   integer  $limit       The number of records.
 150       *
 151       * @return  object[]  An array of results.
 152       *
 153       * @since   3.0
 154       * @throws  \RuntimeException
 155       */
 156      protected function _getList($query, $limitstart = 0, $limit = 0)
 157      {
 158          if (\is_string($query)) {
 159              $query = $this->getDbo()->getQuery(true)->setQuery($query);
 160          }
 161  
 162          $query->setLimit($limit, $limitstart);
 163          $this->getDbo()->setQuery($query);
 164  
 165          return $this->getDbo()->loadObjectList();
 166      }
 167  
 168      /**
 169       * Returns a record count for the query.
 170       *
 171       * Note: Current implementation of this method assumes that getListQuery() returns a set of unique rows,
 172       * thus it uses SELECT COUNT(*) to count the rows. In cases that getListQuery() uses DISTINCT
 173       * then either this method must be overridden by a custom implementation at the derived Model Class
 174       * or a GROUP BY clause should be used to make the set unique.
 175       *
 176       * @param   DatabaseQuery|string  $query  The query.
 177       *
 178       * @return  integer  Number of rows for query.
 179       *
 180       * @since   3.0
 181       */
 182      protected function _getListCount($query)
 183      {
 184          // Use fast COUNT(*) on DatabaseQuery objects if there is no GROUP BY or HAVING clause:
 185          if (
 186              $query instanceof DatabaseQuery
 187              && $query->type === 'select'
 188              && $query->group === null
 189              && $query->merge === null
 190              && $query->querySet === null
 191              && $query->having === null
 192          ) {
 193              $query = clone $query;
 194              $query->clear('select')->clear('order')->clear('limit')->clear('offset')->select('COUNT(*)');
 195  
 196              $this->getDbo()->setQuery($query);
 197  
 198              return (int) $this->getDbo()->loadResult();
 199          }
 200  
 201          // Otherwise fall back to inefficient way of counting all results.
 202  
 203          // Remove the limit, offset and order parts if it's a DatabaseQuery object
 204          if ($query instanceof DatabaseQuery) {
 205              $query = clone $query;
 206              $query->clear('limit')->clear('offset')->clear('order');
 207          }
 208  
 209          $this->getDbo()->setQuery($query);
 210          $this->getDbo()->execute();
 211  
 212          return (int) $this->getDbo()->getNumRows();
 213      }
 214  
 215      /**
 216       * Method to load and return a table object.
 217       *
 218       * @param   string  $name    The name of the view
 219       * @param   string  $prefix  The class prefix. Optional.
 220       * @param   array   $config  Configuration settings to pass to Table::getInstance
 221       *
 222       * @return  Table|boolean  Table object or boolean false if failed
 223       *
 224       * @since   3.0
 225       * @see     \JTable::getInstance()
 226       */
 227      protected function _createTable($name, $prefix = 'Table', $config = array())
 228      {
 229          // Make sure we are returning a DBO object
 230          if (!\array_key_exists('dbo', $config)) {
 231              $config['dbo'] = $this->getDbo();
 232          }
 233  
 234          return $this->getMVCFactory()->createTable($name, $prefix, $config);
 235      }
 236  
 237      /**
 238       * Method to get a table object, load it if necessary.
 239       *
 240       * @param   string  $name     The table name. Optional.
 241       * @param   string  $prefix   The class prefix. Optional.
 242       * @param   array   $options  Configuration array for model. Optional.
 243       *
 244       * @return  Table  A Table object
 245       *
 246       * @since   3.0
 247       * @throws  \Exception
 248       */
 249      public function getTable($name = '', $prefix = '', $options = array())
 250      {
 251          if (empty($name)) {
 252              $name = $this->getName();
 253          }
 254  
 255          // We need this ugly code to deal with non-namespaced MVC code
 256          if (empty($prefix) && $this->getMVCFactory() instanceof LegacyFactory) {
 257              $prefix = 'Table';
 258          }
 259  
 260          if ($table = $this->_createTable($name, $prefix, $options)) {
 261              return $table;
 262          }
 263  
 264          throw new \Exception(Text::sprintf('JLIB_APPLICATION_ERROR_TABLE_NAME_NOT_SUPPORTED', $name), 0);
 265      }
 266  
 267      /**
 268       * Method to check if the given record is checked out by the current user
 269       *
 270       * @param   \stdClass  $item  The record to check
 271       *
 272       * @return  bool
 273       */
 274      public function isCheckedOut($item)
 275      {
 276          $table = $this->getTable();
 277          $checkedOutField = $table->getColumnAlias('checked_out');
 278  
 279          if (property_exists($item, $checkedOutField) && $item->{$checkedOutField} != $this->getCurrentUser()->id) {
 280              return true;
 281          }
 282  
 283          return false;
 284      }
 285  
 286      /**
 287       * Clean the cache
 288       *
 289       * @param   string  $group  The cache group
 290       *
 291       * @return  void
 292       *
 293       * @since   3.0
 294       */
 295      protected function cleanCache($group = null)
 296      {
 297          $app = Factory::getApplication();
 298  
 299          $options = [
 300              'defaultgroup' => $group ?: ($this->option ?? $app->input->get('option')),
 301              'cachebase'    => $app->get('cache_path', JPATH_CACHE),
 302              'result'       => true,
 303          ];
 304  
 305          try {
 306              /** @var CallbackController $cache */
 307              $cache = $this->getCacheControllerFactory()->createCacheController('callback', $options);
 308              $cache->clean();
 309          } catch (CacheExceptionInterface $exception) {
 310              $options['result'] = false;
 311          }
 312  
 313          // Trigger the onContentCleanCache event.
 314          $this->dispatchEvent(new Event($this->event_clean_cache, $options));
 315      }
 316  
 317      /**
 318       * Boots the component with the given name.
 319       *
 320       * @param   string  $component  The component name, eg. com_content.
 321       *
 322       * @return  ComponentInterface  The service container
 323       *
 324       * @since   4.0.0
 325       */
 326      protected function bootComponent($component): ComponentInterface
 327      {
 328          return Factory::getApplication()->bootComponent($component);
 329      }
 330  
 331      /**
 332       * Dispatches the given event on the internal dispatcher, does a fallback to the global one.
 333       *
 334       * @param   EventInterface  $event  The event
 335       *
 336       * @return  void
 337       *
 338       * @since   4.1.0
 339       */
 340      protected function dispatchEvent(EventInterface $event)
 341      {
 342          try {
 343              $this->getDispatcher()->dispatch($event->getName(), $event);
 344          } catch (\UnexpectedValueException $e) {
 345              Factory::getContainer()->get(DispatcherInterface::class)->dispatch($event->getName(), $event);
 346          }
 347      }
 348  
 349      /**
 350       * Get the database driver.
 351       *
 352       * @return  DatabaseInterface  The database driver.
 353       *
 354       * @since   4.2.0
 355       * @throws  \UnexpectedValueException
 356       *
 357       * @deprecated  5.0 Use getDatabase() instead
 358       */
 359      public function getDbo()
 360      {
 361          try {
 362              return $this->getDatabase();
 363          } catch (DatabaseNotFoundException $e) {
 364              throw new \UnexpectedValueException('Database driver not set in ' . __CLASS__);
 365          }
 366      }
 367  
 368      /**
 369       * Set the database driver.
 370       *
 371       * @param   DatabaseInterface  $db  The database driver.
 372       *
 373       * @return  void
 374       *
 375       * @since   4.2.0
 376       *
 377       * @deprecated  5.0 Use setDatabase() instead
 378       */
 379      public function setDbo(DatabaseInterface $db = null)
 380      {
 381          if ($db === null) {
 382              return;
 383          }
 384  
 385          $this->setDatabase($db);
 386      }
 387  
 388      /**
 389       * Proxy for _db variable.
 390       *
 391       * @param   string  $name  The name of the element
 392       *
 393       * @return  mixed  The value of the element if set, null otherwise
 394       *
 395       * @since   4.2.0
 396       *
 397       * @deprecated  5.0 Use getDatabase() instead of directly accessing _db
 398       */
 399      public function __get($name)
 400      {
 401          if ($name === '_db') {
 402              return $this->getDbo();
 403          }
 404  
 405          // Default the variable
 406          if (!isset($this->$name)) {
 407              $this->$name = null;
 408          }
 409  
 410          return $this->$name;
 411      }
 412  }


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