IniRepository: Add support for triggers
This commit is contained in:
parent
f644860529
commit
957ad9361f
|
@ -5,6 +5,7 @@ namespace Icinga\Repository;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Data\ConfigObject;
|
||||||
use Icinga\Data\Extensible;
|
use Icinga\Data\Extensible;
|
||||||
use Icinga\Data\Filter\Filter;
|
use Icinga\Data\Filter\Filter;
|
||||||
use Icinga\Data\Updatable;
|
use Icinga\Data\Updatable;
|
||||||
|
@ -18,6 +19,7 @@ use Icinga\Exception\StatementException;
|
||||||
* Additionally provided features:
|
* Additionally provided features:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Insert, update and delete capabilities</li>
|
* <li>Insert, update and delete capabilities</li>
|
||||||
|
* <li>Triggers for inserts, updates and deletions</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
abstract class IniRepository extends Repository implements Extensible, Updatable, Reducible
|
abstract class IniRepository extends Repository implements Extensible, Updatable, Reducible
|
||||||
|
@ -29,6 +31,19 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
|
||||||
*/
|
*/
|
||||||
protected $ds;
|
protected $ds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tables for which triggers are available when inserting, updating or deleting rows
|
||||||
|
*
|
||||||
|
* This may be initialized by concrete repository implementations and describes for which table names triggers
|
||||||
|
* are available. The repository attempts to find a method depending on the type of event and table for which
|
||||||
|
* to run the trigger. The name of such a method is expected to be declared using lowerCamelCase.
|
||||||
|
* (e.g. group_membership will be translated to onUpdateGroupMembership and groupmembership will be translated
|
||||||
|
* to onUpdateGroupmembership) The available events are onInsert, onUpdate and onDelete.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $triggers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new INI repository object
|
* Create a new INI repository object
|
||||||
*
|
*
|
||||||
|
@ -45,6 +60,119 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the tables for which triggers are available when inserting, updating or deleting rows
|
||||||
|
*
|
||||||
|
* Calls $this->initializeTriggers() in case $this->triggers is null.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTriggers()
|
||||||
|
{
|
||||||
|
if ($this->triggers === null) {
|
||||||
|
$this->triggers = $this->initializeTriggers();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->triggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrite this in your repository implementation in case you need to initialize the triggers lazily
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function initializeTriggers()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a trigger for the given table and row which is about to be inserted
|
||||||
|
*
|
||||||
|
* @param string $table
|
||||||
|
* @param ConfigObject $new
|
||||||
|
*
|
||||||
|
* @return ConfigObject
|
||||||
|
*/
|
||||||
|
public function onInsert($table, ConfigObject $new)
|
||||||
|
{
|
||||||
|
$trigger = $this->getTrigger($table, 'onInsert');
|
||||||
|
if ($trigger !== null) {
|
||||||
|
$row = $this->$trigger($new);
|
||||||
|
if ($row !== null) {
|
||||||
|
$new = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a trigger for the given table and row which is about to be updated
|
||||||
|
*
|
||||||
|
* @param string $table
|
||||||
|
* @param ConfigObject $old
|
||||||
|
* @param ConfigObject $new
|
||||||
|
*
|
||||||
|
* @return ConfigObject
|
||||||
|
*/
|
||||||
|
public function onUpdate($table, ConfigObject $old, ConfigObject $new)
|
||||||
|
{
|
||||||
|
$trigger = $this->getTrigger($table, 'onUpdate');
|
||||||
|
if ($trigger !== null) {
|
||||||
|
$row = $this->$trigger($old, $new);
|
||||||
|
if ($row !== null) {
|
||||||
|
$new = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a trigger for the given table and row which has been deleted
|
||||||
|
*
|
||||||
|
* @param string $table
|
||||||
|
* @param ConfigObject $old
|
||||||
|
*
|
||||||
|
* @return ConfigObject
|
||||||
|
*/
|
||||||
|
public function onDelete($table, ConfigObject $old)
|
||||||
|
{
|
||||||
|
$trigger = $this->getTrigger($table, 'onDelete');
|
||||||
|
if ($trigger !== null) {
|
||||||
|
$this->$trigger($old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the trigger method for the given table and event-type
|
||||||
|
*
|
||||||
|
* @param string $table The table name for which to return a trigger method
|
||||||
|
* @param string $event The name of the event type
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
* @throws ProgrammingError In case the table is registered as having triggers but not any trigger is found
|
||||||
|
*/
|
||||||
|
protected function getTrigger($table, $event)
|
||||||
|
{
|
||||||
|
if (! in_array($table, $this->getTriggers())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$identifier = join('', array_map('ucfirst', explode('_', $table)));
|
||||||
|
if (! method_exists($this, $event . $identifier)) {
|
||||||
|
throw new ProgrammingError(
|
||||||
|
'Cannot find any trigger for table "%s". Add a trigger or remove the table from %s::$triggers',
|
||||||
|
$table,
|
||||||
|
get_class($this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $event . $identifier;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert the given data for the given target
|
* Insert the given data for the given target
|
||||||
*
|
*
|
||||||
|
@ -64,7 +192,7 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
|
||||||
throw new StatementException(t('Cannot insert. Section "%s" does already exist'), $section);
|
throw new StatementException(t('Cannot insert. Section "%s" does already exist'), $section);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->ds->setSection($section, $newData);
|
$this->ds->setSection($section, $this->onInsert($target, new ConfigObject($newData)));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->ds->saveIni();
|
$this->ds->saveIni();
|
||||||
|
@ -98,6 +226,7 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
|
||||||
$query->addFilter($this->requireFilter($target, $filter));
|
$query->addFilter($this->requireFilter($target, $filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var ConfigObject $config */
|
||||||
$newSection = null;
|
$newSection = null;
|
||||||
foreach ($query as $section => $config) {
|
foreach ($query as $section => $config) {
|
||||||
if ($newSection !== null) {
|
if ($newSection !== null) {
|
||||||
|
@ -107,25 +236,32 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$newConfig = clone $config;
|
||||||
foreach ($newData as $column => $value) {
|
foreach ($newData as $column => $value) {
|
||||||
if ($column === $keyColumn) {
|
if ($column === $keyColumn) {
|
||||||
$newSection = $value;
|
$newSection = $value;
|
||||||
} else {
|
} else {
|
||||||
$config->$column = $value;
|
$newConfig->$column = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is necessary as the query result set contains the key column.
|
// This is necessary as the query result set contains the key column.
|
||||||
unset($config->$keyColumn);
|
unset($newConfig->$keyColumn);
|
||||||
|
|
||||||
if ($newSection) {
|
if ($newSection) {
|
||||||
if ($this->ds->hasSection($newSection)) {
|
if ($this->ds->hasSection($newSection)) {
|
||||||
throw new StatementException(t('Cannot update. Section "%s" does already exist'), $newSection);
|
throw new StatementException(t('Cannot update. Section "%s" does already exist'), $newSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->ds->removeSection($section)->setSection($newSection, $config);
|
$this->ds->removeSection($section)->setSection(
|
||||||
|
$newSection,
|
||||||
|
$this->onUpdate($target, $config, $newConfig)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$this->ds->setSection($section, $config);
|
$this->ds->setSection(
|
||||||
|
$section,
|
||||||
|
$this->onUpdate($target, $config, $newConfig)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,8 +287,10 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
|
||||||
$query->addFilter($this->requireFilter($target, $filter));
|
$query->addFilter($this->requireFilter($target, $filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var ConfigObject $config */
|
||||||
foreach ($query as $section => $config) {
|
foreach ($query as $section => $config) {
|
||||||
$this->ds->removeSection($section);
|
$this->ds->removeSection($section);
|
||||||
|
$this->onDelete($target, $config);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue