Файловый менеджер - Редактировать - /var/www/html/libraries/kunena/src/Table/KunenaTableObject.php
Ðазад
<?php /** * Kunena Component * * @package Kunena.Framework * @subpackage Table * * @copyright Copyright (C) 2008 - @currentyear@ Kunena Team. All rights reserved. * @license https://www.gnu.org/copyleft/gpl.html GNU/GPL * @link https://www.kunena.org **/ namespace Kunena\Forum\Libraries\Table; \defined('_JEXEC') or die(); use Closure; use InvalidArgumentException; use Joomla\CMS\Factory; use Joomla\CMS\Table\Table; use Joomla\Database\DatabaseDriver; use Joomla\Database\QueryInterface; use Kunena\Forum\Libraries\Database\KunenaDatabaseObject; use RuntimeException; use UnexpectedValueException; /** * Abstract Table Object class * * Parent class to all table objects. * * Note: If you set default values for the fields, please keep at least one default key value as null! * * @since Kunena 6.0 */ abstract class KunenaTableObject { /** * Store all instances of this type by Id. * Always override this variable in your own class! * * @var array * @since Kunena 4.0 */ protected static $instances = null; /** * Name of the database table to model. * Always override this variable in your own class! * * @var string * @since Kunena 4.0 */ protected static $tbl = ''; /** * Array of table fields with their default value (field=>default). * You can either fill up your table structure or leave base class to fetch the fields for you. * * @var array * @since Kunena 4.0 */ protected static $tbl_fields; /** * Array of primary key fields in the table. * Always override this variable in your own class! * * @var array * @since Kunena 4.0 */ protected static $tbl_keys = []; /** * DatabaseDriver object. * * @var DatabaseDriver * @since Kunena 4.0 */ protected static $db; /** * Indicator that the tables have been locked. * * @var boolean * @since Kunena 4.0 */ protected static $_locked = false; private static $tbl_key; private static $locked; /** * Flag whether the object exists in the database or not. * * @var boolean * @since Kunena 4.0 */ protected $_exists = false; /** * Serialized key for the object. * * @var string * @since Kunena 4.0 */ protected $_key; /** * Constructor to create the table object instance. All objects with key set are stored into global instances. * * @param array $keys Name of the primary key field in the table. * * @since Kunena 4.0 */ public function __construct($keys = null) { // First run: Initialise the table properties. if (\is_null(static::$tbl_fields)) { static::getFields(); } $exists = false; $tbl_keys = []; if ($keys === null) { // We need to check a special case where object properties have already been set. // This happens only if $db->loadObject() or $db->loadObjectList() are called with a class type. // Build storage key for the object. foreach (static::$tbl_keys as $keyName) { $keyValue = isset($this->$keyName) ? $this->$keyName : null; $exists |= ($keyValue !== null); $tbl_keys[$keyName] = $keyValue; } if ($exists) { if (\is_array(static::$instances)) { // Yes, we are in the special case. $this->_key = \count($tbl_keys) > 1 ? json_encode($tbl_keys) : reset($tbl_keys); if (isset(static::$instances[$this->_key])) { // If we already had loaded the object, we can stop now. // This is because of we keep only one global instance from the object. return; } } // Initialise the object. $this->_exists = true; $this->initialise(true); } } if (!$exists) { $exists = $this->load($keys); if ($exists) { // Build storage key for the object. foreach (static::$tbl_keys as $keyName) { $tbl_keys[$keyName] = isset($this->$keyName) ? $this->$keyName : null; } } } if ($exists && \is_array(static::$instances)) { $this->_key = \count($tbl_keys) > 1 ? json_encode($tbl_keys) : reset($tbl_keys); if (!isset(static::$instances[$this->_key])) { // Add the new object into the instances. static::$instances[$this->_key] = $this; } } } /** * Get the database columns. * * @return int[]|string[] An array of the field names, or false if an error occurs. * * @since Kunena 4.0 * * @throws UnexpectedValueException */ public static function getFields() { if (static::$tbl_fields === null) { // Lookup the fields for this table only once. static::$tbl_fields = static::$db->getTableColumns(static::$tbl, false); if (empty(static::$tbl_fields)) { throw new UnexpectedValueException(sprintf('No columns found for %s table', static::$tbl)); } } return array_keys(static::$tbl_fields); } /** * Override this function if you need to initialise object right after creating it. * * Can be used for example if the database fields need to be converted to array or Joomla\Registry\Registry. * * @param bool $sqlFetch True only if properties were assigned before constructor was called. * * @return void * * @since Kunena 4.0 */ protected function initialise($sqlFetch = false): void { } /** * @param null $keys keys * @param bool $reset reset * * @return boolean|KunenaTableObject * * @since Kunena 6.0 */ protected function load($keys = null, $reset = true) { try { $keys = $this->getKeyValues($keys); } catch (UnexpectedValueException $e) { if ($e->getCode() == 0) { // Key not fully given, no need to load the item. foreach ($keys as $field => $value) { // Make sure the object contains the search fields. $this->$field = $value; } return false; } // Error, throw it forward. throw $e; } if ($reset) { $this->reset(); } $k = static::$tbl; // Initialise the query. $query = static::$db->createQuery() ->select('*') ->from(static::$db->quoteName($k)); foreach ($keys as $field => $value) { // Make sure the object contains the search fields. // This is incompatible to Joomla\CMS\Table\Table, but needed by this class. $this->$field = $value; // Add the search tuple to the query. $query->where(static::$db->quoteName($field) . ' = ' . static::$db->quote($value)); } $query->setLimit(1); static::$db->setQuery($query); $row = static::$db->loadAssoc(); // Check that we have a result. if (empty($row)) { return false; } // Bind the object with the row and return. return $this->_exists = $this->bind($row); } /** * Returns all keys and their values as an array. * * @param array|string $fields fields * @param bool $throw throw * * @return array * * @since Kunena 4.0 */ protected function getKeyValues($fields = null, $throw = true): array { // FIXME: bug... static $fieldNames = null; $tableKeys = static::$tbl_keys; $keys = []; if (\is_null($fields)) { // No fields were given as parameter: use table instance. foreach ($tableKeys as $keyName) { $keyValue = isset($this->$keyName) ? $this->$keyName : null; $keys[$keyName] = $keyValue; // If null primary keys aren't allowed if ($throw && \is_null($keyValue)) { throw new UnexpectedValueException(sprintf('%s: Null primary key not allowed   %s..', \get_class($this), $keyName), 0); } } } else { if (\is_null($fieldNames)) { // Lazy initialize fields list. $fieldNames = static::getFields(); } if (!\is_array($fields)) { $fields = (array) $fields; } foreach ($fields as $keyName => $keyValue) { // Check if key in given numeric location exists. if (is_numeric($keyName)) { if (!isset($tableKeys[$keyName])) { throw new UnexpectedValueException(sprintf('%s: Missing key in index %s.', \get_class($this), $keyName), 1); } // Find out key name in given numeric location and use it. $keyName = $tableKeys[$keyName]; } $keys[$keyName] = $keyValue; // Verify that the used key exists in the table. if (!\in_array($keyName, $fieldNames)) { throw new UnexpectedValueException(sprintf('%s: Missing field in database: %s.', \get_class($this), $keyName), 2); } } } // Make sure user didn't pass empty array. if (empty($keys)) { throw new UnexpectedValueException(sprintf('%s: No fields given.', \get_class($this)), 3); } return $keys; } /** * Method to reset class properties to the defaults set in the class * definition. It will ignore the primary key. * * If you want to reset other properties, you need to override the function. * * @return KunenaTableObject * * @since Kunena 4.0 */ public function reset(): KunenaTableObject { // Get the default values for the class from the table. foreach (static::$tbl_fields as $k => $v) { // If the property is not the primary key. if (!\in_array($k, static::$tbl_keys)) { $this->$k = $v->Default; } } return $this; } /** * Method to bind an associative array or object to the Joomla\CMS\Table\Table instance.This * method only binds properties that are publicly accessible and optionally * takes an array of properties to ignore when binding. * * @param mixed $src An associative array or object to bind to the Joomla\CMS\Table\Table instance. * @param mixed $ignore An optional array or space separated list of properties to ignore while binding. * * @return KunenaTableObject * * @since Kunena 4.0 * * @throws InvalidArgumentException */ public function bind($src, $ignore = []): KunenaTableObject { // If the source value is not an array or object return false. if (!\is_object($src) && !\is_array($src)) { throw new InvalidArgumentException(sprintf('%s::bind(*%s*)', \get_class($this), \gettype($src))); } // If the source value is an object, get its accessible properties. if (\is_object($src)) { $src = get_object_vars($src); } // If the ignore value is a string, explode it over spaces. if (!\is_array($ignore)) { $ignore = explode(' ', $ignore); } // Bind the source value, excluding the ignored fields. foreach ($this->getProperties() as $k => $v) { // Only process fields not in the ignore array. if (!\in_array($k, $ignore)) { if (isset($src[$k])) { $this->$k = $src[$k]; } } } return $this; } /** * Returns an associative array of object properties. * * @return Closure * * @since Kunena 4.0 */ public function getProperties() { // Use closure to return public variables only. $self = $this; return function () use ($self) { return get_object_vars($self); }; } /** * Method to get the DatabaseDriver object. * * @return DatabaseDriver The internal database driver object. * * @since Kunena 4.0 */ public static function getDatabase(): DatabaseDriver { return static::$db; } /** * Method to set the DatabaseDriver object. * * @link http://docs.joomla.org/Joomla\CMS\Table\Table/setDbo * * @param DatabaseDriver $db A DatabaseDriver object to be used by the table object. * * @return boolean True on success. * * @since K4.0 */ public static function setDbo(DatabaseDriver $db): bool { static::$db = $db; return true; } /** * Returns the global instance to the object. * * Note that using array of fields will always make a query to the database, but it's very useful feature if you * want to search one item by using arbitrary set of matching fields. If there are more than one matching object, * first one gets returned. * * @param int|array $keys An optional primary key value to load the object by, or an array of fields to match. * * @return KunenaDatabaseObject * * @since Kunena 4.0 * * @throw RuntimeException */ public static function getInstance($keys): KunenaDatabaseObject { $k = json_encode(self::resolveKeys($keys)); // FIXME: $k = (int) $keys; // If we are creating or loading a new item or we load instance by alternative keys, // we need to create a new object. if (!isset(static::$instances[$k])) { $c = \get_called_class(); $instance = new $c($keys); // @var KunenaTableObject $instance if (!$instance->exists()) { return $instance; } // Instance exists: make sure that we return the global instance. $k = $instance->_key; } // Return global instance from the identifier. $instance = static::$instances[$k]; // But before that, check that we have valid item. if ($k != $instance->_key) { throw new RuntimeException(\get_called_class() . ": Identifier doesn't match ({$k} != {$instance->_key})"); } return $instance; } /** * Returns all keys and their values as an array. * * @param array|string $fields fields * * @return array * * @since Kunena 4.0 * * @throws UnexpectedValueException */ protected static function resolveKeys($fields): array { // First run: Initialise the table properties. if (\is_null(static::$tbl_fields)) { static::getFields(); } $keys = []; if (!\is_array($fields)) { $fields = (array) $fields; } foreach ($fields as $keyName => $keyValue) { // Check if key in given numeric location exists. if (is_numeric($keyName)) { if (!isset(static::$tbl_keys[$keyName])) { throw new UnexpectedValueException(sprintf('%s: Missing key in index: %s.', \get_called_class(), $keyName), 1); } // Find out key name in given numeric location and use it. $keyName = static::$tbl_keys[$keyName]; } $keys[$keyName] = $keyValue; // Verify that the used key exists in the table. if (!isset(static::$tbl_fields[$keyName])) { throw new UnexpectedValueException(sprintf('%s: Missing field in database: %s.', \get_called_class(), $keyName), 2); } } // Make sure user didn't pass empty array. if (empty($keys)) { throw new UnexpectedValueException(sprintf('%s: No fields given.', \get_called_class()), 3); } return $keys; } /** * For internal use only. * * @return array|null * * @since Kunena 6.0 */ public static function &getInstances(): ?array { return static::$instances; } /** * Removes all or selected instances from the object cache. * * @param null|int|array $ids ids * * @return void * * @since Kunena 4.0 */ public static function freeInstances($ids = null): void { if (!isset(static::$instances)) { return; } if ($ids === null) { $ids = array_keys(static::$instances); } $ids = (array) $ids; foreach ($ids as $id) { unset(static::$instances[$id]); } } /** * @internal * * @return \Joomla\Database\DatabaseQuery * * @since Kunena 6.0 */ public static function getQuery() { $db = static::$db; return $db->createQuery() ->select($db->quoteName('a.*')) ->from($db->quoteName(static::$tbl, 'a')); } /** * @internal * * @param QueryInterface $query query * * @return array * * @since Kunena 6.0 */ public static function &loadInstances(QueryInterface $query): array { $db = Factory::getContainer()->get('DatabaseDriver'); $db->createQuery(); $items = (array) $db->loadObjectList('id', \get_called_class()); if (\is_array(static::$instances)) { static::$instances += $items; } return $items; } /** * @return string * * @since Kunena 6.0 */ public function getId(): string { return $this->_key; } /** * Method to provide a shortcut to binding, checking and storing a Joomla\CMS\Table\Table * instance to the database table. The method will check a row in once the * data has been stored and if an ordering filter is present will attempt to * reOrder the table rows based on the filter. The ordering filter is an instance * property name. The rows that will be reOrdered are those whose value matches * the Joomla\CMS\Table\Table instance for the property specified. * * @param mixed $src An associative array or object to bind to the Joomla\CMS\Table\Table instance. * @param string $orderingFilter Filter for the order updating * @param mixed $ignore An optional array or space separated list of properties * to ignore while binding. * * @return boolean True on success. * * @since Kunena 4.0 */ /* public function save($src, $orderingFilter = '', $ignore = '') { // Attempt to bind the source to the instance. if (!$this->bind($src, $ignore)) { return false; } // Run any sanity checks on the instance and verify that it is ready for storage. if (!$this->check()) { return false; } // Attempt to store the properties to the database table. if (!$this->store()) { return false; } // Attempt to check the row in, just in case it was checked out. if (!$this->checkIn()) { return false; } // If an ordering filter is set, attempt reOrder the rows in the table based on the filter and value. if ($orderingFilter) { $filterValue = $this->$orderingFilter; $this->reOrder($orderingFilter ? static::$db->quoteName($orderingFilter) . ' = ' . static::$db->quote($filterValue) : ''); } // Throw exception to empty and return true. throw new Exception(''); return true; } */ /** * Create almost identical copy of the object, but clean up the key fields. * * New object will also return false on $new->exists() until it gets saved. * * @return void * * @since Kunena 4.0 */ public function __clone() { foreach (static::$tbl_keys as $keyName) { $this->$keyName = null; } $this->_exists = false; } /** * Method to perform sanity checks on the Joomla\CMS\Table\TableObject instance properties to ensure * they are safe to store in the database. Child classes should override this * method to make sure the data they are storing in the database is safe and * as expected before storage. * * @return boolean True if the instance is sane and able to be stored in the database. * * @since Kunena 4.0 */ public function check(): bool { return true; } /** * @param bool $updateNulls update * * @return boolean * * @since Kunena 6.0 */ public function store($updateNulls = false): bool { if ($this->exists()) { try { static::$db->updateObject(static::$tbl, $this, static::$tbl_keys, $updateNulls); } catch (RuntimeException $e) { throw new RuntimeException(\get_class($this) . '::store failed - ' . $e->getMessage()); return false; } } else { try { static::$db->insertObject(static::$tbl, $this, static::$tbl_keys); } catch (RuntimeException $e) { throw new RuntimeException(\get_class($this) . '::store failed - ' . $e->getMessage()); return false; } } if (static::$locked) { $this->unlock(); } $this->_exists = true; return true; } /** * Returns true if the object exists in the database. * * @param boolean $exists Internal parameter to change state. * * @return boolean True if object exists in database. * * @since Kunena 4.0 */ public function exists($exists = null): bool { $return = $this->_exists; if ($exists !== null) { $this->_exists = $exists; } return $return; } /** * Method to unlock the database table for writing. * * @return boolean True on success. * * @since Kunena 4.0 */ protected function unlock(): bool { static::$db->unlockTables(); static::$_locked = false; return true; } /** * Method to delete a row from the database table by primary key value. * * @param mixed $keys An optional primary key value to delete. If not set the * instance property value is used. If array given, you can * use arbitrary fields to delete more than one item. * * @return boolean True on success. * * @since Kunena 4.0 * * @throws UnexpectedValueException */ public function delete($keys = null): bool { try { $keys = $this->getKeyValues($keys); } catch (UnexpectedValueException $e) { throw $e; } $k = static::$tbl; // Delete the row by given keys/fields. $query = static::$db->createQuery() ->delete() ->from(static::$db->quoteName($k)); foreach ($keys as $key => $value) { $query->where(static::$db->quoteName($key) . ' = ' . static::$db->quote($value)); } $query->setLimit(1); static::$db->setQuery($query); static::$db->execute(); return true; } /** * Method to check a row out if the necessary properties/fields exist. To * prevent race conditions while editing rows in a database, a row can be * checked out if the fields 'checked_out' and 'checked_out_time' are available. * While a row is checked out, any attempt to store the row by a user other * than the one who checked the row out should be held until the row is checked * in again. * * @param integer $userId The Id of the user checking out the row. * @param mixed $pk An optional primary key value to check out. If not set * the instance property value is used. * * @return boolean True on success. * * @since Kunena 4.0 */ public function checkOut(int $userId, $pk = null): bool { // If there is no checked_out or checked_out_time field, just return true. if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time')) { return true; } $k = static::$tbl_key; $pk = (\is_null($pk)) ? $this->$k : $pk; // If no primary key is given, return false. if ($pk === null) { throw new UnexpectedValueException('Null primary key not allowed.'); } // Get the current time in MySQL format. $time = Factory::getDate()->toSql(); // Check the row out by primary key. $query = static::$db->createQuery() ->update(static::$tbl) ->set(static::$db->quoteName('checked_out') . ' = ' . static::$db->quote((int) $userId)) ->set(static::$db->quoteName('checked_out_time') . ' = ' . static::$db->quote($time)) ->where(static::$db->quoteName($k) . ' = ' . static::$db->quote($pk)); static::$db->setQuery($query); static::$db->execute(); // Set table values in the object. $this->checked_out = (int) $userId; $this->checked_out_time = $time; return true; } /** * Method to check a row in if the necessary properties/fields exist. Checking * a row in will allow other users the ability to edit the row. * * @param mixed $pk An optional primary key value to check out. If not set the instance property value is used. * * @return boolean True on success. * * @since Kunena 4.0 */ public function checkIn($pk = null): bool { // If there is no checked_out or checked_out_time field, just return true. if (!property_exists($this, 'checked_out') || !property_exists($this, 'checked_out_time')) { return true; } $k = static::$tbl_keys; $pk = (\is_null($pk)) ? $this->$k : $pk; // If no primary key is given, return false. if ($pk === null) { throw new UnexpectedValueException('Null primary key not allowed.'); } // Check the row in by primary key. $query = static::$db->createQuery(); $nullDate = static::$db->getNullDate() ? static::$db->quote(static::$db->getNullDate()) : 'NULL'; $query->update(static::$tbl) ->set(static::$db->quoteName('checked_out') . ' = 0') ->set(static::$db->quoteName('checked_out_time') . ' = ' . $nullDate) ->where(static::$db->quoteName($k) . ' = ' . static::$db->quote($pk)); static::$db->setQuery($query); // Check for a database error. static::$db->execute(); // Set table values in the object. $this->checked_out = 0; $this->checked_out_time = null; return true; } /** * Method to increment the hits for a row if the necessary property/field exists. * * @internal param mixed $pk An optional primary key value to increment. If not set the instance property value is * used. * * @return boolean True on success. * * @since Kunena 4.0 */ public function hit(): bool { $pk = null; // If there is no hits field, just return true. if (!property_exists($this, 'hits')) { return true; } $k = static::$tbl_keys; $pk = (\is_null($pk)) ? $this->$k : $pk; // If no primary key is given, return false. if ($pk === null) { return false; } // Check the row in by primary key. $query = static::$db->createQuery() ->update(static::$tbl) ->set(static::$db->quoteName('hits') . ' = (' . static::$db->quoteName('hits') . ' + 1)') ->where(static::$db->quoteName($k) . ' = ' . static::$db->quote($pk)); static::$db->setQuery($query); static::$db->execute(); // Set table values in the object. $this->hits++; return true; } /** * Method to determine if a row is checked out and therefore editable by * a user. If the row is checked out by the same user, then it is considered * not checked out -- as the user can still edit it. * * @param integer $with The userid to preform the match with, if an item is checked * out by this user the function will return false. * @param integer $against The userid to perform the match against when the function * is used as a static function. * * @return boolean True if checked out. * * @since Kunena 4.0 */ public function isCheckedOut($with = 0, $against = null): bool { // Handle the non-static case. if (isset($this) && ($this instanceof Table) && \is_null($against)) { $against = $this->get('checked_out'); } // The item is not checked out or is checked out by the same user. if (!$against || ($against == $with)) { return false; } static::$db = Factory::getContainer()->get('DatabaseDriver'); static::$db->setQuery('SELECT COUNT(' . static::$db->quoteName('userid') . ')' . ' FROM ' . static::$db->quoteName('#__session') . ' WHERE ' . static::$db->quoteName('userid') . ' = ' . static::$db->quote((int) $against)); // If a session exists for the user then it is checked out. return (bool) static::$db->loadResult(); } /** * Method to lock the database table for writing. * * @return boolean True on success. * * @since Kunena 4.0 * * @throws RuntimeException */ protected function lock(): bool { static::$db->lockTable(static::$tbl); static::$_locked = true; return true; } } KunenaTableObject::setDbo(Factory::getContainer()->get('db'));
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка