diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:44:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:44:51 +0000 |
commit | a1ec78bf0dc93d0e05e5f066f1949dc3baecea06 (patch) | |
tree | ee596ce1bc9840661386f96f9b8d1f919a106317 /vendor/gipfl/zfdbstore | |
parent | Initial commit. (diff) | |
download | icingaweb2-module-incubator-a1ec78bf0dc93d0e05e5f066f1949dc3baecea06.tar.xz icingaweb2-module-incubator-a1ec78bf0dc93d0e05e5f066f1949dc3baecea06.zip |
Adding upstream version 0.20.0.upstream/0.20.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gipfl/zfdbstore')
-rw-r--r-- | vendor/gipfl/zfdbstore/composer.json | 16 | ||||
-rw-r--r-- | vendor/gipfl/zfdbstore/src/BaseStore.php | 112 | ||||
-rw-r--r-- | vendor/gipfl/zfdbstore/src/DbStorable.php | 79 | ||||
-rw-r--r-- | vendor/gipfl/zfdbstore/src/DbStorableInterface.php | 36 | ||||
-rw-r--r-- | vendor/gipfl/zfdbstore/src/NotFoundError.php | 9 | ||||
-rw-r--r-- | vendor/gipfl/zfdbstore/src/Storable.php | 323 | ||||
-rw-r--r-- | vendor/gipfl/zfdbstore/src/StorableInterface.php | 44 | ||||
-rw-r--r-- | vendor/gipfl/zfdbstore/src/Store.php | 24 | ||||
-rw-r--r-- | vendor/gipfl/zfdbstore/src/ZfDbStore.php | 241 |
9 files changed, 884 insertions, 0 deletions
diff --git a/vendor/gipfl/zfdbstore/composer.json b/vendor/gipfl/zfdbstore/composer.json new file mode 100644 index 0000000..dc84939 --- /dev/null +++ b/vendor/gipfl/zfdbstore/composer.json @@ -0,0 +1,16 @@ +{ + "name": "gipfl/zfdbstore", + "description": "Storable class helpers for ZfDb", + "type": "library", + "require": { + "php": ">=5.6" + }, + "config": { + "sort-packages": true + }, + "autoload": { + "psr-4": { + "gipfl\\ZfDbStore\\": "src" + } + } +} diff --git a/vendor/gipfl/zfdbstore/src/BaseStore.php b/vendor/gipfl/zfdbstore/src/BaseStore.php new file mode 100644 index 0000000..176ec33 --- /dev/null +++ b/vendor/gipfl/zfdbstore/src/BaseStore.php @@ -0,0 +1,112 @@ +<?php + +namespace gipfl\ZfDbStore; + +use Evenement\EventEmitterTrait; +use RuntimeException; + +/** + * Class BaseStore + * + * This class handles creation/update/delete of $storable + * and save records them into a log table in the DB + */ +abstract class BaseStore implements Store +{ + use EventEmitterTrait; + + /** + * If a new element is created, it stores it into the DB + * and emits the "insert" event, in order to create the corresponding activity log + * + * If an element is updated, it updates the DB record and + * emits the "update" event + * + * @param StorableInterface $storable + * @return bool Whether the store() applied any change to the stored object + */ + public function store(StorableInterface $storable) + { + $affected = false; + + if ($storable->isNew()) { + $this->insertIntoStore($storable); + $this->emit('insert', [$storable]); + $affected = true; + } else { + if ($storable->isModified() && $this->updateStore($storable)) { + $this->emit('update', [$storable]); + $affected = true; + } + } + $storable->setStored(); + + return $affected; + } + + /** + * If a new element is deleted, it deletes the record from the DB + * and emits the "delete" event, in order to create the corresponding activity log + * + * @param StorableInterface $storable + * @return bool + */ + public function delete(StorableInterface $storable) + { + if ($this->deleteFromStore($storable)) { + $this->emit('delete', [$storable]); + return true; + } + + return false; + } + + /** + * Loads $storable by it's key property/properties + * + * @param StorableInterface $storable + * @param $key + * @return StorableInterface + */ + abstract protected function loadFromStore(StorableInterface $storable, $key); + + /** + * Deletes this record from the store + * + * @param StorableInterface $storable + */ + abstract protected function deleteFromStore(StorableInterface $storable); + + /** + * Inserts the $storable, refreshes the object in case storing implies + * changes (like auto-incremental IDs) + * + * @param StorableInterface $storable + * @return bool + * @throws \gipfl\ZfDb\Adapter\Exception\AdapterException + * @throws \gipfl\ZfDb\Statement\Exception\StatementException + * @throws \Zend_Db_Adapter_Exception + */ + abstract protected function insertIntoStore(StorableInterface $storable); + abstract protected function updateStore(StorableInterface $storable); + + /** + * Load $storable from DB + * + * @param array|string $key + * @param string $className + * @return StorableInterface + */ + public function load($key, $className) + { + $storable = new $className(); + if ($storable instanceof StorableInterface) { + $storable = $storable::create(); + return $this->loadFromStore($storable, $key); + } else { + throw new RuntimeException( + get_class($this) . "::load: '$className' is not a StorableInterface implementation" + ); + } + } +} diff --git a/vendor/gipfl/zfdbstore/src/DbStorable.php b/vendor/gipfl/zfdbstore/src/DbStorable.php new file mode 100644 index 0000000..4bd1783 --- /dev/null +++ b/vendor/gipfl/zfdbstore/src/DbStorable.php @@ -0,0 +1,79 @@ +<?php + +namespace gipfl\ZfDbStore; + +use RuntimeException; + +/** + * DbStorable + * + * This trait provides all you need to create an object implementing the + * DbStorableInterface + */ +trait DbStorable +{ + use Storable; + + // protected $tableName; + + public function getTableName() + { + if (isset($this->tableName)) { + return $this->tableName; + } else { + throw new RuntimeException('A DbStorable needs a tableName'); + } + } + + public function hasAutoIncKey() + { + return $this->getAutoIncKeyName() !== null; + } + + public function getAutoIncKeyName() + { + if (isset($this->autoIncKeyName)) { + return $this->autoIncKeyName; + } else { + return null; + } + } + + protected function requireAutoIncKeyName() + { + $key = $this->getAutoIncKeyName(); + if ($key === null) { + throw new RuntimeException('This DbStorable has no autoinc key'); + } + + return $key; + } + + public function getAutoIncId() + { + $key = $this->requireAutoIncKeyName(); + if (isset($this->properties[$key])) { + return (int) $this->properties[$key]; + } + + return null; + } + + protected function forgetAutoIncId() + { + $key = $this->requireAutoIncKeyName(); + if (isset($this->properties[$key])) { + $this->properties[$key] = null; + } + + return $this; + } + + public function __invoke($properties = []) + { + $storable = new static(); + $storable->setProperties($properties); + + return $storable; + } +} diff --git a/vendor/gipfl/zfdbstore/src/DbStorableInterface.php b/vendor/gipfl/zfdbstore/src/DbStorableInterface.php new file mode 100644 index 0000000..ba9a49f --- /dev/null +++ b/vendor/gipfl/zfdbstore/src/DbStorableInterface.php @@ -0,0 +1,36 @@ +<?php + +namespace gipfl\ZfDbStore; + +interface DbStorableInterface extends StorableInterface +{ + /** + * The table where this Storable will be loaded from and stored to + * + * @return string + */ + public function getTableName(); + + /** + * Whether this Storable has an auto-incrementing key column + * @return bool + */ + public function hasAutoIncKey(); + + /** + * Returns the name of the auto-incrementing key column + * + * @return string + */ + public function getAutoIncKeyName(); + + /** + * Get the AutoInc value if set + * + * Should throw and Exception in case no such key has been defined. This + * will return null for unstored DbStorables + * + * @return int|null + */ + public function getAutoIncId(); +} diff --git a/vendor/gipfl/zfdbstore/src/NotFoundError.php b/vendor/gipfl/zfdbstore/src/NotFoundError.php new file mode 100644 index 0000000..fb2413e --- /dev/null +++ b/vendor/gipfl/zfdbstore/src/NotFoundError.php @@ -0,0 +1,9 @@ +<?php + +namespace gipfl\ZfDbStore; + +use Exception; + +class NotFoundError extends Exception +{ +} diff --git a/vendor/gipfl/zfdbstore/src/Storable.php b/vendor/gipfl/zfdbstore/src/Storable.php new file mode 100644 index 0000000..9980efd --- /dev/null +++ b/vendor/gipfl/zfdbstore/src/Storable.php @@ -0,0 +1,323 @@ +<?php + +namespace gipfl\ZfDbStore; + +use InvalidArgumentException; +use RuntimeException; + +/** + * Trait Storable + * + * This trait implements a generic trait used for storing + * information about users activity (i.e. creation of new elements, + * update/delete existing records) + * + * Each storable is characterized by: + * - $defaultProperties (array of properties set by default) + * - $modifiedProperties (array of properties modified by the user) + * - $storedProperties (array of properties loaded from the DB) + * - key property represents the primary key in the DB + */ +trait Storable +{ + /** @var null|array */ + protected $storedProperties; + + ///** @var array */ + //protected $defaultProperties = []; + + /** @var array */ + protected $modifiedProperties = []; + + /** @var array */ + protected $properties = []; + + ///** @var string|array */ + //protected $keyProperty; + + /** + * If a $storable has no stored properties it means that + * it is a new element -> the user is creating it right now + * + * @return bool + */ + public function isNew() + { + return null === $this->storedProperties; + } + + /** + * This function returns the key property (it can be an array of properties) of the $storable + * i.e. it returns the primary key in the case of DB object + * + * @return array|mixed + */ + public function getKey() + { + $property = $this->getKeyProperty(); + if (is_string($property)) { + return $this->get($property); + } else { + return $this->getProperties($property); + } + } + + /** + * @return string|array + */ + public function getKeyProperty() + { + if (isset($this->keyProperty)) { + return $this->keyProperty; + } else { + throw new RuntimeException('A storable needs a key property.'); + } + } + + /** + * Create a $storable setting its properties + * + * @param array $properties + * @return static + */ + public static function create(array $properties = []) + { + $storable = new static(); + $storable->properties = $storable->getDefaultProperties(); + $storable->setProperties($properties); + + return $storable; + } + + /** + * Loads an already existing $storable + * + * @param Store $store + * @param $key + * @return mixed + */ + public static function load(Store $store, $key) + { + return $store->load($key, get_called_class()); + return $store->load(get_called_class(), $key); + } + + /** + * Returns the value of $property (if this property exists) + * + * @param $property + * @return mixed + */ + public function get($property, $default = null) + { + $this->assertPropertyExists($property); + + if (array_key_exists($property, $this->properties)) { + if ($this->properties[$property] === null) { + return $default; + } else { + return $this->properties[$property]; + } + } else { + return $default; + } + } + + /** + * Returns the array of values corresponding to the requested array of properties + * + * @param array|null $properties + * @return array + */ + public function getProperties(array $properties = null) + { + if ($properties === null) { + $properties = array_keys($this->properties); + } + + $result = []; + foreach ($properties as $property) { + $result[$property] = $this->get($property); + } + + return $result; + } + + /** + * Returns the array of properties modified by the user + * + * @return array + */ + public function getModifiedProperties() + { + return $this->getProperties($this->listModifiedProperties()); + } + + /** + * Returns the array of stored properties + * It can be used only in case of already existing $storable + */ + public function getStoredProperties() + { + if ($this->isNew()) { + throw new RuntimeException( + 'Trying to access stored properties of an unstored Storable' + ); + } + + return $this->storedProperties; + } + + /** + * Set the value of a given property + * + * @param $property + * @param $value + * @return bool + */ + public function set($property, $value) + { + $this->assertPropertyExists($property); + + if ($value === $this->get($property)) { + return false; + } + + $this->properties[$property] = $value; + + if ($this->storedProperties !== null && $this->storedProperties[$property] === $value) { + $this->resetModifiedProperty($property); + } else { + $this->setModifiedProperty($property); + } + + return true; + } + + /** + * Initialize the stored property at the first loading of the $storable element + * + * @param $property + * @param $value + */ + public function setStoredProperty($property, $value) + { + $this->assertPropertyExists($property); + + $this->storedProperties[$property] = $value; + $this->properties[$property] = $value; + unset($this->modifiedProperties[$property]); + } + + /** + * Set array of values for the given array of properties + * + * @param array $properties + * @return $this + */ + public function setProperties(array $properties) + { + foreach ($properties as $property => $value) { + $this->set($property, $value); + } + + return $this; + } + + /** + * Initialize the stored property array + * + * @param array $properties + * @return $this + */ + public function setStoredProperties(array $properties) + { + foreach ($properties as $property => $value) { + $this->setStoredProperty($property, $value); + } + + return $this; + } + + /** + * @param $property + */ + public function assertPropertyExists($property) + { + if (! $this->hasProperty($property)) { + throw new InvalidArgumentException(sprintf( + "Trying to access invalid property '%s'", + $property + )); + } + } + + /** + * @param $property + * @return bool + */ + public function hasProperty($property) + { + return array_key_exists($property, $this->defaultProperties); + } + + /** + * @param $property + */ + private function setModifiedProperty($property) + { + $this->modifiedProperties[$property] = true; + } + + /** + * @param $property + */ + private function resetModifiedProperty($property) + { + unset($this->modifiedProperties[$property]); + } + + /** + * Check if $storable has changed, + * if not the $modifiedProperties array is empty + * + * @return bool + */ + public function isModified() + { + return !empty($this->modifiedProperties); + } + + /** + * @return mixed + */ + public function getDefaultProperties() + { + if (isset($this->defaultProperties)) { + return $this->defaultProperties; + } else { + throw new RuntimeException('A storable needs default properties.'); + } + } + + /** + * Get the array key of the modifies properties + * + * @return array + */ + public function listModifiedProperties() + { + return array_keys($this->modifiedProperties); + } + + /** + * @return $this + */ + public function setStored() + { + $this->storedProperties = $this->properties; + $this->modifiedProperties = []; + + return $this; + } +} diff --git a/vendor/gipfl/zfdbstore/src/StorableInterface.php b/vendor/gipfl/zfdbstore/src/StorableInterface.php new file mode 100644 index 0000000..8ae49d2 --- /dev/null +++ b/vendor/gipfl/zfdbstore/src/StorableInterface.php @@ -0,0 +1,44 @@ +<?php + +namespace gipfl\ZfDbStore; + +interface StorableInterface +{ + public function isNew(); + + public function getKey(); + + public function getKeyProperty(); + + public static function create(array $properties = []); + + public static function load(Store $store, $key); + + public function get($property); + + public function getProperties(array $properties = null); + + public function hasProperty($property); + + public function getModifiedProperties(); + + public function getStoredProperties(); + + public function set($property, $value); + + public function setStoredProperty($property, $value); + + public function setProperties(array $properties); + + public function setStoredProperties(array $properties); + + public function assertPropertyExists($property); + + public function isModified(); + + public function getDefaultProperties(); + + public function listModifiedProperties(); + + public function setStored(); +} diff --git a/vendor/gipfl/zfdbstore/src/Store.php b/vendor/gipfl/zfdbstore/src/Store.php new file mode 100644 index 0000000..cdc7ab1 --- /dev/null +++ b/vendor/gipfl/zfdbstore/src/Store.php @@ -0,0 +1,24 @@ +<?php + +namespace gipfl\ZfDbStore; + +interface Store +{ + /** + * Function used for saving changes and log the activity. + * To be extended as needed (see BaseStore.php) + * + * @param StorableInterface $storable + * @return mixed + */ + public function store(StorableInterface $storable); + + /** + * @param array|string $key + * @param string $className + * @return StorableInterface + */ + public function load($key, $className); + public function exists(StorableInterface $storable); + public function delete(StorableInterface $storable); +} diff --git a/vendor/gipfl/zfdbstore/src/ZfDbStore.php b/vendor/gipfl/zfdbstore/src/ZfDbStore.php new file mode 100644 index 0000000..d34541c --- /dev/null +++ b/vendor/gipfl/zfdbstore/src/ZfDbStore.php @@ -0,0 +1,241 @@ +<?php + +namespace gipfl\ZfDbStore; + +use InvalidArgumentException; +use RuntimeException; +use gipfl\ZfDb\Adapter\Adapter; +use Zend_Db_Adapter_Abstract as ZfDb; +use function array_key_exists; +use function assert; +use function implode; +use function is_array; +use function is_string; +use function method_exists; + +/** + * Class DbStore + * + * Extends BaseStore for DB object + */ +class ZfDbStore extends BaseStore +{ + /** @var Adapter|ZfDb */ + protected $db; + + /** + * ZfDbStore constructor. + * @param Adapter|ZfDb $db + */ + public function __construct($db) + { + if ($db instanceof Adapter || $db instanceof ZfDb) { + $this->db = $db; + } else { + throw new InvalidArgumentException('ZfDb Adapter is required'); + } + } + + /** + * @return Adapter|ZfDb + */ + public function getDb() + { + return $this->db; + } + + /** + * Checks whether the passed $storable already exists in the DB + * + * @param DbStorableInterface $storable + * @return bool + */ + public function exists(StorableInterface $storable) + { + return (int) $this->db->fetchOne( + $this->db + ->select() + ->from($this->getTableName($storable), '(1)') + ->where($this->createWhere($storable)) + ) === 1; + } + + /** + * @param DbStorableInterface $storable + * @param string|null $keyColumn + * @param string|null $labelColumn + * @return array + */ + public function enum(StorableInterface $storable, $keyColumn = null, $labelColumn = null) + { + assert($storable instanceof DbStorableInterface); + if ($keyColumn === null) { + $key = $storable->getKeyProperty(); + if (is_array($key)) { + if ($storable->hasAutoIncKey()) { + $key = $storable->getAutoIncKeyName(); + } else { + throw new InvalidArgumentException( + 'Cannot provide an enum for a multi-key column' + ); + } + } + } else { + $key = $keyColumn; + } + + if ($labelColumn === null) { + if (method_exists($storable, 'getDisplayColumn')) { + $label = $storable->getDisplayColumn(); + } else { + $label = $storable->getKeyProperty(); + if (is_array($label)) { + $label = $key; + } + } + } else { + $label = $labelColumn; + } + + $columns = [ + 'key_col' => $key, + 'label_col' => $label + ]; + + $query = $this->db->select()->from( + $this->getTableName($storable), + $columns + ); + + return $this->db->fetchPairs($query); + } + + protected function insertIntoStore(StorableInterface $storable) + { + assert($storable instanceof DbStorableInterface); + $result = $this->db->insert( + $this->getTableName($storable), + $storable->getProperties() + ); + /** @var DbStorable $storable */ + if ($storable->hasAutoIncKey()) { + $storable->set( + $storable->getAutoIncKeyName(), + $this->db->lastInsertId($this->getTableName($storable)) + ); + } + + return $result > 0; + } + + protected function updateStore(StorableInterface $storable) + { + assert($storable instanceof DbStorableInterface); + $this->db->update( + $this->getTableName($storable), + $storable->getProperties(), + $this->createWhere($storable) + ); + + return true; + } + + protected function deleteFromStore(StorableInterface $storable) + { + assert($storable instanceof DbStorableInterface); + return $this->db->delete( + $this->getTableName($storable), + $this->createWhere($storable) + ); + } + + protected function loadFromStore(StorableInterface $storable, $key) + { + assert($storable instanceof DbStorableInterface); + $keyColumn = $storable->getKeyProperty(); + $select = $this->db->select()->from($this->getTableName($storable)); + + if (is_string($keyColumn)) { + $select->where("$keyColumn = ?", $key); + } else { + foreach ($keyColumn as $column) { + if (array_key_exists($column, $key)) { + $select->where("$column = ?", $key[$column]); + } else { + throw new RuntimeException('Multicolumn key required, got no %s', $column); + } + } + } + + $result = $this->db->fetchAll($select); + // TODO: properties should be changed in storeProperties + // when you load the element from db before changing it. + if (empty($result)) { + throw new NotFoundError('Not found: ' . $this->describeKey($storable, $key)); + } + + if (count($result) > 1) { + throw new NotFoundError(sprintf( + 'One row expected, got %s: %s', + count($result), + $this->describeKey($storable, $key) + )); + } + + $storable->setStoredProperties((array) $result[0]); + + return $storable; + } + + protected function describeKey(StorableInterface $storable, $key) + { + + assert($storable instanceof DbStorableInterface); + $keyColumn = $storable->getKeyProperty(); + if (is_string($keyColumn)) { + return (string) $key; + } + + $parts = []; + foreach ($keyColumn as $column) { + if (array_key_exists($column, $key)) { + $parts[$column] = $key[$column]; + } else { + $parts[$column] = '?'; + } + } + return implode(', ', $parts); + } + + /** + * Returns $storable table name + * + * @param DbStorableInterface $storable + * @return string + */ + protected function getTableName(DbStorableInterface $storable) + { + return $storable->getTableName(); + } + + /** + * @param DbStorableInterface $storable + * @return string + */ + protected function createWhere($storable) + { + $where = []; + foreach ((array) $storable->getKeyProperty() as $key) { + $value = $storable->get($key); + // TODO, eventually: + // $key = $this->db->quoteIdentifier($key); + if ($value === null) { + $where[] = "$key IS NULL"; + } else { + $where[] = $this->db->quoteInto("$key = ?", $value); + } + } + + return implode(' AND ', $where); + } +} |