[icinga-checkins] icinga.org: icingaweb2/master: IniRepository: Add support for triggers

git at icinga.org git at icinga.org
Thu Oct 27 15:12:29 CEST 2016


Module: icingaweb2
Branch: master
Commit: 957ad9361f359d86308f3b6fb8e7326dac70e0d7
URL:    https://git.icinga.org/?p=icingaweb2.git;a=commit;h=957ad9361f359d86308f3b6fb8e7326dac70e0d7

Author: Johannes Meyer <johannes.meyer at netways.de>
Date:   Thu Oct 27 15:11:21 2016 +0200

IniRepository: Add support for triggers


---

 library/Icinga/Repository/IniRepository.php |  148 ++++++++++++++++++++++++++-
 1 file changed, 143 insertions(+), 5 deletions(-)

diff --git a/library/Icinga/Repository/IniRepository.php b/library/Icinga/Repository/IniRepository.php
index 8ff1936..04b25c5 100644
--- a/library/Icinga/Repository/IniRepository.php
+++ b/library/Icinga/Repository/IniRepository.php
@@ -5,6 +5,7 @@ namespace Icinga\Repository;
 
 use Exception;
 use Icinga\Application\Config;
+use Icinga\Data\ConfigObject;
 use Icinga\Data\Extensible;
 use Icinga\Data\Filter\Filter;
 use Icinga\Data\Updatable;
@@ -18,6 +19,7 @@ use Icinga\Exception\StatementException;
  * Additionally provided features:
  * <ul>
  *  <li>Insert, update and delete capabilities</li>
+ *  <li>Triggers for inserts, updates and deletions</li>
  * </ul>
  */
 abstract class IniRepository extends Repository implements Extensible, Updatable, Reducible
@@ -30,6 +32,19 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
     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
      *
      * @param   Config  $ds         The data source to use
@@ -46,6 +61,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
      *
      * $data must provide a proper value for the data source's key column.
@@ -64,7 +192,7 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
             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 {
             $this->ds->saveIni();
@@ -98,6 +226,7 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
             $query->addFilter($this->requireFilter($target, $filter));
         }
 
+        /** @var ConfigObject $config */
         $newSection = null;
         foreach ($query as $section => $config) {
             if ($newSection !== null) {
@@ -107,25 +236,32 @@ abstract class IniRepository extends Repository implements Extensible, Updatable
                 );
             }
 
+            $newConfig = clone $config;
             foreach ($newData as $column => $value) {
                 if ($column === $keyColumn) {
                     $newSection = $value;
                 } else {
-                    $config->$column = $value;
+                    $newConfig->$column = $value;
                 }
             }
 
             // This is necessary as the query result set contains the key column.
-            unset($config->$keyColumn);
+            unset($newConfig->$keyColumn);
 
             if ($newSection) {
                 if ($this->ds->hasSection($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 {
-                $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));
         }
 
+        /** @var ConfigObject $config */
         foreach ($query as $section => $config) {
             $this->ds->removeSection($section);
+            $this->onDelete($target, $config);
         }
 
         try {



More information about the icinga-checkins mailing list