This exposes an api entity for the Recent Items stored in the user session.
In the process, it simplifies the process of adding a recent item,
performing most of the lookups automatically.
];
}
+ /**
+ * Get icon for a particular activity (based on type).
+ *
+ * Example: `CRM_Activity_BAO_Activity::getIcon('Activity', 123)`
+ *
+ * @param string $entityName
+ * Always "Activity".
+ * @param int $entityId
+ * Id of the activity.
+ * @throws CRM_Core_Exception
+ */
+ public static function getEntityIcon(string $entityName, int $entityId) {
+ $field = Civi\Api4\Activity::getFields(FALSE)
+ ->addWhere('name', '=', 'activity_type_id')
+ ->setLoadOptions(['id', 'label', 'icon'])
+ ->execute()->single();
+ $activityTypes = array_column($field['options'], NULL, 'id');
+ $activityType = CRM_Core_DAO::getFieldValue(parent::class, $entityId, 'activity_type_id');
+ return $activityTypes[$activityType]['icon'] ?? self::$_icon;
+ }
+
}
'id' => $contact->id,
'is_deleted' => 1,
];
- CRM_Utils_Hook::pre('update', $contact->contact_type, $contact->id, $updateParams);
+ CRM_Utils_Hook::pre('edit', $contact->contact_type, $contact->id, $updateParams);
$params = [1 => [$contact->id, 'Integer']];
$query = 'DELETE FROM civicrm_uf_match WHERE contact_id = %1';
$contact->save();
CRM_Core_BAO_Log::register($contact->id, 'civicrm_contact', $contact->id);
- CRM_Utils_Hook::post('update', $contact->contact_type, $contact->id, $contact);
+ CRM_Utils_Hook::post('edit', $contact->contact_type, $contact->id, $contact);
return TRUE;
}
return CRM_Contact_BAO_Contact_Permission::allow($record['id'], $actionType, $userID);
}
+ /**
+ * Get icon for a particular contact.
+ *
+ * Example: `CRM_Contact_BAO_Contact::getIcon('Contact', 123)`
+ *
+ * @param string $entityName
+ * Always "Contact".
+ * @param int $entityId
+ * Id of the contact.
+ * @throws CRM_Core_Exception
+ */
+ public static function getEntityIcon(string $entityName, int $entityId) {
+ $contactTypes = CRM_Contact_BAO_ContactType::getAllContactTypes();
+ $subTypes = CRM_Utils_Array::explodePadded(CRM_Core_DAO::getFieldValue(parent::class, $entityId, 'contact_sub_type'));
+ foreach ((array) $subTypes as $subType) {
+ if (!empty($contactTypes[$subType]['icon'])) {
+ return $contactTypes[$subType]['icon'];
+ }
+ }
+ // If no sub-type icon, lookup contact type
+ $contactType = CRM_Core_DAO::getFieldValue(parent::class, $entityId, 'contact_type');
+ return $contactTypes[$contactType]['icon'] ?? self::$_icon;
+ }
+
}
CRM_Utils_Recent::add($contact->display_name,
CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $contact->id),
$contact->id,
- $this->_contactType,
+ 'Contact',
$contact->id,
$contact->display_name,
$recentOther
$recentOther = [
'imageUrl' => $contactImageUrl,
- 'subtype' => $contactSubtype,
- 'isDeleted' => $isDeleted,
+ 'is_deleted' => $isDeleted,
];
if (CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::EDIT)) {
CRM_Utils_Recent::add($displayName,
CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_contactId}"),
$this->_contactId,
- $contactType,
+ 'Contact',
$this->_contactId,
$displayName,
$recentOther
return static::$_paths ?? [];
}
+ /**
+ * Overridable function to get icon for a particular entity.
+ *
+ * Example: `CRM_Contact_BAO_Contact::getIcon('Contact', 123)`
+ *
+ * @param string $entityName
+ * Short name of the entity. This may seem redundant because the entity name can usually be inferred
+ * from the BAO class being called, but not always. Some virtual entities share a BAO class.
+ * @param int $entityId
+ * Id of the entity.
+ * @throws CRM_Core_Exception
+ */
+ public static function getEntityIcon(string $entityName, int $entityId) {
+ if (static::class === 'CRM_Core_DAO' || static::class !== CRM_Core_DAO_AllCoreTables::getBAOClassName(static::class)) {
+ throw new CRM_Core_Exception('CRM_Core_DAO::getIcon must be called on a BAO class e.g. CRM_Contact_BAO_Contact::getIcon("Contact", 123).');
+ }
+ // By default, just return the icon representing this entity. If there's more complex lookup to do,
+ // the BAO for this entity should override this method.
+ return static::$_icon;
+ }
+
/**
* When creating a record without a supplied name,
* create a unique, clean name derived from the label.
* @copyright CiviCRM LLC https://civicrm.org/licensing
*/
+use Civi\Api4\Utils\CoreUtil;
+
/**
* Recent items utility class.
*/
return self::$_recent;
}
+ /**
+ * Create function used by the API - supplies defaults
+ *
+ * @param array $params
+ */
+ public static function create(array $params) {
+ $params['title'] = $params['title'] ?? self::getTitle($params['entity_type'], $params['entity_id']);
+ $params['view_url'] = $params['view_url'] ?? self::getUrl($params['entity_type'], $params['entity_id'], 'view');
+ $params['edit_url'] = $params['edit_url'] ?? self::getUrl($params['entity_type'], $params['entity_id'], 'update');
+ $params['delete_url'] = $params['delete_url'] ?? (empty($params['is_deleted']) ? self::getUrl($params['entity_type'], $params['entity_id'], 'delete') : NULL);
+ self::add($params['title'], $params['view_url'], $params['entity_id'], $params['entity_type'], $params['contact_id'] ?? NULL, NULL, $params);
+ return $params;
+ }
+
/**
* Add an item to the recent stack.
*
* The title to display.
* @param string $url
* The link for the above title.
- * @param string $id
+ * @param string $entityId
* Object id.
- * @param string $type
+ * @param string $entityType
* @param int $contactId
+ * Deprecated, probably unused param
* @param string $contactName
+ * Deprecated, probably unused param
* @param array $others
*/
public static function add(
$title,
$url,
- $id,
- $type,
+ $entityId,
+ $entityType,
$contactId,
$contactName,
$others = []
) {
+ $entityType = self::normalizeEntityType($entityType);
+
// Abort if this entity type is not supported
- if (!self::isProviderEnabled($type)) {
+ if (!self::isProviderEnabled($entityType)) {
return;
}
// Ensure item is not already present in list
- self::removeItems(['id' => $id, 'type' => $type]);
+ self::removeItems(['entity_id' => $entityId, 'entity_type' => $entityType]);
if (!is_array($others)) {
$others = [];
array_unshift(self::$_recent,
[
'title' => $title,
+ // TODO: deprecate & remove "url" in favor of "view_url"
'url' => $url,
- 'id' => $id,
- 'type' => $type,
+ 'view_url' => $url,
+ // TODO: deprecate & remove "id" in favor of "entity_id"
+ 'id' => $entityId,
+ 'entity_id' => (int) $entityId,
+ // TODO: deprecate & remove "type" in favor of "entity_type"
+ 'type' => $entityType,
+ 'entity_type' => $entityType,
+ // Deprecated param
'contact_id' => $contactId,
+ // Param appears to be unused
'contactName' => $contactName,
'subtype' => $others['subtype'] ?? NULL,
- 'isDeleted' => $others['isDeleted'] ?? FALSE,
+ // TODO: deprecate & remove "isDeleted" in favor of "is_deleted"
+ 'isDeleted' => $others['is_deleted'] ?? $others['isDeleted'] ?? FALSE,
+ 'is_deleted' => (bool) ($others['is_deleted'] ?? $others['isDeleted'] ?? FALSE),
+ // imageUrl is deprecated
'image_url' => $others['imageUrl'] ?? NULL,
- 'edit_url' => $others['editUrl'] ?? NULL,
- 'delete_url' => $others['deleteUrl'] ?? NULL,
- 'icon' => $others['icon'] ?? self::getIcon($type, $others['subtype'] ?? NULL),
+ 'edit_url' => $others['edit_url'] ?? $others['editUrl'] ?? NULL,
+ 'delete_url' => $others['delete_url'] ?? $others['deleteUrl'] ?? NULL,
+ 'icon' => $others['icon'] ?? self::getIcon($entityType, $entityId),
]
);
}
/**
- * @param $type
- * @param $subType
+ * Get default title for this item, based on the entity's `label_field`
+ *
+ * @param string $entityType
+ * @param int $entityId
+ * @return string|null
+ */
+ private static function getTitle($entityType, $entityId) {
+ $labelField = CoreUtil::getInfoItem($entityType, 'label_field');
+ $title = NULL;
+ if ($labelField) {
+ $record = civicrm_api4($entityType, 'get', [
+ 'where' => [['id', '=', $entityId]],
+ 'select' => [$labelField],
+ ], 0);
+ $title = $record[$labelField] ?? NULL;
+ }
+ return $title ?? (CoreUtil::getInfoItem($entityType, 'label_field'));
+ }
+
+ /**
+ * Get a link to view/update/delete a given entity.
+ *
+ * @param string $entityType
+ * @param int $entityId
+ * @param string $action
+ * Either 'view', 'update', or 'delete'
* @return string|null
*/
- private static function getIcon($type, $subType) {
- $icon = NULL;
- $contactTypes = CRM_Contact_BAO_ContactType::getAllContactTypes();
- if (!empty($contactTypes[$type])) {
- // Pick icon from contact sub-type first if available, then contact type
- $subTypesAndType = array_merge((array) CRM_Utils_Array::explodePadded($subType), [$type]);
- foreach ($subTypesAndType as $contactType) {
- $icon = $icon ?? $contactTypes[$contactType]['icon'] ?? NULL;
+ private static function getUrl($entityType, $entityId, $action) {
+ if ($action !== 'view') {
+ $check = civicrm_api4($entityType, 'checkAccess', [
+ 'action' => $action,
+ 'values' => ['id' => $entityId],
+ ], 0);
+ if (empty($check['access'])) {
+ return NULL;
}
- // If no contact type icon, proceed to lookup icon from dao
- $type = 'Contact';
}
- if (!$icon) {
- $daoClass = CRM_Core_DAO_AllCoreTables::getFullName($type);
- if ($daoClass) {
- $icon = $daoClass::$_icon;
- }
+ $paths = (array) CoreUtil::getInfoItem($entityType, 'paths');
+ if (!empty($paths[$action])) {
+ return CRM_Utils_System::url(str_replace('[id]', $entityId, $paths[$action]));
+ }
+ return NULL;
+ }
+
+ /**
+ * @param $entityType
+ * @param $entityId
+ * @return string|null
+ */
+ private static function getIcon($entityType, $entityId) {
+ $icon = NULL;
+ $daoClass = CRM_Core_DAO_AllCoreTables::getFullName($entityType);
+ if ($daoClass) {
+ $icon = CRM_Core_DAO_AllCoreTables::getBAOClassName($daoClass)::getEntityIcon($entityType, $entityId);
}
return $icon ?: 'fa-gear';
}
* @param \Civi\Core\Event\PostEvent $event
*/
public static function on_hook_civicrm_post(\Civi\Core\Event\PostEvent $event) {
- if ($event->action === 'delete' && $event->id && CRM_Core_Session::getLoggedInContactID()) {
- // Is this an entity that might be in the recent items list?
- $providersPermitted = Civi::settings()->get('recentItemsProviders') ?: array_keys(self::getProviders());
- if (in_array($event->entity, $providersPermitted)) {
- self::del(['id' => $event->id, 'type' => $event->entity]);
+ if ($event->id && CRM_Core_Session::getLoggedInContactID()) {
+ $entityType = self::normalizeEntityType($event->entity);
+ if ($event->action === 'delete') {
+ // Is this an entity that might be in the recent items list?
+ $providersPermitted = Civi::settings()->get('recentItemsProviders') ?: array_keys(self::getProviders());
+ if (in_array($entityType, $providersPermitted)) {
+ self::del(['entity_id' => $event->id, 'entity_type' => $entityType]);
+ }
+ }
+ elseif ($event->action === 'edit') {
+ if (isset($event->object->is_deleted)) {
+ \Civi\Api4\RecentItem::update()
+ ->addWhere('entity_type', '=', $entityType)
+ ->addWhere('entity_id', '=', $event->id)
+ ->addValue('is_deleted', (bool) $event->object->is_deleted)
+ ->execute();
+ }
}
}
}
self::$_recent = array_filter(self::$_recent, function($item) use ($props) {
foreach ($props as $key => $val) {
- if (isset($item[$key]) && $item[$key] != $val) {
+ if (($item[$key] ?? NULL) != $val) {
return TRUE;
}
}
* @return bool
*/
public static function isProviderEnabled($providerName) {
-
- // Join contact types to providerName 'Contact'
- $contactTypes = CRM_Contact_BAO_ContactType::contactTypes(TRUE);
- if (in_array($providerName, $contactTypes)) {
- $providerName = 'Contact';
- }
$allowed = TRUE;
// Use core setting recentItemsProviders if configured
return $allowed;
}
+ /**
+ * @param string $entityType
+ * @return string
+ */
+ private static function normalizeEntityType($entityType) {
+ // Change Individual/Organization/Household to 'Contact'
+ if (in_array($entityType, CRM_Contact_BAO_ContactType::basicTypes(TRUE), TRUE)) {
+ return 'Contact';
+ }
+ return $entityType;
+ }
+
/**
* Gets the list of available providers to civi's recent items stack
*
+ * TODO: Make this an option group so extensions can extend it.
+ *
* @return array
*/
public static function getProviders() {
/**
* Unique identifier for this entity.
*
- * @var string
+ * @var string|string[]
*/
protected static $idField = 'id';
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+namespace Civi\Api4;
+
+/**
+ * Recent Items API.
+ *
+ * Lists the most recently viewed entities by the current user.
+ *
+ * The list is stored in the user's session.
+ * The number of items stored is determined by the setting `recentItemsMaxCount`.
+ *
+ * @searchable secondary
+ * @since 5.49
+ * @package Civi\Api4
+ */
+class RecentItem extends Generic\BasicEntity {
+
+ protected static $idField = ['entity_id', 'entity_type'];
+
+ protected static $getter = ['CRM_Utils_Recent', 'get'];
+ protected static $setter = ['CRM_Utils_Recent', 'create'];
+ protected static $deleter = ['CRM_Utils_Recent', 'del'];
+
+ /**
+ * @param bool $checkPermissions
+ * @return Generic\BasicGetFieldsAction
+ */
+ public static function getFields($checkPermissions = TRUE) {
+ return (new Generic\BasicGetFieldsAction('RecentItem', __FUNCTION__, function() {
+ return [
+ [
+ 'name' => 'entity_id',
+ 'data_type' => 'Integer',
+ 'required' => TRUE,
+ ],
+ [
+ 'name' => 'entity_type',
+ 'title' => 'Entity Type',
+ 'options' => \CRM_Utils_Recent::getProviders(),
+ 'required' => TRUE,
+ ],
+ [
+ 'name' => 'title',
+ ],
+ [
+ 'name' => 'is_deleted',
+ 'data_type' => 'Boolean',
+ ],
+ [
+ 'name' => 'icon',
+ ],
+ [
+ 'name' => 'view_url',
+ 'title' => 'View URL',
+ ],
+ [
+ 'name' => 'edit_url',
+ 'title' => 'Edit URL',
+ ],
+ [
+ 'name' => 'delete_url',
+ 'title' => 'Delete URL',
+ ],
+ ];
+ }))->setCheckPermissions($checkPermissions);
+ }
+
+ /**
+ * @return array
+ */
+ public static function permissions() {
+ return [
+ 'default' => ['access CiviCRM'],
+ ];
+ }
+
+}
use api\v4\UnitTestCase;
use Civi\Api4\Activity;
+use Civi\Api4\RecentItem;
/**
* @group headless
->addValue('subject', 'Hello recent!')
->execute()->first()['id'];
$this->assertEquals(1, $this->getRecentItemCount(['type' => 'Activity', 'id' => $aid1]));
- $this->assertStringContainsString('Hello recent!', \CRM_Utils_Recent::get()[0]['title']);
+ $recentItem = RecentItem::get(FALSE)->execute()->first();
+ $this->assertStringContainsString('Hello recent!', $recentItem['title']);
+ $this->assertStringContainsString("id=$aid1", $recentItem['view_url']);
+ $this->assertEquals('fa-slideshare', $recentItem['icon']);
$aid2 = Activity::create(FALSE)
->addValue('activity_type_id:name', 'Meeting')
->addValue('source_contact_id', $cid)
->addValue('subject', 'Goodbye recent!')
->execute()->first()['id'];
- $this->assertEquals(1, $this->getRecentItemCount(['type' => 'Activity', 'id' => $aid2]));
- $this->assertStringContainsString('Goodbye recent!', \CRM_Utils_Recent::get()[0]['title']);
+ $this->assertEquals(1, $this->getRecentItemCount(['type' => 'Activity', 'entity_id' => $aid2]));
+ $this->assertStringContainsString('Goodbye recent!', RecentItem::get(FALSE)->execute()[0]['title']);
Activity::delete(FALSE)->addWhere('id', '=', $aid1)->execute();
- $this->assertEquals(0, $this->getRecentItemCount(['type' => 'Activity', 'id' => $aid1]));
- $this->assertEquals(1, $this->getRecentItemCount(['type' => 'Activity', 'id' => $aid2]));
+ $this->assertEquals(0, $this->getRecentItemCount(['entity_type' => 'Activity', 'entity_id' => $aid1]));
+ $this->assertEquals(1, $this->getRecentItemCount(['entity_type' => 'Activity', 'entity_id' => $aid2]));
}
/**
* @return int
*/
private function getRecentItemCount($props) {
- $count = 0;
- foreach (\CRM_Utils_Recent::get() as $item) {
- foreach ($props as $key => $val) {
- if (($item[$key] ?? NULL) != $val) {
- continue 2;
- }
- }
- ++$count;
+ $recent = RecentItem::get(FALSE);
+ foreach ($props as $key => $val) {
+ $recent->addWhere($key, '=', $val);
}
- return $count;
+ return $recent->execute()->count();
}
}
->execute()
->indexBy('name');
- $errMsg = sprintf('%s is missing required ID field', $entity);
- $subset = ['data_type' => 'Integer'];
+ $idField = CoreUtil::getIdFieldName($entity);
- $this->assertArrayHasKey('data_type', $fields['id'], $errMsg);
- $this->assertEquals('Integer', $fields['id']['data_type']);
+ $errMsg = sprintf('%s getfields is missing primary key field', $entity);
+
+ $this->assertArrayHasKey($idField, $fields, $errMsg);
+ $this->assertEquals('Integer', $fields[$idField]['data_type']);
// Ensure that the getFields (FieldSpec) format is generally consistent.
foreach ($fields as $field) {
->execute()
->first();
- $this->assertArrayHasKey('id', $createResult, "create missing ID");
- $id = $createResult['id'];
+ $idField = CoreUtil::getIdFieldName($entity);
+
+ $this->assertArrayHasKey($idField, $createResult, "create missing ID");
+ $id = $createResult[$idField];
$this->assertGreaterThanOrEqual(1, $id, "$entity ID not positive");
if (!$isReadOnly) {
$this->assertEquals(1, $this->checkAccessCounts["{$entity}::create"]);
->execute();
$errMsg = sprintf('Failed to fetch a %s after creation', $entity);
- $this->assertEquals($id, $getResult->first()['id'], $errMsg);
+ $idField = CoreUtil::getIdFieldName($entity);
+ $this->assertEquals($id, $getResult->first()[$idField], $errMsg);
$this->assertEquals(1, $getResult->count(), $errMsg);
}
->execute();
$errMsg = sprintf('Failed to fetch a %s after creation', $entity);
- $this->assertEquals($id, $getResult->first()['id'], $errMsg);
+ $idField = CoreUtil::getIdFieldName($entity);
+ $this->assertEquals($id, $getResult->first()[$idField], $errMsg);
$this->assertEquals(1, $getResult->count(), $errMsg);
$this->resetCheckAccess();
}
* @param string $entity
*/
protected function checkGetCount($entityClass, $id, $entity): void {
+ $idField = CoreUtil::getIdFieldName($entity);
$getResult = $entityClass::get(FALSE)
- ->addWhere('id', '=', $id)
+ ->addWhere($idField, '=', $id)
->selectRowCount()
->execute();
$errMsg = sprintf('%s getCount failed', $entity);
$this->assertEquals(0, $this->checkAccessCounts["{$entity}::delete"]);
$isReadOnly = $this->isReadOnly($entityClass);
+ $idField = CoreUtil::getIdFieldName($entity);
$deleteAction = $entityClass::delete()
->setCheckPermissions(!$isReadOnly)
- ->addWhere('id', '=', $id);
+ ->addWhere($idField, '=', $id);
if (property_exists($deleteAction, 'useTrash')) {
$deleteAction->setUseTrash(FALSE);
$deleteResult = $deleteAction->execute();
});
- // We should have emitted an event.
- $hookEntity = ($entity === 'Contact') ? 'Individual' : $entity; /* ooph */
- $this->assertContains("pre.{$hookEntity}.delete", $log, "$entity should emit hook_civicrm_pre() for deletions");
- $this->assertContains("post.{$hookEntity}.delete", $log, "$entity should emit hook_civicrm_post() for deletions");
+ if (in_array('DAOEntity', CoreUtil::getInfoItem($entity, 'type'))) {
+ // We should have emitted an event.
+ $hookEntity = ($entity === 'Contact') ? 'Individual' : $entity;/* ooph */
+ $this->assertContains("pre.{$hookEntity}.delete", $log, "$entity should emit hook_civicrm_pre() for deletions");
+ $this->assertContains("post.{$hookEntity}.delete", $log, "$entity should emit hook_civicrm_post() for deletions");
- // should get back an array of deleted id
- $this->assertEquals([['id' => $id]], (array) $deleteResult);
- if (!$isReadOnly) {
- $this->assertEquals(1, $this->checkAccessCounts["{$entity}::delete"]);
+ // should get back an array of deleted id
+ $this->assertEquals([['id' => $id]], (array) $deleteResult);
+ if (!$isReadOnly) {
+ $this->assertEquals(1, $this->checkAccessCounts["{$entity}::delete"]);
+ }
}
$this->resetCheckAccess();
}
--- /dev/null
+<?php
+
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+
+namespace api\v4\Entity;
+
+use api\v4\UnitTestCase;
+use Civi\Api4\RecentItem;
+use Civi\Api4\Contact;
+use Civi\Test\TransactionalInterface;
+
+/**
+ * Test Address functionality
+ *
+ * @group headless
+ */
+class RecentItemTest extends UnitTestCase implements TransactionalInterface {
+
+ /**
+ *
+ */
+ public function testRecentContact() {
+ $cid = Contact::create(FALSE)
+ ->addValue('first_name', 'Hello')
+ ->execute()->single()['id'];
+
+ $this->createLoggedInUser();
+
+ RecentItem::create(FALSE)
+ ->addValue('entity_type', 'Contact')
+ ->addValue('entity_id', $cid)
+ ->execute();
+
+ $item = RecentItem::get(FALSE)
+ ->addWhere('entity_type', '=', 'Contact')
+ ->addWhere('entity_id', '=', $cid)
+ ->execute()->single();
+
+ $this->assertEquals('Hello', $item['title']);
+ $this->assertEquals('fa-user', $item['icon']);
+ $this->assertEquals(\CRM_Utils_System::url('civicrm/contact/view?reset=1&cid=' . $cid), $item['view_url']);
+
+ RecentItem::delete(FALSE)
+ ->addWhere('entity_type', '=', 'Contact')
+ ->addWhere('entity_id', '=', $cid)
+ ->execute();
+
+ $this->assertCount(0, RecentItem::get(FALSE)
+ ->addWhere('entity_type', '=', 'Contact')
+ ->addWhere('entity_id', '=', $cid)
+ ->execute());
+
+ RecentItem::create(FALSE)
+ ->addValue('entity_type', 'Contact')
+ ->addValue('entity_id', $cid)
+ ->execute();
+
+ $this->assertCount(1, RecentItem::get(FALSE)
+ ->addWhere('entity_type', '=', 'Contact')
+ ->addWhere('entity_id', '=', $cid)
+ ->execute());
+
+ // Move contact to trash
+ Contact::delete(FALSE)->addWhere('id', '=', $cid)->execute();
+ $item = RecentItem::get(FALSE)
+ ->addWhere('entity_type', '=', 'Contact')
+ ->addWhere('entity_id', '=', $cid)
+ ->execute()->single();
+ $this->assertEquals('Hello', $item['title']);
+ $this->assertTrue($item['is_deleted']);
+
+ // Delete contact
+ Contact::delete(FALSE)->setUseTrash(FALSE)->addWhere('id', '=', $cid)->execute();
+
+ $this->assertCount(0, RecentItem::get(FALSE)
+ ->addWhere('entity_type', '=', 'Contact')
+ ->addWhere('entity_id', '=', $cid)
+ ->execute());
+ }
+
+}
'loadOptions' => TRUE,
'where' => [
['OR', [['required', '=', TRUE], ['required_if', 'IS NOT EMPTY']]],
+ ['readonly', 'IS EMPTY'],
],
], 'name');
$requiredParams = array_merge($requiredParams, $overrides[$entity]);
}
- unset($requiredParams['id']);
-
return $requiredParams;
}
}
if ($field['name'] === 'entity_id') {
// What could possibly go wrong with this?
- switch ($field['table_name']) {
+ switch ($field['table_name'] ?? NULL) {
case 'civicrm_financial_item':
return $this->getFkID(FinancialItemCreationSpecProvider::DEFAULT_ENTITY);