entity.class.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. <?php
  2. /**
  3. * @file
  4. * Define Linkit entity search plugin class.
  5. */
  6. /**
  7. * Represents a Linkit entity search plugin.
  8. */
  9. class LinkitSearchPluginEntity extends LinkitSearchPlugin {
  10. /**
  11. * Entity field query instance.
  12. *
  13. * @var EntityFieldQuery Resource
  14. */
  15. var $query;
  16. /**
  17. * The entity info array of an entity type.
  18. *
  19. * @var array
  20. */
  21. var $entity_info = array();
  22. /**
  23. * The name of the property that contains the entity label.
  24. *
  25. * @var string
  26. */
  27. var $entity_field_label;
  28. /**
  29. * The name of the property of the bundle object that contains the name of
  30. * the bundle object.
  31. *
  32. * @var string
  33. */
  34. var $entity_key_bundle;
  35. /**
  36. * Plugin specific settings.
  37. *
  38. * @var array
  39. */
  40. var $conf = array();
  41. /**
  42. * Overrides LinkitSearchPlugin::__construct().
  43. *
  44. * Initialize this plugin with the plugin, profile, and entity specific
  45. * variables.
  46. *
  47. * @param array $plugin
  48. * The plugin array.
  49. *
  50. * @param LinkitProfile object $profile
  51. * The Linkit profile to use.
  52. */
  53. function __construct($plugin, LinkitProfile $profile) {
  54. parent::__construct($plugin, $profile);
  55. // Load the corresponding entity info.
  56. $this->entity_info = entity_get_info($this->plugin['entity_type']);
  57. // Set bundle key name.
  58. if (isset($this->entity_info['entity keys']['bundle']) &&
  59. !isset($this->entity_key_bundle)) {
  60. $this->entity_key_bundle = $this->entity_info['entity keys']['bundle'];
  61. }
  62. // Set the label field name.
  63. if (!isset($this->entity_field_label)) {
  64. // Check that the entity has a label in entity keys.
  65. // If not, Linkit don't know what to search for.
  66. if (!isset($this->entity_info['entity keys']['label'])) {
  67. // This is only used when building the plugin list.
  68. $this->unusable = TRUE;
  69. }
  70. else {
  71. $this->entity_field_label = $this->entity_info['entity keys']['label'];
  72. }
  73. }
  74. // Make a shortcut for the profile data settings for this plugin.
  75. $this->conf = isset($this->profile->data[$this->plugin['name']]) ?
  76. $this->profile->data[$this->plugin['name']] : array();
  77. }
  78. /**
  79. * Create a label of an entity.
  80. *
  81. * @param $entity
  82. * The entity to get the label from.
  83. *
  84. * @return
  85. * The entity label, or FALSE if not found.
  86. */
  87. function createLabel($entity) {
  88. return filter_xss(entity_label($this->plugin['entity_type'], $entity));
  89. }
  90. /**
  91. * Create a search row description.
  92. *
  93. * If there is a "result_description", run it through token_replace.
  94. *
  95. * @param object $data
  96. * An entity object that will be used in the token_place function.
  97. *
  98. * @return
  99. * A string containing the row description.
  100. *
  101. * @see token_replace()
  102. */
  103. function createDescription($data) {
  104. $description = token_replace(check_plain($this->conf['result_description']), array(
  105. $this->plugin['entity_type'] => $data,
  106. ), array('clear' => TRUE));
  107. return $description;
  108. }
  109. /**
  110. * Create an uri for an entity.
  111. *
  112. * @param $entity
  113. * The entity to get the path from.
  114. *
  115. * @return
  116. * A string containing the path of the entity, NULL if the entity has no
  117. * uri of its own.
  118. */
  119. function createPath($entity) {
  120. // Create the URI for the entity.
  121. $uri = entity_uri($this->plugin['entity_type'], $entity);
  122. $options = array();
  123. // Handle multilingual sites.
  124. if (isset($entity->language) && $entity->language != LANGUAGE_NONE && drupal_multilingual() && language_negotiation_get_any(LOCALE_LANGUAGE_NEGOTIATION_URL)) {
  125. $languages = language_list('enabled');
  126. // Only use enabled languages.
  127. $languages = $languages[1];
  128. if ($languages && isset($languages[$entity->language])) {
  129. $options['language'] = $languages[$entity->language];
  130. }
  131. }
  132. // Process the uri with the insert plugin.
  133. $path = linkit_get_insert_plugin_processed_path($this->profile, $uri['path'], $options);
  134. return $path;
  135. }
  136. /**
  137. * Create a group text.
  138. *
  139. * @param $entity
  140. * The entity object.
  141. *
  142. * @return
  143. * When "group_by_bundle" is active, we need to add the bundle name to the
  144. * group, else just return the entity label.
  145. */
  146. function createGroup($entity) {
  147. // Get the entity label.
  148. $group = $this->entity_info['label'];
  149. // If the entities by this entity should be grouped by bundle, get the
  150. // name and append it to the group.
  151. if (isset($this->conf['group_by_bundle']) && $this->conf['group_by_bundle']) {
  152. $bundles = $this->entity_info['bundles'];
  153. $bundle_name = $bundles[$entity->{$this->entity_key_bundle}]['label'];
  154. $group .= ' - ' . check_plain($bundle_name);
  155. }
  156. return $group;
  157. }
  158. /**
  159. * Create a row class to append to the search result row.
  160. *
  161. * @param $entity
  162. * The entity object.
  163. *
  164. * @return
  165. * A string to with classes.
  166. */
  167. function createRowClass($entity) {
  168. return '';
  169. }
  170. /**
  171. * Start a new EntityFieldQuery instance.
  172. */
  173. function getQueryInstance() {
  174. $this->query = new EntityFieldQuery();
  175. $this->query->entityCondition('entity_type', $this->plugin['entity_type']);
  176. // Add the default sort on the entity label.
  177. $this->query->propertyOrderBy($this->entity_field_label, 'ASC');
  178. }
  179. /**
  180. * Implements LinkitSearchPluginInterface::fetchResults().
  181. */
  182. public function fetchResults($search_string) {
  183. // If the $search_string is not a string, something is wrong and an empty
  184. // array is returned.
  185. $matches = array();
  186. // Get the EntityFieldQuery instance.
  187. $this->getQueryInstance();
  188. // Add the search condition to the query object.
  189. $this->query->propertyCondition($this->entity_field_label,
  190. '%' . db_like($search_string) . '%', 'LIKE')
  191. ->addTag('linkit_entity_autocomplete')
  192. ->addTag('linkit_' . $this->plugin['entity_type'] . '_autocomplete');
  193. // Add access tag for the query.
  194. // There is also a runtime access check that uses entity_access().
  195. $this->query->addTag($this->plugin['entity_type'] . '_access');
  196. // Bundle check.
  197. if (isset($this->entity_key_bundle) && isset($this->conf['bundles']) ) {
  198. $bundles = array_filter($this->conf['bundles']);
  199. if ($bundles) {
  200. $this->query->propertyCondition($this->entity_key_bundle, $bundles, 'IN');
  201. }
  202. }
  203. // Execute the query.
  204. $result = $this->query->execute();
  205. if (!isset($result[$this->plugin['entity_type']])) {
  206. return array();
  207. }
  208. $ids = array_keys($result[$this->plugin['entity_type']]);
  209. // Load all the entities with all the ids we got.
  210. $entities = entity_load($this->plugin['entity_type'], $ids);
  211. foreach ($entities AS $entity) {
  212. // Check the access against the defined entity access callback.
  213. if (entity_access('view', $this->plugin['entity_type'], $entity) === FALSE) {
  214. continue;
  215. }
  216. $matches[] = array(
  217. 'title' => $this->createLabel($entity),
  218. 'description' => $this->createDescription($entity),
  219. 'path' => $this->createPath($entity),
  220. 'group' => $this->createGroup($entity),
  221. 'addClass' => $this->createRowClass($entity),
  222. );
  223. }
  224. return $matches;
  225. }
  226. /**
  227. * Overrides LinkitSearchPlugin::buildSettingsForm().
  228. */
  229. function buildSettingsForm() {
  230. $form[$this->plugin['name']] = array(
  231. '#type' => 'fieldset',
  232. '#title' => t('!type plugin settings', array('!type' => $this->ui_title())),
  233. '#collapsible' => TRUE,
  234. '#collapsed' => TRUE,
  235. '#tree' => TRUE,
  236. '#states' => array(
  237. 'invisible' => array(
  238. 'input[name="data[search_plugins][' . $this->plugin['name'] . '][enabled]"]' => array('checked' => FALSE),
  239. ),
  240. ),
  241. );
  242. // Get supported tokens for the entity type.
  243. $tokens = linkit_extract_tokens($this->plugin['entity_type']);
  244. // A short description within the search result for each row.
  245. $form[$this->plugin['name']]['result_description'] = array(
  246. '#title' => t('Result description'),
  247. '#type' => 'textfield',
  248. '#default_value' => isset($this->conf['result_description']) ? $this->conf['result_description'] : '',
  249. '#size' => 120,
  250. '#maxlength' => 255,
  251. '#description' => t('Available tokens: %tokens.', array('%tokens' => implode(', ', $tokens))),
  252. );
  253. // If the token module is installed, lets do some fancy stuff with the
  254. // token chooser.
  255. if (module_exists('token')) {
  256. // Unset the regular description if token module is enabled.
  257. unset($form[$this->plugin['name']]['result_description']['#description']);
  258. // Display the user documentation of placeholders.
  259. $form[$this->plugin['name']]['token_help'] = array(
  260. '#title' => t('Replacement patterns'),
  261. '#type' => 'markup',
  262. );
  263. $form[$this->plugin['name']]['token_help']['help'] = array(
  264. '#theme' => 'token_tree_link',
  265. '#token_types' => array($this->plugin['entity_type']),
  266. );
  267. }
  268. // If there are bundles, add some default settings features.
  269. if (count($this->entity_info['bundles']) > 1) {
  270. $bundles = array();
  271. // Extract the bundle data.
  272. foreach ($this->entity_info['bundles'] as $bundle_name => $bundle) {
  273. $bundles[$bundle_name] = $bundle['label'];
  274. }
  275. // Filter the possible bundles to use if the entity has bundles.
  276. $form[$this->plugin['name']]['bundles'] = array(
  277. '#title' => t('Type filter'),
  278. '#type' => 'checkboxes',
  279. '#options' => $bundles,
  280. '#default_value' => isset($this->conf['bundles']) ? $this->conf['bundles'] : array(),
  281. '#description' => t('If left blank, all types will appear in autocomplete results.'),
  282. );
  283. // Group the results with this bundle.
  284. $form[$this->plugin['name']]['group_by_bundle'] = array(
  285. '#title' => t('Group by bundle'),
  286. '#type' => 'checkbox',
  287. '#default_value' => isset($this->conf['group_by_bundle']) ? $this->conf['group_by_bundle'] : 0,
  288. );
  289. }
  290. return $form;
  291. }
  292. }