INFRA-132 - CRM/Contribute - Convert single-line @param to multi-line
[civicrm-core.git] / CRM / Core / BAO / EntityTag.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26*/
27
28/**
29 * This class contains functions for managing Tag(tag) for a contact
30 *
31 * @package CRM
06b69b18 32 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
33 * $Id$
34 *
35 */
36class CRM_Core_BAO_EntityTag extends CRM_Core_DAO_EntityTag {
37
38 /**
39 *
40 * Given a contact id, it returns an array of tag id's the
41 * contact belongs to.
42 *
43 * @param int $entityID id of the entity usually the contactID.
44 * @param string $entityTable name of the entity table usually 'civicrm_contact'
45 *
46 * @return array(
da3c7979 47 ) reference $tag array of category id's the contact belongs to.
6a488035 48 *
6a488035
TO
49 * @static
50 */
00be9182 51 public static function &getTag($entityID, $entityTable = 'civicrm_contact') {
6a488035
TO
52 $tags = array();
53
54 $entityTag = new CRM_Core_BAO_EntityTag();
55 $entityTag->entity_id = $entityID;
56 $entityTag->entity_table = $entityTable;
57 $entityTag->find();
58
59 while ($entityTag->fetch()) {
60 $tags[$entityTag->tag_id] = $entityTag->tag_id;
61 }
62 return $tags;
63 }
64
65 /**
100fef9d 66 * Takes an associative array and creates a entityTag object
6a488035
TO
67 *
68 * the function extract all the params it needs to initialize the create a
69 * group object. the params array could contain additional unused name/value
70 * pairs
71 *
72 * @param array $params (reference ) an assoc array of name/value pairs
73 *
c490a46a 74 * @return CRM_Core_BAO_EntityTag object
6a488035
TO
75 * @static
76 */
00be9182 77 public static function add(&$params) {
6a488035
TO
78 $dataExists = self::dataExists($params);
79 if (!$dataExists) {
80 return NULL;
81 }
82
83 $entityTag = new CRM_Core_BAO_EntityTag();
84 $entityTag->copyValues($params);
85
86 // dont save the object if it already exists, CRM-1276
87 if (!$entityTag->find(TRUE)) {
88 $entityTag->save();
89
90 //invoke post hook on entityTag
91 // we are using this format to keep things consistent between the single and bulk operations
92 // so a bit different from other post hooks
93 $object = array(0 => array(0 => $params['entity_id']), 1 => $params['entity_table']);
94 CRM_Utils_Hook::post('create', 'EntityTag', $params['tag_id'], $object);
95 }
96 return $entityTag;
97 }
98
99 /**
100 * Check if there is data to create the object
101 *
c490a46a 102 * @param array $params an assoc array of name/value pairs
dd244018 103 *
6a488035 104 * @return boolean
6a488035
TO
105 * @static
106 */
00be9182 107 public static function dataExists($params) {
c490a46a 108 return !($params['tag_id'] == 0);
6a488035
TO
109 }
110
111 /**
100fef9d 112 * Delete the tag for a contact
6a488035
TO
113 *
114 * @param array $params (reference ) an assoc array of name/value pairs
115 *
c490a46a 116 * @return CRM_Core_BAO_EntityTag object
6a488035
TO
117 * @static
118 *
119 */
00be9182 120 public static function del(&$params) {
6a488035
TO
121 $entityTag = new CRM_Core_BAO_EntityTag();
122 $entityTag->copyValues($params);
355b20b1 123 $entityTag->delete();
6a488035 124
355b20b1 125 //invoke post hook on entityTag
126 $object = array(0 => array(0 => $params['entity_id']), 1 => $params['entity_table']);
127 CRM_Utils_Hook::post('delete', 'EntityTag', $params['tag_id'], $object);
6a488035
TO
128 }
129
130 /**
131 * Given an array of entity ids and entity table, add all the entity to the tags
132 *
da6b46f4
EM
133 * @param array $entityIds (reference ) the array of entity ids to be added
134 * @param int $tagId the id of the tag
c490a46a 135 * @param string $entityTable name of entity table default:civicrm_contact
6a488035 136 *
c490a46a 137 * @return array (total, added, notAdded) count of enities added to tag
6a488035
TO
138 * @static
139 */
00be9182 140 public static function addEntitiesToTag(&$entityIds, $tagId, $entityTable = 'civicrm_contact') {
6a488035
TO
141 $numEntitiesAdded = 0;
142 $numEntitiesNotAdded = 0;
143 $entityIdsAdded = array();
144
145 foreach ($entityIds as $entityId) {
146 $tag = new CRM_Core_DAO_EntityTag();
147
148 $tag->entity_id = $entityId;
149 $tag->tag_id = $tagId;
150 $tag->entity_table = $entityTable;
151 if (!$tag->find()) {
152 $tag->save();
153 $entityIdsAdded[] = $entityId;
154 $numEntitiesAdded++;
155 }
156 else {
157 $numEntitiesNotAdded++;
158 }
159 }
160
161 //invoke post hook on entityTag
162 $object = array($entityIdsAdded, $entityTable);
163 CRM_Utils_Hook::post('create', 'EntityTag', $tagId, $object);
164
165 // reset the group contact cache for all groups
166 // if tags are being used in a smart group
167 CRM_Contact_BAO_GroupContactCache::remove();
168
169 return array(count($entityIds), $numEntitiesAdded, $numEntitiesNotAdded);
170 }
171
172 /**
173 * Given an array of entity ids and entity table, remove entity(s) tags
174 *
da6b46f4
EM
175 * @param array $entityIds (reference ) the array of entity ids to be removed
176 * @param int $tagId the id of the tag
c490a46a 177 * @param string $entityTable name of entity table default:civicrm_contact
6a488035 178 *
c490a46a 179 * @return array (total, removed, notRemoved) count of entities removed from tags
6a488035
TO
180 * @static
181 */
00be9182 182 public static function removeEntitiesFromTag(&$entityIds, $tagId, $entityTable = 'civicrm_contact') {
6a488035
TO
183 $numEntitiesRemoved = 0;
184 $numEntitiesNotRemoved = 0;
185 $entityIdsRemoved = array();
186
187 foreach ($entityIds as $entityId) {
188 $tag = new CRM_Core_DAO_EntityTag();
189
190 $tag->entity_id = $entityId;
191 $tag->tag_id = $tagId;
192 $tag->entity_table = $entityTable;
193 if ($tag->find()) {
194 $tag->delete();
195 $entityIdsRemoved[] = $entityId;
196 $numEntitiesRemoved++;
197 }
198 else {
199 $numEntitiesNotRemoved++;
200 }
201 }
202
203 //invoke post hook on entityTag
204 $object = array($entityIdsRemoved, $entityTable);
205 CRM_Utils_Hook::post('delete', 'EntityTag', $tagId, $object);
206
207 // reset the group contact cache for all groups
208 // if tags are being used in a smart group
209 CRM_Contact_BAO_GroupContactCache::remove();
210
211 return array(count($entityIds), $numEntitiesRemoved, $numEntitiesNotRemoved);
212 }
213
214 /**
100fef9d 215 * Takes an associative array and creates tag entity record for all tag entities
6a488035 216 *
c490a46a 217 * @param array $params (reference) an assoc array of name/value pairs
dd244018 218 * @param $entityTable
100fef9d 219 * @param int $entityID
dd244018 220 *
6a488035 221 * @return void
6a488035
TO
222 * @static
223 */
00be9182 224 public static function create(&$params, $entityTable, $entityID) {
6a488035
TO
225 // get categories for the entity id
226 $entityTag = CRM_Core_BAO_EntityTag::getTag($entityID, $entityTable);
227
228 // get the list of all the categories
229 $allTag = CRM_Core_BAO_Tag::getTags($entityTable);
230
231 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
232 if (!is_array($params)) {
233 $params = array();
234 }
235
236 // this fix is done to prevent warning generated by array_key_exits incase of empty array is given as input
237 if (!is_array($entityTag)) {
238 $entityTag = array();
239 }
240
241 // check which values has to be inserted/deleted for contact
242 foreach ($allTag as $key => $varValue) {
243 $tagParams['entity_table'] = $entityTable;
244 $tagParams['entity_id'] = $entityID;
245 $tagParams['tag_id'] = $key;
246
247 if (array_key_exists($key, $params) && !array_key_exists($key, $entityTag)) {
248 // insert a new record
249 CRM_Core_BAO_EntityTag::add($tagParams);
250 }
251 elseif (!array_key_exists($key, $params) && array_key_exists($key, $entityTag)) {
252 // delete a record for existing contact
253 CRM_Core_BAO_EntityTag::del($tagParams);
254 }
255 }
256 }
257
258 /**
259 * This function returns all entities assigned to a specific tag
260 *
261 * @param object $tag an object of a tag.
262 *
07fc2fd3 263 * @return array $entityIds array of entity ids
6a488035 264 */
00be9182 265 public function getEntitiesByTag($tag) {
07fc2fd3 266 $entityIds = array();
6a488035
TO
267 $entityTagDAO = new CRM_Core_DAO_EntityTag();
268 $entityTagDAO->tag_id = $tag->id;
269 $entityTagDAO->find();
270 while ($entityTagDAO->fetch()) {
07fc2fd3 271 $entityIds[] = $entityTagDAO->entity_id;
6a488035 272 }
07fc2fd3 273 return $entityIds;
6a488035
TO
274 }
275
276 /**
100fef9d 277 * Get contact tags
6a488035 278 */
00be9182 279 public static function getContactTags($contactID, $count = FALSE) {
6a488035
TO
280 $contactTags = array();
281 if (!$count) {
282 $select = "SELECT name ";
283 }
284 else {
285 $select = "SELECT count(*) as cnt";
286 }
287
8ef12e64 288 $query = "{$select}
289 FROM civicrm_tag ct
6a488035
TO
290 INNER JOIN civicrm_entity_tag et ON ( ct.id = et.tag_id AND
291 et.entity_id = {$contactID} AND
292 et.entity_table = 'civicrm_contact' AND
293 ct.is_tagset = 0 )";
294
295 $dao = CRM_Core_DAO::executeQuery($query);
296
297 if ($count) {
298 $dao->fetch();
299 return $dao->cnt;
300 }
301
302 while ($dao->fetch()) {
303 $contactTags[] = $dao->name;
304 }
305
306 return $contactTags;
307 }
308
309 /**
100fef9d 310 * Get child contact tags given parentId
6a488035 311 */
00be9182 312 public static function getChildEntityTags($parentId, $entityId, $entityTable = 'civicrm_contact') {
6a488035
TO
313 $entityTags = array();
314 $query = "SELECT ct.id as tag_id, name FROM civicrm_tag ct
315 INNER JOIN civicrm_entity_tag et ON ( et.entity_id = {$entityId} AND
316 et.entity_table = '{$entityTable}' AND et.tag_id = ct.id)
317 WHERE ct.parent_id = {$parentId}";
318
319 $dao = CRM_Core_DAO::executeQuery($query);
320
321 while ($dao->fetch()) {
322 $entityTags[$dao->tag_id] = array(
323 'id' => $dao->tag_id,
324 'name' => $dao->name,
325 );
326 }
327
328 return $entityTags;
329 }
330
331 /**
100fef9d 332 * Merge two tags: tag B into tag A.
6a488035 333 */
00be9182 334 public function mergeTags($tagAId, $tagBId) {
6a488035
TO
335 $queryParams = array(1 => array($tagBId, 'Integer'),
336 2 => array($tagAId, 'Integer'),
337 );
338
339 // re-compute used_for field
340 $query = "SELECT id, name, used_for FROM civicrm_tag WHERE id IN (%1, %2)";
341 $dao = CRM_Core_DAO::executeQuery($query, $queryParams);
342 $tags = array();
343 while ($dao->fetch()) {
344 $label = ($dao->id == $tagAId) ? 'tagA' : 'tagB';
345 $tags[$label] = $dao->name;
346 $tags["{$label}_used_for"] = $dao->used_for ? explode(",", $dao->used_for) : array();
347 }
348 $usedFor = array_merge($tags["tagA_used_for"], $tags["tagB_used_for"]);
349 $usedFor = implode(',', array_unique($usedFor));
350 $tags["tagB_used_for"] = explode(",", $usedFor);
351
352 // get all merge queries together
353 $sqls = array(
354 // 1. update entity tag entries
c2105be3 355 "UPDATE IGNORE civicrm_entity_tag SET tag_id = %1 WHERE tag_id = %2",
6a488035
TO
356 // 2. update used_for info for tag B
357 "UPDATE civicrm_tag SET used_for = '{$usedFor}' WHERE id = %1",
358 // 3. remove tag A, if tag A is getting merged into B
359 "DELETE FROM civicrm_tag WHERE id = %2",
360 // 4. remove duplicate entity tag records
361 "DELETE et2.* from civicrm_entity_tag et1 INNER JOIN civicrm_entity_tag et2 ON et1.entity_table = et2.entity_table AND et1.entity_id = et2.entity_id AND et1.tag_id = et2.tag_id WHERE et1.id < et2.id",
c2105be3
BS
362 // 5. remove orphaned entity_tags
363 "DELETE FROM civicrm_entity_tag WHERE tag_id = %2",
6a488035
TO
364 );
365 $tables = array('civicrm_entity_tag', 'civicrm_tag');
366
367 // Allow hook_civicrm_merge() to add SQL statements for the merge operation AND / OR
368 // perform any other actions like logging
369 CRM_Utils_Hook::merge('sqls', $sqls, $tagAId, $tagBId, $tables);
370
371 // call the SQL queries in one transaction
372 $transaction = new CRM_Core_Transaction();
373 foreach ($sqls as $sql) {
374 CRM_Core_DAO::executeQuery($sql, $queryParams, TRUE, NULL, TRUE);
375 }
376 $transaction->commit();
377
378 $tags['status'] = TRUE;
379 return $tags;
380 }
76773c5a
CW
381
382 /**
383 * Get options for a given field.
384 * @see CRM_Core_DAO::buildOptions
385 *
386 * @param String $fieldName
387 * @param String $context : @see CRM_Core_DAO::buildOptionsContext
388 * @param Array $props : whatever is known about this dao object
389 *
390 * @return Array|bool
391 */
392 public static function buildOptions($fieldName, $context = NULL, $props = array()) {
393 $params = array();
394
395 $options = CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params, $context);
396
397 // Output tag list as nested hierarchy
398 // TODO: This will only work when api.entity is "entity_tag". What about others?
399 if (($fieldName == 'tag' || $fieldName == 'tag_id') && ($context == 'search' || $context == 'create')) {
400 $options = CRM_Core_BAO_Tag::getTags('civicrm_contact', CRM_Core_DAO::$_nullArray, CRM_Utils_Array::value('parent_id', $params), '- ');
401 }
402
403 return $options;
404 }
6a488035 405}