4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.7 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2017 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
11 | CiviCRM is free software; you can copy, modify, and distribute it |
12 | under the terms of the GNU Affero General Public License |
13 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
15 | CiviCRM is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
18 | See the GNU Affero General Public License for more details. |
20 | You should have received a copy of the GNU Affero General Public |
21 | License and the CiviCRM Licensing Exception along |
22 | with this program; if not, contact CiviCRM LLC |
23 | at info[AT]civicrm[DOT]org. If you have questions about the |
24 | GNU Affero General Public License or the licensing of CiviCRM, |
25 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
26 +--------------------------------------------------------------------+
29 namespace Civi\Core\SqlTrigger
;
31 use Civi\Core\Event\GenericHookEvent
;
34 * Build a set of SQL triggers for tracking timestamps on an entity.
36 * This class is a generalization of CRM-10554 with the aim of enabling CRM-20958.
39 * @copyright CiviCRM LLC (c) 2004-2017
41 class TimestampTriggers
{
46 * Ex: 'civicrm_contact', 'civicrm_activity'.
52 * An entity name (from civicrm_custom_group.extends).
53 * Ex: 'Contact', 'Activity'.
55 private $customDataEntity;
67 * Ex: 'modified_date'.
69 private $modifiedDate;
73 * Ex: $relations[0] == array('table' => 'civicrm_bar', 'column' => 'foo_id');
78 * @param string $tableName
80 * Ex: 'civicrm_contact', 'civicrm_activity'.
81 * @param string $customDataEntity
82 * An entity name (from civicrm_custom_group.extends).
83 * Ex: 'Contact', 'Activity'.
84 * @return TimestampTriggers
86 public static function create($tableName, $customDataEntity) {
87 return new static($tableName, $customDataEntity);
91 * TimestampTriggers constructor.
93 * @param string $tableName
95 * Ex: 'civicrm_contact', 'civicrm_activity'.
96 * @param string $customDataEntity
97 * An entity name (from civicrm_custom_group.extends).
98 * Ex: 'Contact', 'Activity'.
99 * @param string $createdDate
101 * Ex: 'created_date'.
102 * @param string $modifiedDate
104 * Ex: 'modified_date'.
105 * @param array $relations
106 * Ex: $relations[0] == array('table' => 'civicrm_bar', 'column' => 'foo_id');
108 public function __construct(
111 $createdDate = 'created_date',
112 $modifiedDate = 'modified_date',
115 $this->tableName
= $tableName;
116 $this->customDataEntity
= $customDataEntity;
117 $this->createdDate
= $createdDate;
118 $this->modifiedDate
= $modifiedDate;
119 $this->relations
= $relations;
123 * Add our list of triggers to the global list.
125 * @param \Civi\Core\Event\GenericHookEvent $e
126 * @see \CRM_Utils_Hook::triggerInfo
128 public function onTriggerInfo($e) {
129 $this->alterTriggerInfo($e->info
, $e->tableName
);
133 * Add our list of triggers to the global list.
135 * @see \CRM_Utils_Hook::triggerInfo
136 * @see \CRM_Core_DAO::triggerRebuild
139 * See hook_civicrm_triggerInfo.
140 * @param string|NULL $tableFilter
141 * See hook_civicrm_triggerInfo.
143 public function alterTriggerInfo(&$info, $tableFilter = NULL) {
144 // If we haven't upgraded yet, then the created_date/modified_date may not exist.
145 // In the past, this was a version-based check, but checkFieldExists()
146 // seems more robust.
147 if (\CRM_Core_Config
::isUpgradeMode()) {
148 if (!\CRM_Core_DAO
::checkFieldExists($this->getTableName(),
149 $this->getCreatedDate())
155 if ($tableFilter == NULL ||
$tableFilter == $this->getTableName()) {
157 'table' => array($this->getTableName()),
159 'event' => array('INSERT'),
160 'sql' => "\nSET NEW.{$this->getCreatedDate()} = CURRENT_TIMESTAMP;\n",
164 // Update timestamp when modifying closely related tables
165 $relIdx = \CRM_Utils_Array
::index(
166 array('column', 'table'),
167 $this->getAllRelations()
169 foreach ($relIdx as $column => $someRelations) {
170 $this->generateTimestampTriggers($info, $tableFilter,
171 array_keys($someRelations), $column);
176 * Generate triggers to update the timestamp.
178 * The corresponding civicrm_FOO row is updated on insert/update/delete
179 * to a table that extends civicrm_FOO.
180 * Don't regenerate triggers for all such tables if only asked for one table.
183 * Reference to the array where generated trigger information is being stored
184 * @param string|null $tableFilter
185 * Name of the table for which triggers are being generated, or NULL if all tables
186 * @param array $relatedTableNames
187 * Array of all core or all custom table names extending civicrm_FOO
188 * @param string $contactRefColumn
189 * 'contact_id' if processing core tables, 'entity_id' if processing custom tables
191 * @link https://issues.civicrm.org/jira/browse/CRM-15602
194 public function generateTimestampTriggers(
201 $contactRefColumn = \CRM_Core_DAO
::escapeString($contactRefColumn);
203 // If specific related table requested, just process that one.
204 // (Reply: This feels fishy.)
205 if (in_array($tableFilter, $relatedTableNames)) {
206 $relatedTableNames = array($tableFilter);
209 // If no specific table requested (include all related tables),
210 // or a specific related table requested (as matched above)
211 if (empty($tableFilter) ||
isset($relatedTableNames[$tableFilter])) {
213 'table' => $relatedTableNames,
215 'event' => array('INSERT', 'UPDATE'),
216 'sql' => "\nUPDATE {$this->getTableName()} SET {$this->getModifiedDate()} = CURRENT_TIMESTAMP WHERE id = NEW.$contactRefColumn;\n",
219 'table' => $relatedTableNames,
221 'event' => array('DELETE'),
222 'sql' => "\nUPDATE {$this->getTableName()} SET {$this->getModifiedDate()} = CURRENT_TIMESTAMP WHERE id = OLD.$contactRefColumn;\n",
230 public function getTableName() {
231 return $this->tableName
;
235 * @param string $tableName
236 * @return TimestampTriggers
238 public function setTableName($tableName) {
239 $this->tableName
= $tableName;
246 public function getCustomDataEntity() {
247 return $this->customDataEntity
;
251 * @param string $customDataEntity
252 * @return TimestampTriggers
254 public function setCustomDataEntity($customDataEntity) {
255 $this->customDataEntity
= $customDataEntity;
262 public function getCreatedDate() {
263 return $this->createdDate
;
267 * @param string $createdDate
268 * @return TimestampTriggers
270 public function setCreatedDate($createdDate) {
271 $this->createdDate
= $createdDate;
278 public function getModifiedDate() {
279 return $this->modifiedDate
;
283 * @param string $modifiedDate
284 * @return TimestampTriggers
286 public function setModifiedDate($modifiedDate) {
287 $this->modifiedDate
= $modifiedDate;
293 * Each item is an array('table' => string, 'column' => string)
295 public function getRelations() {
296 return $this->relations
;
300 * @param array $relations
301 * @return TimestampTriggers
303 public function setRelations($relations) {
304 $this->relations
= $relations;
309 * Get a list of all tracked relations.
311 * This is basically the curated list (`$this->relations`) plus any custom data.
314 * Each item is an array('table' => string, 'column' => string)
316 public function getAllRelations() {
317 $relations = $this->getRelations();
319 if ($this->getCustomDataEntity()) {
320 $customGroupDAO = \CRM_Core_BAO_CustomGroup
::getAllCustomGroupsByBaseEntity($this->getCustomDataEntity());
321 $customGroupDAO->is_multiple
= 0;
322 $customGroupDAO->find();
323 while ($customGroupDAO->fetch()) {
324 $relations[] = array(
325 'table' => $customGroupDAO->table_name
,
326 'column' => 'entity_id',