83e0bcfa2403e04581f0937da4f9e462a0df7f7c
[yaffs-website] / web / core / modules / views / src / Plugin / views / query / QueryPluginBase.php
1 <?php
2
3 namespace Drupal\views\Plugin\views\query;
4
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Cache\CacheableDependencyInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\views\Plugin\views\PluginBase;
9 use Drupal\views\ViewExecutable;
10 use Drupal\views\Views;
11
12 /**
13  * @defgroup views_query_plugins Views query plugins
14  * @{
15  * Plugins for views queries.
16  *
17  * Query plugins generate and execute a built query object against a
18  * particular storage backend, converting the Views query object into an
19  * actual query. Although query plugins need not necessarily use SQL, most
20  * other handler plugins that affect the query (fields, filters, etc.)
21  * implicitly assume that the query is using SQL.
22  *
23  * Query plugins extend \Drupal\views\Plugin\views\query\QueryPluginBase.
24  * They must be annotated with \Drupal\views\Annotation\ViewsQuery
25  * annotation, and they must be in namespace directory Plugin\views\query.
26  *
27  * @ingroup views_plugins
28  * @see plugin_api
29  */
30
31 /**
32  * Base plugin class for Views queries.
33  */
34 abstract class QueryPluginBase extends PluginBase implements CacheableDependencyInterface {
35
36   /**
37    * A pager plugin that should be provided by the display.
38    *
39    * @var views_plugin_pager
40    */
41   public $pager = NULL;
42
43   /**
44    * Stores the limit of items that should be requested in the query.
45    *
46    * @var int
47    */
48   protected $limit;
49
50   /**
51    * Generate a query and a countquery from all of the information supplied
52    * to the object.
53    *
54    * @param $get_count
55    *   Provide a countquery if this is true, otherwise provide a normal query.
56    */
57   public function query($get_count = FALSE) {}
58
59   /**
60    * Let modules modify the query just prior to finalizing it.
61    *
62    * @param view $view
63    *   The view which is executed.
64    */
65   public function alter(ViewExecutable $view) {}
66
67   /**
68    * Builds the necessary info to execute the query.
69    *
70    * @param view $view
71    *   The view which is executed.
72    */
73   public function build(ViewExecutable $view) {}
74
75   /**
76    * Executes the query and fills the associated view object with according
77    * values.
78    *
79    * Values to set: $view->result, $view->total_rows, $view->execute_time,
80    * $view->pager['current_page'].
81    *
82    * $view->result should contain an array of objects. The array must use a
83    * numeric index starting at 0.
84    *
85    * @param view $view
86    *   The view which is executed.
87    */
88   public function execute(ViewExecutable $view) {}
89
90   /**
91    * Add a signature to the query, if such a thing is feasible.
92    *
93    * This signature is something that can be used when perusing query logs to
94    * discern where particular queries might be coming from.
95    *
96    * @param view $view
97    *   The view which is executed.
98    */
99   public function addSignature(ViewExecutable $view) {}
100
101   /**
102    * Get aggregation info for group by queries.
103    *
104    * If NULL, aggregation is not allowed.
105    */
106   public function getAggregationInfo() {}
107
108   public function validateOptionsForm(&$form, FormStateInterface $form_state) {}
109
110   public function submitOptionsForm(&$form, FormStateInterface $form_state) {}
111
112   public function summaryTitle() {
113     return $this->t('Settings');
114   }
115
116   /**
117    * {@inheritdoc}
118    */
119   public function calculateDependencies() {
120     $dependencies = [];
121
122     foreach ($this->getEntityTableInfo() as $entity_type => $info) {
123       if (!empty($info['provider'])) {
124         $dependencies['module'][] = $info['provider'];
125       }
126     }
127
128     return $dependencies;
129   }
130
131   /**
132    * Set a LIMIT on the query, specifying a maximum number of results.
133    */
134   public function setLimit($limit) {
135     $this->limit = $limit;
136   }
137
138   /**
139    * Set an OFFSET on the query, specifying a number of results to skip
140    */
141   public function setOffset($offset) {
142     $this->offset = $offset;
143   }
144
145   /**
146    * Returns the limit of the query.
147    */
148   public function getLimit() {
149     return $this->limit;
150   }
151
152   /**
153    * Create a new grouping for the WHERE or HAVING clause.
154    *
155    * @param $type
156    *   Either 'AND' or 'OR'. All items within this group will be added
157    *   to the WHERE clause with this logical operator.
158    * @param $group
159    *   An ID to use for this group. If unspecified, an ID will be generated.
160    * @param $where
161    *   'where' or 'having'.
162    *
163    * @return
164    *   The group ID generated.
165    */
166   public function setWhereGroup($type = 'AND', $group = NULL, $where = 'where') {
167     // Set an alias.
168     $groups = &$this->$where;
169
170     if (!isset($group)) {
171       $group = empty($groups) ? 1 : max(array_keys($groups)) + 1;
172     }
173
174     // Create an empty group
175     if (empty($groups[$group])) {
176       $groups[$group] = ['conditions' => [], 'args' => []];
177     }
178
179     $groups[$group]['type'] = strtoupper($type);
180     return $group;
181   }
182
183   /**
184    * Control how all WHERE and HAVING groups are put together.
185    *
186    * @param $type
187    *   Either 'AND' or 'OR'
188    */
189   public function setGroupOperator($type = 'AND') {
190     $this->groupOperator = strtoupper($type);
191   }
192
193   /**
194    * Loads all entities contained in the passed-in $results.
195    *.
196    * If the entity belongs to the base table, then it gets stored in
197    * $result->_entity. Otherwise, it gets stored in
198    * $result->_relationship_entities[$relationship_id];
199    *
200    * Query plugins that don't support entities can leave the method empty.
201    */
202   public function loadEntities(&$results) {}
203
204   /**
205    * Returns a Unix timestamp to database native timestamp expression.
206    *
207    * @param string $field
208    *   The query field that will be used in the expression.
209    * @param bool $string_date
210    *   For certain databases, date format functions vary depending on string or
211    *   numeric storage.
212    * @param bool $calculate_offset
213    *   If set to TRUE, the timezone offset will be included in the returned
214    *   field.
215    *
216    * @return string
217    *   An expression representing a timestamp with time zone.
218    */
219   public function getDateField($field, $string_date = FALSE, $calculate_offset = TRUE) {
220     return $field;
221   }
222
223   /**
224    * Set the database to the current user timezone,
225    *
226    * @return string
227    *   The current timezone as returned by drupal_get_user_timezone().
228    */
229   public function setupTimezone() {
230     return drupal_get_user_timezone();
231   }
232
233   /**
234    * Creates cross-database date formatting.
235    *
236    * @param string $field
237    *   An appropriate query expression pointing to the date field.
238    * @param string $format
239    *   A format string for the result, like 'Y-m-d H:i:s'.
240    * @param bool $string_date
241    *   For certain databases, date format functions vary depending on string or
242    *   numeric storage.
243    *
244    * @return string
245    *   A string representing the field formatted as a date in the format
246    *   specified by $format.
247    */
248   public function getDateFormat($field, $format, $string_date = FALSE) {
249     return $field;
250   }
251
252   /**
253    * Returns an array of all tables from the query that map to an entity type.
254    *
255    * Includes the base table and all relationships, if eligible.
256    *
257    * Available keys for each table:
258    * - base: The actual base table (i.e. "user" for an author relationship).
259    * - relationship_id: The id of the relationship, or "none".
260    * - alias: The alias used for the relationship.
261    * - entity_type: The entity type matching the base table.
262    * - revision: A boolean that specifies whether the table is a base table or
263    *   a revision table of the entity type.
264    *
265    * @return array
266    *   An array of table information, keyed by table alias.
267    */
268   public function getEntityTableInfo() {
269     // Start with the base table.
270     $entity_tables = [];
271     $views_data = Views::viewsData();
272     $base_table = $this->view->storage->get('base_table');
273     $base_table_data = $views_data->get($base_table);
274
275     if (isset($base_table_data['table']['entity type'])) {
276       $entity_tables[$base_table_data['table']['entity type']] = [
277         'base' => $base_table,
278         'alias' => $base_table,
279         'relationship_id' => 'none',
280         'entity_type' => $base_table_data['table']['entity type'],
281         'revision' => $base_table_data['table']['entity revision'],
282       ];
283
284       // Include the entity provider.
285       if (!empty($base_table_data['table']['provider'])) {
286         $entity_tables[$base_table_data['table']['entity type']]['provider'] = $base_table_data['table']['provider'];
287       }
288     }
289
290     // Include all relationships.
291     foreach ((array) $this->view->relationship as $relationship_id => $relationship) {
292       $table_data = $views_data->get($relationship->definition['base']);
293       if (isset($table_data['table']['entity type'])) {
294
295         // If this is not one of the entity base tables, skip it.
296         $entity_type = \Drupal::entityTypeManager()->getDefinition($table_data['table']['entity type']);
297         $entity_base_tables = [$entity_type->getBaseTable(), $entity_type->getDataTable(), $entity_type->getRevisionTable(), $entity_type->getRevisionDataTable()];
298         if (!in_array($relationship->definition['base'], $entity_base_tables)) {
299           continue;
300         }
301
302         $entity_tables[$relationship_id . '__' . $relationship->tableAlias] = [
303           'base' => $relationship->definition['base'],
304           'relationship_id' => $relationship_id,
305           'alias' => $relationship->alias,
306           'entity_type' => $table_data['table']['entity type'],
307           'revision' => $table_data['table']['entity revision'],
308         ];
309
310         // Include the entity provider.
311         if (!empty($table_data['table']['provider'])) {
312           $entity_tables[$relationship_id . '__' . $relationship->tableAlias]['provider'] = $table_data['table']['provider'];
313         }
314       }
315     }
316
317     // Determine which of the tables are revision tables.
318     foreach ($entity_tables as $table_alias => $table) {
319       $entity_type = \Drupal::entityManager()->getDefinition($table['entity_type']);
320       if ($entity_type->getRevisionTable() == $table['base']) {
321         $entity_tables[$table_alias]['revision'] = TRUE;
322       }
323     }
324
325     return $entity_tables;
326   }
327
328   /**
329    * {@inheritdoc}
330    */
331   public function getCacheMaxAge() {
332     return Cache::PERMANENT;
333   }
334
335   /**
336    * {@inheritdoc}
337    */
338   public function getCacheContexts() {
339     $contexts = [];
340     if (($views_data = Views::viewsData()->get($this->view->storage->get('base_table'))) && !empty($views_data['table']['entity type'])) {
341       $entity_type_id = $views_data['table']['entity type'];
342       $entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
343       $contexts = $entity_type->getListCacheContexts();
344     }
345     return $contexts;
346   }
347
348   /**
349    * {@inheritdoc}
350    */
351   public function getCacheTags() {
352     return [];
353   }
354
355   /**
356    * Applies a timezone offset to the given field.
357    *
358    * @param string &$field
359    *   The date field, in string format.
360    * @param int $offset
361    *   The timezone offset to apply to the field.
362    */
363   public function setFieldTimezoneOffset(&$field, $offset) {
364     // No-op. Timezone offsets are implementation-specific and should implement
365     // this method as needed.
366   }
367
368   /**
369    * Get the timezone offset in seconds.
370    *
371    * @return int
372    *   The offset, in seconds, for the timezone being used.
373    */
374   public function getTimezoneOffset() {
375     $timezone = $this->setupTimezone();
376     $offset = 0;
377     if ($timezone) {
378       $dtz = new \DateTimeZone($timezone);
379       $dt = new \DateTime('now', $dtz);
380       $offset = $dtz->getOffset($dt);
381     }
382     return $offset;
383   }
384
385 }
386
387 /**
388  * @}
389  */