Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
7.69% |
6 / 78 |
CRAP | |
22.98% |
145 / 631 |
ViewExecutable | |
0.00% |
0 / 1 |
|
7.69% |
6 / 78 |
37921.36 | |
22.98% |
145 / 631 |
__construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
6 / 6 |
|||
id | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
save | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
setArguments | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
addCacheContext | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
setCurrentPage | |
0.00% |
0 / 1 |
4.07 | |
83.33% |
5 / 6 |
|||
getCurrentPage | |
0.00% |
0 / 1 |
3.07 | |
80.00% |
4 / 5 |
|||
getItemsPerPage | |
0.00% |
0 / 1 |
3.07 | |
80.00% |
4 / 5 |
|||
setItemsPerPage | |
0.00% |
0 / 1 |
3.04 | |
83.33% |
5 / 6 |
|||
getOffset | |
0.00% |
0 / 1 |
3.58 | |
60.00% |
3 / 5 |
|||
setOffset | |
0.00% |
0 / 1 |
3.04 | |
83.33% |
5 / 6 |
|||
usePager | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
setAjaxEnabled | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
ajaxEnabled | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
setExposedInput | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getExposedInput | |
0.00% |
0 / 1 |
56 | |
0.00% |
0 / 10 |
|||
initDisplay | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 6 |
|||
chooseDisplay | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 7 |
|||
getDisplay | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
setDisplay | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 17 |
|||
newDisplay | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 6 |
|||
getStyle | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
initStyle | |
0.00% |
0 / 1 |
3.33 | |
66.67% |
4 / 6 |
|||
initHandlers | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
getPager | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
initPager | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 9 |
|||
renderPager | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 3 |
|||
getBaseTables | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
_preQuery | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 8 |
|||
_postExecute | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 5 |
|||
_initHandler | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
_buildArguments | |
0.00% |
0 / 1 |
210 | |
0.00% |
0 / 38 |
|||
getQuery | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
initQuery | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 10 |
|||
build | |
0.00% |
0 / 1 |
380 | |
0.00% |
0 / 58 |
|||
_build | |
0.00% |
0 / 1 |
110 | |
0.00% |
0 / 20 |
|||
execute | |
0.00% |
0 / 1 |
13.27 | |
62.50% |
15 / 24 |
|||
render | |
0.00% |
0 / 1 |
272 | |
0.00% |
0 / 44 |
|||
getCacheTags | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
buildRenderable | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 4 |
|||
executeDisplay | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 7 |
|||
preview | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 8 |
|||
preExecute | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 9 |
|||
postExecute | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 4 |
|||
attachDisplays | |
0.00% |
0 / 1 |
5.12 | |
83.33% |
10 / 12 |
|||
access | |
0.00% |
0 / 1 |
72 | |
0.00% |
0 / 12 |
|||
setResponse | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getResponse | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
setRequest | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getRequest | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getTitle | |
0.00% |
0 / 1 |
7.19 | |
55.56% |
5 / 9 |
|||
setTitle | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
buildTitle | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 6 |
|||
hasUrl | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 10 |
|||
getUrl | |
0.00% |
0 / 1 |
19 | |
96.97% |
32 / 33 |
|||
getUrlInfo | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
getPath | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 6 |
|||
getUser | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
createDuplicate | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
destroy | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 12 |
|||
validate | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 12 |
|||
getHandlerTypes | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
getPluginTypes | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
addHandler | |
100.00% |
1 / 1 |
6 | |
100.00% |
20 / 20 |
|||
generateHandlerId | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
getHandlers | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 9 |
|||
getHandler | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
setHandler | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 7 |
|||
removeHandler | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 6 |
|||
setHandlerOption | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
setShowAdminLinks | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getShowAdminLinks | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
mergeDefaults | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
buildThemeFunctions | |
100.00% |
1 / 1 |
5 | |
100.00% |
14 / 14 |
|||
hasFormElements | |
0.00% |
0 / 1 |
56 | |
0.00% |
0 / 9 |
|||
getDependencies | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
serialize | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 10 |
|||
unserialize | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 15 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\views\ViewExecutable. | |
*/ | |
namespace Drupal\views; | |
use Drupal\Component\Utility\Html; | |
use Drupal\Component\Utility\Tags; | |
use Drupal\Core\DependencyInjection\DependencySerializationTrait; | |
use Drupal\Core\Form\FormState; | |
use Drupal\Core\Routing\RouteProviderInterface; | |
use Drupal\Core\Session\AccountInterface; | |
use Drupal\views\Plugin\views\display\DisplayRouterInterface; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\Routing\Exception\RouteNotFoundException; | |
/** | |
* Represents a view as a whole. | |
* | |
* An object to contain all of the data to generate a view, plus the member | |
* functions to build the view query, execute the query and render the output. | |
*/ | |
class ViewExecutable implements \Serializable { | |
use DependencySerializationTrait; | |
/** | |
* The config entity in which the view is stored. | |
* | |
* @var \Drupal\views\Entity\View | |
*/ | |
public $storage; | |
/** | |
* Whether or not the view has been built. | |
* | |
* @todo Group with other static properties. | |
* | |
* @var bool | |
*/ | |
public $built = FALSE; | |
/** | |
* Whether the view has been executed/query has been run. | |
* | |
* @todo Group with other static properties. | |
* | |
* @var bool | |
*/ | |
public $executed = FALSE; | |
/** | |
* Any arguments that have been passed into the view. | |
* | |
* @var array | |
*/ | |
public $args = array(); | |
/** | |
* An array of build info. | |
* | |
* @var array | |
*/ | |
public $build_info = array(); | |
/** | |
* Whether this view uses AJAX. | |
* | |
* @var bool | |
*/ | |
protected $ajaxEnabled = FALSE; | |
/** | |
* Where the results of a query will go. | |
* | |
* The array must use a numeric index starting at 0. | |
* | |
* @var \Drupal\views\ResultRow[] | |
*/ | |
public $result = array(); | |
// May be used to override the current pager info. | |
/** | |
* The current page. If the view uses pagination. | |
* | |
* @var int | |
*/ | |
protected $current_page = NULL; | |
/** | |
* The number of items per page. | |
* | |
* @var int | |
*/ | |
protected $items_per_page = NULL; | |
/** | |
* The pager offset. | |
* | |
* @var int | |
*/ | |
protected $offset = NULL; | |
/** | |
* The total number of rows returned from the query. | |
* | |
* @var int | |
*/ | |
public $total_rows = NULL; | |
/** | |
* Attachments to place before the view. | |
* | |
* @var array() | |
*/ | |
public $attachment_before = array(); | |
/** | |
* Attachments to place after the view. | |
* | |
* @var array | |
*/ | |
public $attachment_after = array(); | |
/** | |
* Feed icons attached to the view. | |
* | |
* @var array | |
*/ | |
public $feedIcons = array(); | |
// Exposed widget input | |
/** | |
* All the form data from $form_state->getValues(). | |
* | |
* @var array | |
*/ | |
public $exposed_data = array(); | |
/** | |
* An array of input values from exposed forms. | |
* | |
* @var array | |
*/ | |
protected $exposed_input = array(); | |
/** | |
* Exposed widget input directly from the $form_state->getValues(). | |
* | |
* @var array | |
*/ | |
public $exposed_raw_input = array(); | |
/** | |
* Used to store views that were previously running if we recurse. | |
* | |
* @var \Drupal\views\ViewExecutable[] | |
*/ | |
public $old_view = array(); | |
/** | |
* To avoid recursion in views embedded into areas. | |
* | |
* @var \Drupal\views\ViewExecutable[] | |
*/ | |
public $parent_views = array(); | |
/** | |
* Whether this view is an attachment to another view. | |
* | |
* @var bool | |
*/ | |
public $is_attachment = NULL; | |
/** | |
* Identifier of the current display. | |
* | |
* @var string | |
*/ | |
public $current_display; | |
/** | |
* Where the $query object will reside. | |
* | |
* @var \Drupal\views\Plugin\views\query\QueryPluginBase | |
*/ | |
public $query = NULL; | |
/** | |
* The used pager plugin used by the current executed view. | |
* | |
* @var \Drupal\views\Plugin\views\pager\PagerPluginBase | |
*/ | |
public $pager = NULL; | |
/** | |
* The current used display plugin. | |
* | |
* @var \Drupal\views\Plugin\views\display\DisplayPluginBase | |
*/ | |
public $display_handler; | |
/** | |
* The list of used displays of the view. | |
* | |
* An array containing Drupal\views\Plugin\views\display\DisplayPluginBase | |
* objects. | |
* | |
* @var \Drupal\views\DisplayPluginCollection | |
*/ | |
public $displayHandlers; | |
/** | |
* The current used style plugin. | |
* | |
* @var \Drupal\views\Plugin\views\style\StylePluginBase | |
*/ | |
public $style_plugin; | |
/** | |
* The current used row plugin, if the style plugin supports row plugins. | |
* | |
* @var \Drupal\views\Plugin\views\row\RowPluginBase | |
*/ | |
public $rowPlugin; | |
/** | |
* Stores the current active row while rendering. | |
* | |
* @var int | |
*/ | |
public $row_index; | |
/** | |
* Allow to override the url of the current view. | |
* | |
* @var \Drupal\Core\Url | |
*/ | |
public $override_url; | |
/** | |
* Allow to override the path used for generated urls. | |
* | |
* @var string | |
*/ | |
public $override_path = NULL; | |
/** | |
* Allow to override the used database which is used for this query. | |
* | |
* @var bool | |
*/ | |
public $base_database = NULL; | |
// Handlers which are active on this view. | |
/** | |
* Stores the field handlers which are initialized on this view. | |
* | |
* @var \Drupal\views\Plugin\views\field\FieldPluginBase[] | |
*/ | |
public $field; | |
/** | |
* Stores the argument handlers which are initialized on this view. | |
* | |
* @var \Drupal\views\Plugin\views\argument\ArgumentPluginBase[] | |
*/ | |
public $argument; | |
/** | |
* Stores the sort handlers which are initialized on this view. | |
* | |
* @var \Drupal\views\Plugin\views\sort\SortPluginBase[] | |
*/ | |
public $sort; | |
/** | |
* Stores the filter handlers which are initialized on this view. | |
* | |
* @var \Drupal\views\Plugin\views\filter\FilterPluginBase[] | |
*/ | |
public $filter; | |
/** | |
* Stores the relationship handlers which are initialized on this view. | |
* | |
* @var \Drupal\views\Plugin\views\relationship\RelationshipPluginBase[] | |
*/ | |
public $relationship; | |
/** | |
* Stores the area handlers for the header which are initialized on this view. | |
* | |
* @var \Drupal\views\Plugin\views\area\AreaPluginBase[] | |
*/ | |
public $header; | |
/** | |
* Stores the area handlers for the footer which are initialized on this view. | |
* | |
* @var \Drupal\views\Plugin\views\area\AreaPluginBase[] | |
*/ | |
public $footer; | |
/** | |
* Stores the area handlers for the empty text which are initialized on this view. | |
* | |
* An array containing Drupal\views\Plugin\views\area\AreaPluginBase objects. | |
* | |
* @var \Drupal\views\Plugin\views\area\AreaPluginBase[] | |
*/ | |
public $empty; | |
/** | |
* Stores the current response object. | |
* | |
* @var \Symfony\Component\HttpFoundation\Response | |
*/ | |
protected $response = NULL; | |
/** | |
* Stores the current request object. | |
* | |
* @var \Symfony\Component\HttpFoundation\Request | |
*/ | |
protected $request; | |
/** | |
* Does this view already have loaded it's handlers. | |
* | |
* @todo Group with other static properties. | |
* | |
* @var bool | |
*/ | |
public $inited; | |
/** | |
* The rendered output of the exposed form. | |
* | |
* @var string | |
*/ | |
public $exposed_widgets; | |
/** | |
* If this view has been previewed. | |
* | |
* @var bool | |
*/ | |
public $preview; | |
/** | |
* Force the query to calculate the total number of results. | |
* | |
* @todo Move to the query. | |
* | |
* @var bool | |
*/ | |
public $get_total_rows; | |
/** | |
* Indicates if the sorts have been built. | |
* | |
* @todo Group with other static properties. | |
* | |
* @var bool | |
*/ | |
public $build_sort; | |
/** | |
* Stores the many-to-one tables for performance. | |
* | |
* @var array | |
*/ | |
public $many_to_one_tables; | |
/** | |
* A unique identifier which allows to update multiple views output via js. | |
* | |
* @var string | |
*/ | |
public $dom_id; | |
/** | |
* A render array container to store render related information. | |
* | |
* For example you can alter the array and attach some asset library or JS | |
* settings via the #attached key. This is the required way to add custom | |
* CSS or JS. | |
* | |
* @var array | |
* | |
* @see \Drupal\Core\Render\AttachmentsResponseProcessorInterface::processAttachments() | |
*/ | |
public $element = [ | |
'#attached' => [ | |
'library' => ['views/views.module'], | |
'drupalSettings' => [], | |
], | |
'#cache' => [], | |
]; | |
/** | |
* The current user. | |
* | |
* @var \Drupal\Core\Session\AccountInterface | |
*/ | |
protected $user; | |
/** | |
* Should the admin links be shown on the rendered view. | |
* | |
* @var bool | |
*/ | |
protected $showAdminLinks; | |
/** | |
* The views data. | |
* | |
* @var \Drupal\views\ViewsData | |
*/ | |
protected $viewsData; | |
/** | |
* The route provider. | |
* | |
* @var \Drupal\Core\Routing\RouteProviderInterface | |
*/ | |
protected $routeProvider; | |
/** | |
* Constructs a new ViewExecutable object. | |
* | |
* @param \Drupal\views\ViewEntityInterface $storage | |
* The view config entity the actual information is stored on. | |
* @param \Drupal\Core\Session\AccountInterface $user | |
* The current user. | |
* @param \Drupal\views\ViewsData $views_data | |
* The views data. | |
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider | |
* The route provider. | |
*/ | |
public function __construct(ViewEntityInterface $storage, AccountInterface $user, ViewsData $views_data, RouteProviderInterface $route_provider) { | |
// Reference the storage and the executable to each other. | |
$this->storage = $storage; | |
$this->storage->set('executable', $this); | |
$this->user = $user; | |
$this->viewsData = $views_data; | |
$this->routeProvider = $route_provider; | |
} | |
/** | |
* Returns the identifier. | |
* | |
* @return string|null | |
* The entity identifier, or NULL if the object does not yet have an | |
* identifier. | |
*/ | |
public function id() { | |
return $this->storage->id(); | |
} | |
/** | |
* Saves the view. | |
*/ | |
public function save() { | |
$this->storage->save(); | |
} | |
/** | |
* Sets the arguments for the view. | |
* | |
* @param array $args | |
* The arguments passed to the view. | |
*/ | |
public function setArguments(array $args) { | |
// The array keys of the arguments will be incorrect if set by | |
// views_embed_view() or \Drupal\views\ViewExecutable:preview(). | |
$this->args = array_values($args); | |
} | |
/** | |
* Expands the list of used cache contexts for the view. | |
* | |
* @param string $cache_context | |
* The additional cache context. | |
* | |
* @return $this | |
*/ | |
public function addCacheContext($cache_context) { | |
$this->element['#cache']['contexts'][] = $cache_context; | |
return $this; | |
} | |
/** | |
* Sets the current page for the pager. | |
* | |
* @param int $page | |
* The current page. | |
*/ | |
public function setCurrentPage($page) { | |
$this->current_page = $page; | |
// Calls like ::unserialize() might call this method without a proper $page. | |
// Also check whether the element is pre rendered. At that point, the cache | |
// keys cannot longer be manipulated. | |
if ($page !== NULL && empty($this->element['#pre_rendered'])) { | |
$this->element['#cache']['keys'][] = 'page:' . $page; | |
} | |
// If the pager is already initialized, pass it through to the pager. | |
if (!empty($this->pager)) { | |
return $this->pager->setCurrentPage($page); | |
} | |
} | |
/** | |
* Gets the current page from the pager. | |
* | |
* @return int | |
* The current page. | |
*/ | |
public function getCurrentPage() { | |
// If the pager is already initialized, pass it through to the pager. | |
if (!empty($this->pager)) { | |
return $this->pager->getCurrentPage(); | |
} | |
if (isset($this->current_page)) { | |
return $this->current_page; | |
} | |
} | |
/** | |
* Gets the items per page from the pager. | |
* | |
* @return int | |
* The items per page. | |
*/ | |
public function getItemsPerPage() { | |
// If the pager is already initialized, pass it through to the pager. | |
if (!empty($this->pager)) { | |
return $this->pager->getItemsPerPage(); | |
} | |
if (isset($this->items_per_page)) { | |
return $this->items_per_page; | |
} | |
} | |
/** | |
* Sets the items per page on the pager. | |
* | |
* @param int $items_per_page | |
* The items per page. | |
*/ | |
public function setItemsPerPage($items_per_page) { | |
// Check whether the element is pre rendered. At that point, the cache keys | |
// cannot longer be manipulated. | |
if (empty($this->element['#pre_rendered'])) { | |
$this->element['#cache']['keys'][] = 'items_per_page:' . $items_per_page; | |
} | |
$this->items_per_page = $items_per_page; | |
// If the pager is already initialized, pass it through to the pager. | |
if (!empty($this->pager)) { | |
$this->pager->setItemsPerPage($items_per_page); | |
} | |
} | |
/** | |
* Gets the pager offset from the pager. | |
* | |
* @return int | |
* The pager offset. | |
*/ | |
public function getOffset() { | |
// If the pager is already initialized, pass it through to the pager. | |
if (!empty($this->pager)) { | |
return $this->pager->getOffset(); | |
} | |
if (isset($this->offset)) { | |
return $this->offset; | |
} | |
} | |
/** | |
* Sets the offset on the pager. | |
* | |
* @param int $offset | |
* The pager offset. | |
*/ | |
public function setOffset($offset) { | |
// Check whether the element is pre rendered. At that point, the cache keys | |
// cannot longer be manipulated. | |
if (empty($this->element['#pre_rendered'])) { | |
$this->element['#cache']['keys'][] = 'offset:' . $offset; | |
} | |
$this->offset = $offset; | |
// If the pager is already initialized, pass it through to the pager. | |
if (!empty($this->pager)) { | |
$this->pager->setOffset($offset); | |
} | |
} | |
/** | |
* Determines if the view uses a pager. | |
* | |
* @return bool | |
* TRUE if the view uses a pager, FALSE otherwise. | |
*/ | |
public function usePager() { | |
if (!empty($this->pager)) { | |
return $this->pager->usePager(); | |
} | |
} | |
/** | |
* Sets whether or not AJAX should be used. | |
* | |
* If AJAX is used, paging, table sorting, and exposed filters will be fetched | |
* via an AJAX call rather than a page refresh. | |
* | |
* @param bool $ajax_enabled | |
* TRUE if AJAX should be used, FALSE otherwise. | |
*/ | |
public function setAjaxEnabled($ajax_enabled) { | |
$this->ajaxEnabled = (bool) $ajax_enabled; | |
} | |
/** | |
* Determines whether or not AJAX should be used. | |
* | |
* @return bool | |
* TRUE if AJAX is enabled, FALSE otherwise. | |
*/ | |
public function ajaxEnabled() { | |
return $this->ajaxEnabled; | |
} | |
/** | |
* Sets the exposed filters input to an array. | |
* | |
* @param string[] $filters | |
* The values taken from the view's exposed filters and sorts. | |
*/ | |
public function setExposedInput($filters) { | |
$this->exposed_input = $filters; | |
} | |
/** | |
* Figures out what the exposed input for this view is. | |
* | |
* They will be taken from \Drupal::request()->query or from | |
* something previously set on the view. | |
* | |
* @return string[] | |
* An array containing the exposed input values keyed by the filter and sort | |
* name. | |
* | |
* @see self::setExposedInput() | |
*/ | |
public function getExposedInput() { | |
// Fill our input either from \Drupal::request()->query or from something | |
// previously set on the view. | |
if (empty($this->exposed_input)) { | |
// Ensure that we can call the method at any point in time. | |
$this->initDisplay(); | |
$this->exposed_input = \Drupal::request()->query->all(); | |
// unset items that are definitely not our input: | |
foreach (array('page', 'q') as $key) { | |
if (isset($this->exposed_input[$key])) { | |
unset($this->exposed_input[$key]); | |
} | |
} | |
// If we have no input at all, check for remembered input via session. | |
// If filters are not overridden, store the 'remember' settings on the | |
// default display. If they are, store them on this display. This way, | |
// multiple displays in the same view can share the same filters and | |
// remember settings. | |
$display_id = ($this->display_handler->isDefaulted('filters')) ? 'default' : $this->current_display; | |
if (empty($this->exposed_input) && !empty($_SESSION['views'][$this->storage->id()][$display_id])) { | |
$this->exposed_input = $_SESSION['views'][$this->storage->id()][$display_id]; | |
} | |
} | |
return $this->exposed_input; | |
} | |
/** | |
* Sets the display for this view and initializes the display handler. | |
* | |
* @return true | |
* Always returns TRUE. | |
*/ | |
public function initDisplay() { | |
if (isset($this->current_display)) { | |
return TRUE; | |
} | |
// Initialize the display cache array. | |
$this->displayHandlers = new DisplayPluginCollection($this, Views::pluginManager('display')); | |
$this->current_display = 'default'; | |
$this->display_handler = $this->displayHandlers->get('default'); | |
return TRUE; | |
} | |
/** | |
* Gets the first display that is accessible to the user. | |
* | |
* @param array|string $displays | |
* Either a single display id or an array of display ids. | |
* | |
* @return string | |
* The first accessible display id, at least default. | |
*/ | |
public function chooseDisplay($displays) { | |
if (!is_array($displays)) { | |
return $displays; | |
} | |
$this->initDisplay(); | |
foreach ($displays as $display_id) { | |
if ($this->displayHandlers->get($display_id)->access($this->user)) { | |
return $display_id; | |
} | |
} | |
return 'default'; | |
} | |
/** | |
* Gets the current display plugin. | |
* | |
* @return \Drupal\views\Plugin\views\display\DisplayPluginBase | |
* The current display plugin. | |
*/ | |
public function getDisplay() { | |
if (!isset($this->display_handler)) { | |
$this->initDisplay(); | |
} | |
return $this->display_handler; | |
} | |
/** | |
* Sets the current display. | |
* | |
* @param string $display_id | |
* The ID of the display to mark as current. | |
* | |
* @return bool | |
* TRUE if the display was correctly set, FALSE otherwise. | |
*/ | |
public function setDisplay($display_id = NULL) { | |
// If we have not already initialized the display, do so. | |
if (!isset($this->current_display)) { | |
// This will set the default display and instantiate the default display | |
// plugin. | |
$this->initDisplay(); | |
} | |
// If no display ID is passed, we either have initialized the default or | |
// already have a display set. | |
if (!isset($display_id)) { | |
return TRUE; | |
} | |
$display_id = $this->chooseDisplay($display_id); | |
// Ensure the requested display exists. | |
if (!$this->displayHandlers->has($display_id)) { | |
debug(format_string('setDisplay() called with invalid display ID "@display".', array('@display' => $display_id))); | |
return FALSE; | |
} | |
// Reset if the display has changed. It could be called multiple times for | |
// the same display, especially in the UI. | |
if ($this->current_display != $display_id) { | |
// Set the current display. | |
$this->current_display = $display_id; | |
// Reset the style and row plugins. | |
$this->style_plugin = NULL; | |
$this->plugin_name = NULL; | |
$this->rowPlugin = NULL; | |
} | |
if ($display = $this->displayHandlers->get($display_id)) { | |
// Set a shortcut. | |
$this->display_handler = $display; | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
* Creates a new display and a display handler instance for it. | |
* | |
* @param string $plugin_id | |
* (optional) The plugin type from the Views plugin annotation. Defaults to | |
* 'page'. | |
* @param string $title | |
* (optional) The title of the display. Defaults to NULL. | |
* @param string $id | |
* (optional) The ID to use, e.g., 'default', 'page_1', 'block_2'. Defaults | |
* to NULL. | |
* | |
* @return \Drupal\views\Plugin\views\display\DisplayPluginBase | |
* A new display plugin instance if executable is set, the new display ID | |
* otherwise. | |
*/ | |
public function newDisplay($plugin_id = 'page', $title = NULL, $id = NULL) { | |
$this->initDisplay(); | |
$id = $this->storage->addDisplay($plugin_id, $title, $id); | |
$this->displayHandlers->addInstanceId($id); | |
$display = $this->displayHandlers->get($id); | |
$display->newDisplay(); | |
return $display; | |
} | |
/** | |
* Gets the current style plugin. | |
* | |
* @return \Drupal\views\Plugin\views\style\StylePluginBase | |
* The current style plugin. | |
*/ | |
public function getStyle() { | |
if (!isset($this->style_plugin)) { | |
$this->initStyle(); | |
} | |
return $this->style_plugin; | |
} | |
/** | |
* Finds and initializes the style plugin. | |
* | |
* Note that arguments may have changed which style plugin we use, so | |
* check the view object first, then ask the display handler. | |
* | |
* @return bool | |
* TRUE if the style plugin was or could be initialized, FALSE otherwise. | |
*/ | |
public function initStyle() { | |
if (isset($this->style_plugin)) { | |
return TRUE; | |
} | |
$this->style_plugin = $this->display_handler->getPlugin('style'); | |
if (empty($this->style_plugin)) { | |
return FALSE; | |
} | |
return TRUE; | |
} | |
/** | |
* Acquires and attaches all of the handlers. | |
*/ | |
public function initHandlers() { | |
$this->initDisplay(); | |
if (empty($this->inited)) { | |
foreach ($this::getHandlerTypes() as $key => $info) { | |
$this->_initHandler($key, $info); | |
} | |
$this->inited = TRUE; | |
} | |
} | |
/** | |
* Gets the current pager plugin. | |
* | |
* @return \Drupal\views\Plugin\views\pager\PagerPluginBase | |
* The current pager plugin. | |
*/ | |
public function getPager() { | |
if (!isset($this->pager)) { | |
$this->initPager(); | |
} | |
return $this->pager; | |
} | |
/** | |
* Initializes the pager. | |
* | |
* Like style initialization, pager initialization is held until late to allow | |
* for overrides. | |
*/ | |
public function initPager() { | |
if (!isset($this->pager)) { | |
$this->pager = $this->display_handler->getPlugin('pager'); | |
if ($this->pager->usePager()) { | |
$this->pager->setCurrentPage($this->current_page); | |
} | |
// These overrides may have been set earlier via $view->set_* | |
// functions. | |
if (isset($this->items_per_page)) { | |
$this->pager->setItemsPerPage($this->items_per_page); | |
} | |
if (isset($this->offset)) { | |
$this->pager->setOffset($this->offset); | |
} | |
} | |
} | |
/** | |
* Renders the pager, if necessary. | |
* | |
* @param string[] $exposed_input | |
* The input values from the exposed forms and sorts of the view. | |
* | |
* @return array|string | |
* The render array of the pager if it's set, blank string otherwise. | |
*/ | |
public function renderPager($exposed_input) { | |
if (!empty($this->pager) && $this->pager->usePager()) { | |
return $this->pager->render($exposed_input); | |
} | |
return ''; | |
} | |
/** | |
* Creates a list of base tables to be used by the view. | |
* | |
* This is used primarily for the UI. The display must be already initialized. | |
* | |
* @return array | |
* An array of base tables to be used by the view. | |
*/ | |
public function getBaseTables() { | |
$base_tables = array( | |
$this->storage->get('base_table') => TRUE, | |
'#global' => TRUE, | |
); | |
foreach ($this->display_handler->getHandlers('relationship') as $handler) { | |
$base_tables[$handler->definition['base']] = TRUE; | |
} | |
return $base_tables; | |
} | |
/** | |
* Runs the preQuery() on all active handlers. | |
*/ | |
protected function _preQuery() { | |
foreach ($this::getHandlerTypes() as $key => $info) { | |
$handlers = &$this->$key; | |
$position = 0; | |
foreach ($handlers as $id => $handler) { | |
$handlers[$id]->position = $position; | |
$handlers[$id]->preQuery(); | |
$position++; | |
} | |
} | |
} | |
/** | |
* Runs the postExecute() on all active handlers. | |
*/ | |
protected function _postExecute() { | |
foreach ($this::getHandlerTypes() as $key => $info) { | |
$handlers = &$this->$key; | |
foreach ($handlers as $id => $handler) { | |
$handlers[$id]->postExecute($this->result); | |
} | |
} | |
} | |
/** | |
* Attaches the views handler for the specific type. | |
* | |
* @param string $key | |
* One of 'argument', 'field', 'sort', 'filter', 'relationship'. | |
* @param array $info | |
* An array of views handler types use in the view with additional | |
* information about them. | |
*/ | |
protected function _initHandler($key, $info) { | |
// Load the requested items from the display onto the object. | |
$this->$key = &$this->display_handler->getHandlers($key); | |
// This reference deals with difficult PHP indirection. | |
$handlers = &$this->$key; | |
// Run through and test for accessibility. | |
foreach ($handlers as $id => $handler) { | |
if (!$handler->access($this->user)) { | |
unset($handlers[$id]); | |
} | |
} | |
} | |
/** | |
* Builds all the arguments. | |
* | |
* @return bool | |
* TRUE if the arguments were built successfully, FALSE otherwise. | |
*/ | |
protected function _buildArguments() { | |
// Initially, we want to build sorts and fields. This can change, though, | |
// if we get a summary view. | |
if (empty($this->argument)) { | |
return TRUE; | |
} | |
// build arguments. | |
$position = -1; | |
$substitutions = array(); | |
$status = TRUE; | |
// Get the title. | |
$title = $this->display_handler->getOption('title'); | |
// Iterate through each argument and process. | |
foreach ($this->argument as $id => $arg) { | |
$position++; | |
$argument = $this->argument[$id]; | |
if ($argument->broken()) { | |
continue; | |
} | |
$argument->setRelationship(); | |
$arg = isset($this->args[$position]) ? $this->args[$position] : NULL; | |
$argument->position = $position; | |
if (isset($arg) || $argument->hasDefaultArgument()) { | |
if (!isset($arg)) { | |
$arg = $argument->getDefaultArgument(); | |
// make sure default args get put back. | |
if (isset($arg)) { | |
$this->args[$position] = $arg; | |
} | |
// remember that this argument was computed, not passed on the URL. | |
$argument->is_default = TRUE; | |
} | |
// Set the argument, which will also validate that the argument can be set. | |
if (!$argument->setArgument($arg)) { | |
$status = $argument->validateFail($arg); | |
break; | |
} | |
if ($argument->isException()) { | |
$arg_title = $argument->exceptionTitle(); | |
} | |
else { | |
$arg_title = $argument->getTitle(); | |
$argument->query($this->display_handler->useGroupBy()); | |
} | |
// Add this argument's substitution | |
$substitutions["{{ arguments.$id }}"] = $arg_title; | |
$substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($arg)); | |
// Test to see if we should use this argument's title | |
if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) { | |
$title = $argument->options['title']; | |
} | |
} | |
else { | |
// determine default condition and handle. | |
$status = $argument->defaultAction(); | |
break; | |
} | |
// Be safe with references and loops: | |
unset($argument); | |
} | |
// set the title in the build info. | |
if (!empty($title)) { | |
$this->build_info['title'] = $title; | |
} | |
// Store the arguments for later use. | |
$this->build_info['substitutions'] = $substitutions; | |
return $status; | |
} | |
/** | |
* Gets the current query plugin. | |
* | |
* @return \Drupal\views\Plugin\views\query\QueryPluginBase | |
* The current query plugin. | |
*/ | |
public function getQuery() { | |
if (!isset($this->query)) { | |
$this->initQuery(); | |
} | |
return $this->query; | |
} | |
/** | |
* Initializes the query object for the view. | |
* | |
* @return true | |
* Always returns TRUE. | |
*/ | |
public function initQuery() { | |
if (!empty($this->query)) { | |
$class = get_class($this->query); | |
if ($class && $class != 'stdClass') { | |
// return if query is already initialized. | |
return TRUE; | |
} | |
} | |
// Create and initialize the query object. | |
$views_data = Views::viewsData()->get($this->storage->get('base_table')); | |
$this->storage->set('base_field', !empty($views_data['table']['base']['field']) ? $views_data['table']['base']['field'] : ''); | |
if (!empty($views_data['table']['base']['database'])) { | |
$this->base_database = $views_data['table']['base']['database']; | |
} | |
$this->query = $this->display_handler->getPlugin('query'); | |
return TRUE; | |
} | |
/** | |
* Builds the query for the view. | |
* | |
* @param string $display_id | |
* The display ID of the view. | |
* | |
* @return bool|null | |
* TRUE if the view build process was successful, FALSE if setting the | |
* display fails or NULL if the view has been built already. | |
*/ | |
public function build($display_id = NULL) { | |
if (!empty($this->built)) { | |
return; | |
} | |
if (empty($this->current_display) || $display_id) { | |
if (!$this->setDisplay($display_id)) { | |
return FALSE; | |
} | |
} | |
// Let modules modify the view just prior to building it. | |
$module_handler = \Drupal::moduleHandler(); | |
$module_handler->invokeAll('views_pre_build', array($this)); | |
// Attempt to load from cache. | |
// @todo Load a build_info from cache. | |
$start = microtime(TRUE); | |
// If that fails, let's build! | |
$this->build_info = array( | |
'query' => '', | |
'count_query' => '', | |
'query_args' => array(), | |
); | |
$this->initQuery(); | |
// Call a module hook and see if it wants to present us with a | |
// pre-built query or instruct us not to build the query for | |
// some reason. | |
// @todo: Implement this. Use the same mechanism Panels uses. | |
// Run through our handlers and ensure they have necessary information. | |
$this->initHandlers(); | |
// Let the handlers interact with each other if they really want. | |
$this->_preQuery(); | |
if ($this->display_handler->usesExposed()) { | |
$exposed_form = $this->display_handler->getPlugin('exposed_form'); | |
$this->exposed_widgets = $exposed_form->renderExposedForm(); | |
if (FormState::hasAnyErrors() || !empty($this->build_info['abort'])) { | |
$this->built = TRUE; | |
// Don't execute the query, $form_state, but rendering will still be executed to display the empty text. | |
$this->executed = TRUE; | |
return empty($this->build_info['fail']); | |
} | |
} | |
// Build all the relationships first thing. | |
$this->_build('relationship'); | |
// Set the filtering groups. | |
if (!empty($this->filter)) { | |
$filter_groups = $this->display_handler->getOption('filter_groups'); | |
if ($filter_groups) { | |
$this->query->setGroupOperator($filter_groups['operator']); | |
foreach ($filter_groups['groups'] as $id => $operator) { | |
$this->query->setWhereGroup($operator, $id); | |
} | |
} | |
} | |
// Build all the filters. | |
$this->_build('filter'); | |
$this->build_sort = TRUE; | |
// Arguments can, in fact, cause this whole thing to abort. | |
if (!$this->_buildArguments()) { | |
$this->build_time = microtime(TRUE) - $start; | |
$this->attachDisplays(); | |
return $this->built; | |
} | |
// Initialize the style; arguments may have changed which style we use, | |
// so waiting as long as possible is important. But we need to know | |
// about the style when we go to build fields. | |
if (!$this->initStyle()) { | |
$this->build_info['fail'] = TRUE; | |
return FALSE; | |
} | |
if ($this->style_plugin->usesFields()) { | |
$this->_build('field'); | |
} | |
// Build our sort criteria if we were instructed to do so. | |
if (!empty($this->build_sort)) { | |
// Allow the style handler to deal with sorting. | |
if ($this->style_plugin->buildSort()) { | |
$this->_build('sort'); | |
} | |
// allow the plugin to build second sorts as well. | |
$this->style_plugin->buildSortPost(); | |
} | |
// Allow area handlers to affect the query. | |
$this->_build('header'); | |
$this->_build('footer'); | |
$this->_build('empty'); | |
// Allow display handler to affect the query: | |
$this->display_handler->query($this->display_handler->useGroupBy()); | |
// Allow style handler to affect the query: | |
$this->style_plugin->query($this->display_handler->useGroupBy()); | |
// Allow exposed form to affect the query: | |
if (isset($exposed_form)) { | |
$exposed_form->query(); | |
} | |
if (\Drupal::config('views.settings')->get('sql_signature')) { | |
$this->query->addSignature($this); | |
} | |
// Let modules modify the query just prior to finalizing it. | |
$this->query->alter($this); | |
// Only build the query if we weren't interrupted. | |
if (empty($this->built)) { | |
// Build the necessary info to execute the query. | |
$this->query->build($this); | |
} | |
$this->built = TRUE; | |
$this->build_time = microtime(TRUE) - $start; | |
// Attach displays | |
$this->attachDisplays(); | |
// Let modules modify the view just after building it. | |
$module_handler->invokeAll('views_post_build', array($this)); | |
return TRUE; | |
} | |
/** | |
* Builds an individual set of handlers. | |
* | |
* This is an internal method. | |
* | |
* @todo Some filter needs this function, even it is internal. | |
* | |
* @param string $key | |
* The type of handlers (filter etc.) which should be iterated over to | |
* build the relationship and query information. | |
*/ | |
public function _build($key) { | |
$handlers = &$this->$key; | |
foreach ($handlers as $id => $data) { | |
if (!empty($handlers[$id]) && is_object($handlers[$id])) { | |
$multiple_exposed_input = array(0 => NULL); | |
if ($handlers[$id]->multipleExposedInput()) { | |
$multiple_exposed_input = $handlers[$id]->groupMultipleExposedInput($this->exposed_data); | |
} | |
foreach ($multiple_exposed_input as $group_id) { | |
// Give this handler access to the exposed filter input. | |
if (!empty($this->exposed_data)) { | |
if ($handlers[$id]->isAGroup()) { | |
$converted = $handlers[$id]->convertExposedInput($this->exposed_data, $group_id); | |
$handlers[$id]->storeGroupInput($this->exposed_data, $converted); | |
if (!$converted) { | |
continue; | |
} | |
} | |
$rc = $handlers[$id]->acceptExposedInput($this->exposed_data); | |
$handlers[$id]->storeExposedInput($this->exposed_data, $rc); | |
if (!$rc) { | |
continue; | |
} | |
} | |
$handlers[$id]->setRelationship(); | |
$handlers[$id]->query($this->display_handler->useGroupBy()); | |
} | |
} | |
} | |
} | |
/** | |
* Executes the view's query. | |
* | |
* @param string $display_id | |
* The machine name of the display, which should be executed. | |
* | |
* @return bool | |
* TRUE if the view execution was successful, FALSE otherwise. For example, | |
* an argument could stop the process. | |
*/ | |
public function execute($display_id = NULL) { | |
if (empty($this->built)) { | |
if (!$this->build($display_id)) { | |
return FALSE; | |
} | |
} | |
if (!empty($this->executed)) { | |
return TRUE; | |
} | |
// Don't allow to use deactivated displays, but display them on the live preview. | |
if (!$this->display_handler->isEnabled() && empty($this->live_preview)) { | |
$this->build_info['fail'] = TRUE; | |
return FALSE; | |
} | |
// Let modules modify the view just prior to executing it. | |
$module_handler = \Drupal::moduleHandler(); | |
$module_handler->invokeAll('views_pre_execute', array($this)); | |
// Check for already-cached results. | |
/** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */ | |
if (!empty($this->live_preview)) { | |
$cache = Views::pluginManager('cache')->createInstance('none'); | |
} | |
else { | |
$cache = $this->display_handler->getPlugin('cache'); | |
} | |
if ($cache->cacheGet('results')) { | |
if ($this->pager->usePager()) { | |
$this->pager->total_items = $this->total_rows; | |
$this->pager->updatePageInfo(); | |
} | |
} | |
else { | |
$this->query->execute($this); | |
// Enforce the array key rule as documented in | |
// views_plugin_query::execute(). | |
$this->result = array_values($this->result); | |
$this->_postExecute(); | |
$cache->cacheSet('results'); | |
} | |
// Let modules modify the view just after executing it. | |
$module_handler->invokeAll('views_post_execute', array($this)); | |
$this->executed = TRUE; | |
} | |
/** | |
* Renders this view for a certain display. | |
* | |
* Note: You should better use just the preview function if you want to | |
* render a view. | |
* | |
* @param string $display_id | |
* The machine name of the display, which should be rendered. | |
* | |
* @return array|null | |
* A renderable array containing the view output or NULL if the build | |
* process failed. | |
*/ | |
public function render($display_id = NULL) { | |
$this->execute($display_id); | |
// Check to see if the build failed. | |
if (!empty($this->build_info['fail'])) { | |
return; | |
} | |
if (!empty($this->build_info['denied'])) { | |
return; | |
} | |
$exposed_form = $this->display_handler->getPlugin('exposed_form'); | |
$exposed_form->preRender($this->result); | |
$module_handler = \Drupal::moduleHandler(); | |
// @TODO In the longrun, it would be great to execute a view without | |
// the theme system at all. See https://www.drupal.org/node/2322623. | |
$active_theme = \Drupal::theme()->getActiveTheme(); | |
$themes = array_keys($active_theme->getBaseThemes()); | |
$themes[] = $active_theme->getName(); | |
// Check for already-cached output. | |
/** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */ | |
if (!empty($this->live_preview)) { | |
$cache = Views::pluginManager('cache')->createInstance('none'); | |
} | |
else { | |
$cache = $this->display_handler->getPlugin('cache'); | |
} | |
// Run preRender for the pager as it might change the result. | |
if (!empty($this->pager)) { | |
$this->pager->preRender($this->result); | |
} | |
// Initialize the style plugin. | |
$this->initStyle(); | |
if (!isset($this->response)) { | |
// Set the response so other parts can alter it. | |
$this->response = new Response('', 200); | |
} | |
// Give field handlers the opportunity to perform additional queries | |
// using the entire resultset prior to rendering. | |
if ($this->style_plugin->usesFields()) { | |
foreach ($this->field as $id => $handler) { | |
if (!empty($this->field[$id])) { | |
$this->field[$id]->preRender($this->result); | |
} | |
} | |
} | |
$this->style_plugin->preRender($this->result); | |
// Let each area handler have access to the result set. | |
$areas = array('header', 'footer'); | |
// Only call preRender() on the empty handlers if the result is empty. | |
if (empty($this->result)) { | |
$areas[] = 'empty'; | |
} | |
foreach ($areas as $area) { | |
foreach ($this->{$area} as $handler) { | |
$handler->preRender($this->result); | |
} | |
} | |
// Let modules modify the view just prior to rendering it. | |
$module_handler->invokeAll('views_pre_render', array($this)); | |
// Let the themes play too, because pre render is a very themey thing. | |
foreach ($themes as $theme_name) { | |
$function = $theme_name . '_views_pre_render'; | |
if (function_exists($function)) { | |
$function($this); | |
} | |
} | |
$this->display_handler->output = $this->display_handler->render(); | |
$exposed_form->postRender($this->display_handler->output); | |
$cache->postRender($this->display_handler->output); | |
// Let modules modify the view output after it is rendered. | |
$module_handler->invokeAll('views_post_render', array($this, &$this->display_handler->output, $cache)); | |
// Let the themes play too, because post render is a very themey thing. | |
foreach ($themes as $theme_name) { | |
$function = $theme_name . '_views_post_render'; | |
if (function_exists($function)) { | |
$function($this, $this->display_handler->output, $cache); | |
} | |
} | |
return $this->display_handler->output; | |
} | |
/** | |
* Gets the cache tags associated with the executed view. | |
* | |
* Note: The cache plugin controls the used tags, so you can override it, if | |
* needed. | |
* | |
* @return string[] | |
* An array of cache tags. | |
*/ | |
public function getCacheTags() { | |
$this->initDisplay(); | |
/** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */ | |
$cache = $this->display_handler->getPlugin('cache'); | |
return $cache->getCacheTags(); | |
} | |
/** | |
* Builds the render array outline for the given display. | |
* | |
* This render array has a #pre_render callback which will call | |
* ::executeDisplay in order to actually execute the view and then build the | |
* final render array structure. | |
* | |
* @param string $display_id | |
* The display ID. | |
* @param array $args | |
* An array of arguments passed along to the view. | |
* @param bool $cache | |
* (optional) Should the result be render cached. | |
* | |
* @return array|null | |
* A renderable array with #type 'view' or NULL if the display ID was | |
* invalid. | |
*/ | |
public function buildRenderable($display_id = NULL, $args = array(), $cache = TRUE) { | |
// @todo Extract that into a generic method. | |
if (empty($this->current_display) || $this->current_display != $this->chooseDisplay($display_id)) { | |
if (!$this->setDisplay($display_id)) { | |
return NULL; | |
} | |
} | |
return $this->display_handler->buildRenderable($args, $cache); | |
} | |
/** | |
* Executes the given display, with the given arguments. | |
* | |
* To be called externally by whatever mechanism invokes the view, | |
* such as a page callback, hook_block, etc. | |
* | |
* This function should NOT be used by anything external as this | |
* returns data in the format specified by the display. It can also | |
* have other side effects that are only intended for the 'proper' | |
* use of the display, such as setting page titles. | |
* | |
* If you simply want to view the display, use View::preview() instead. | |
* | |
* @param string $display_id | |
* The display ID of the view to be executed. | |
* @param string[] $args | |
* The arguments to be passed to the view. | |
* | |
* @return array|null | |
* A renderable array containing the view output or NULL if the display ID | |
* of the view to be executed doesn't exist. | |
*/ | |
public function executeDisplay($display_id = NULL, $args = array()) { | |
if (empty($this->current_display) || $this->current_display != $this->chooseDisplay($display_id)) { | |
if (!$this->setDisplay($display_id)) { | |
return NULL; | |
} | |
} | |
$this->preExecute($args); | |
// Execute the view | |
$output = $this->display_handler->execute(); | |
$this->postExecute(); | |
return $output; | |
} | |
/** | |
* Previews the given display, with the given arguments. | |
* | |
* To be called externally, probably by an AJAX handler of some flavor. | |
* Can also be called when views are embedded, as this guarantees | |
* normalized output. | |
* | |
* This function does not do any access checks on the view. It is the | |
* responsibility of the caller to check $view->access() or implement other | |
* access logic. To render the view normally with access checks, use | |
* views_embed_view() instead. | |
* | |
* @return array|null | |
* A renderable array containing the view output or NULL if the display ID | |
* of the view to be executed doesn't exist. | |
*/ | |
public function preview($display_id = NULL, $args = array()) { | |
if (empty($this->current_display) || ((!empty($display_id)) && $this->current_display != $display_id)) { | |
if (!$this->setDisplay($display_id)) { | |
return FALSE; | |
} | |
} | |
$this->preview = TRUE; | |
$this->preExecute($args); | |
// Preview the view. | |
$output = $this->display_handler->preview(); | |
$this->postExecute(); | |
return $output; | |
} | |
/** | |
* Runs attachments and lets the display do what it needs to before running. | |
* | |
* @param array @args | |
* An array of arguments from the URL that can be used by the view. | |
*/ | |
public function preExecute($args = array()) { | |
$this->old_view[] = views_get_current_view(); | |
views_set_current_view($this); | |
$display_id = $this->current_display; | |
// Prepare the view with the information we have, but only if we were | |
// passed arguments, as they may have been set previously. | |
if ($args) { | |
$this->setArguments($args); | |
} | |
// Let modules modify the view just prior to executing it. | |
\Drupal::moduleHandler()->invokeAll('views_pre_view', array($this, $display_id, &$this->args)); | |
// Allow hook_views_pre_view() to set the dom_id, then ensure it is set. | |
$this->dom_id = !empty($this->dom_id) ? $this->dom_id : hash('sha256', $this->storage->id() . REQUEST_TIME . mt_rand()); | |
// Allow the display handler to set up for execution | |
$this->display_handler->preExecute(); | |
} | |
/** | |
* Unsets the current view, mostly. | |
*/ | |
public function postExecute() { | |
// unset current view so we can be properly destructed later on. | |
// Return the previous value in case we're an attachment. | |
if ($this->old_view) { | |
$old_view = array_pop($this->old_view); | |
} | |
views_set_current_view(isset($old_view) ? $old_view : FALSE); | |
} | |
/** | |
* Runs attachment displays for the view. | |
*/ | |
public function attachDisplays() { | |
if (!empty($this->is_attachment)) { | |
return; | |
} | |
if (!$this->display_handler->acceptAttachments()) { | |
return; | |
} | |
$this->is_attachment = TRUE; | |
// Find out which other displays attach to the current one. | |
foreach ($this->display_handler->getAttachedDisplays() as $id) { | |
$display_handler = $this->displayHandlers->get($id); | |
// Only attach enabled attachments. | |
if ($display_handler->isEnabled()) { | |
$cloned_view = Views::executableFactory()->get($this->storage); | |
$display_handler->attachTo($cloned_view, $this->current_display, $this->element); | |
} | |
} | |
$this->is_attachment = FALSE; | |
} | |
/** | |
* Determines if the given user has access to the view. | |
* | |
* Note that this sets the display handler if it hasn't been set. | |
* | |
* @param string $displays | |
* The machine name of the display. | |
* @param \Drupal\Core\Session\AccountInterface $account | |
* The user object. | |
* | |
* @return bool | |
* TRUE if the user has access to the view, FALSE otherwise. | |
*/ | |
public function access($displays = NULL, $account = NULL) { | |
// No one should have access to disabled views. | |
if (!$this->storage->status()) { | |
return FALSE; | |
} | |
if (!isset($this->current_display)) { | |
$this->initDisplay(); | |
} | |
if (!$account) { | |
$account = $this->user; | |
} | |
// We can't use choose_display() here because that function | |
// calls this one. | |
$displays = (array)$displays; | |
foreach ($displays as $display_id) { | |
if ($this->displayHandlers->has($display_id)) { | |
if (($display = $this->displayHandlers->get($display_id)) && $display->access($account)) { | |
return TRUE; | |
} | |
} | |
} | |
return FALSE; | |
} | |
/** | |
* Sets the used response object of the view. | |
* | |
* @param \Symfony\Component\HttpFoundation\Response $response | |
* The response object which should be set. | |
*/ | |
public function setResponse(Response $response) { | |
$this->response = $response; | |
} | |
/** | |
* Gets the response object used by the view. | |
* | |
* @return \Symfony\Component\HttpFoundation\Response | |
* The response object of the view. | |
*/ | |
public function getResponse() { | |
if (!isset($this->response)) { | |
$this->response = new Response(); | |
} | |
return $this->response; | |
} | |
/** | |
* Sets the request object. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* The request object. | |
*/ | |
public function setRequest(Request $request) { | |
$this->request = $request; | |
} | |
/** | |
* Gets the request object. | |
* | |
* @return \Symfony\Component\HttpFoundation\Request | |
* The request object. | |
*/ | |
public function getRequest() { | |
return $this->request; | |
} | |
/** | |
* Gets the view's current title. | |
* | |
* This can change depending upon how it was built. | |
* | |
* @return string|false | |
* The view title, FALSE if the display is not set. | |
*/ | |
public function getTitle() { | |
if (empty($this->display_handler)) { | |
if (!$this->setDisplay('default')) { | |
return FALSE; | |
} | |
} | |
// During building, we might find a title override. If so, use it. | |
if (!empty($this->build_info['title'])) { | |
$title = $this->build_info['title']; | |
} | |
else { | |
$title = $this->display_handler->getOption('title'); | |
} | |
// Allow substitutions from the first row. | |
if ($this->initStyle()) { | |
$title = $this->style_plugin->tokenizeValue($title, 0); | |
} | |
return $title; | |
} | |
/** | |
* Overrides the view's current title. | |
* | |
* The tokens in the title get's replaced before rendering. | |
* | |
* @return true | |
* Always returns TRUE. | |
*/ | |
public function setTitle($title) { | |
$this->build_info['title'] = $title; | |
return TRUE; | |
} | |
/** | |
* Forces the view to build a title. | |
*/ | |
public function buildTitle() { | |
$this->initDisplay(); | |
if (empty($this->built)) { | |
$this->initQuery(); | |
} | |
$this->initHandlers(); | |
$this->_buildArguments(); | |
} | |
/** | |
* Determines whether you can link to the view or a particular display. | |
* | |
* Some displays (e.g. block displays) do not have their own route, but may | |
* optionally provide a link to another display that does have a route. | |
* | |
* @param array $args | |
* (optional) The arguments. | |
* @param string $display_id | |
* (optional) The display ID. The current display will be used by default. | |
* | |
* @return bool | |
* TRUE if the current display has a valid route available, FALSE otherwise. | |
*/ | |
public function hasUrl($args = NULL, $display_id = NULL) { | |
if (!empty($this->override_url)) { | |
return TRUE; | |
} | |
// If the display has a valid route available (either its own or for a | |
// linked display), then we can provide a URL for it. | |
$display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay(); | |
if (!$display_handler instanceof DisplayRouterInterface) { | |
return FALSE; | |
} | |
// Look up the route name to make sure it exists. The name may exist, but | |
// not be available yet in some instances when editing a view and doing | |
// a live preview. | |
$provider = \Drupal::service('router.route_provider'); | |
try { | |
$provider->getRouteByName($display_handler->getRouteName()); | |
} | |
catch (RouteNotFoundException $e) { | |
return FALSE; | |
} | |
return TRUE; | |
} | |
/** | |
* Gets the URL for the current view. | |
* | |
* This URL will be adjusted for arguments. | |
* | |
* @param array $args | |
* (optional) Passed in arguments. | |
* @param string $display_id | |
* (optional) Specify the display ID to link to, fallback to the current ID. | |
* | |
* @return \Drupal\Core\Url | |
* The URL of the current view. | |
* | |
* @throws \InvalidArgumentException | |
* Thrown when the current view doesn't have a route available. | |
*/ | |
public function getUrl($args = NULL, $display_id = NULL) { | |
if (!empty($this->override_url)) { | |
return $this->override_url; | |
} | |
if (!isset($path)) { | |
$path = $this->getPath(); | |
} | |
$display_handler = $this->displayHandlers->get($display_id ?: $this->current_display)->getRoutedDisplay(); | |
if (!$display_handler instanceof DisplayRouterInterface) { | |
throw new \InvalidArgumentException('You cannot create a URL to a display without routes.'); | |
} | |
if (!isset($args)) { | |
$args = $this->args; | |
// Exclude arguments that were computed, not passed on the URL. | |
$position = 0; | |
if (!empty($this->argument)) { | |
foreach ($this->argument as $argument) { | |
if (!empty($argument->is_default) && !empty($argument->options['default_argument_skip_url'])) { | |
unset($args[$position]); | |
} | |
$position++; | |
} | |
} | |
} | |
// Don't bother working if there's nothing to do: | |
if (empty($path) || (empty($args) && strpos($path, '%') === FALSE)) { | |
return $display_handler->getUrlInfo(); | |
} | |
$argument_keys = isset($this->argument) ? array_keys($this->argument) : array(); | |
$id = current($argument_keys); | |
/** @var \Drupal\Core\Url $url */ | |
$url = $display_handler->getUrlInfo(); | |
$route = $this->routeProvider->getRouteByName($url->getRouteName()); | |
$variables = $route->compile()->getVariables(); | |
$parameters = $url->getRouteParameters(); | |
foreach ($variables as $variable_name) { | |
if (empty($args)) { | |
// Try to never put % in a URL; use the wildcard instead. | |
if ($id && !empty($this->argument[$id]->options['exception']['value'])) { | |
$parameters[$variable_name] = $this->argument[$id]->options['exception']['value']; | |
} | |
else { | |
// Provide some fallback in case no exception value could be found. | |
$parameters[$variable_name] = '*'; | |
} | |
} | |
else { | |
$parameters[$variable_name] = array_shift($args); | |
} | |
if ($id) { | |
$id = next($argument_keys); | |
} | |
} | |
$url->setRouteParameters($parameters); | |
return $url; | |
} | |
/** | |
* Gets the Url object associated with the display handler. | |
* | |
* @param string $display_id | |
* (optional) The display ID (used only to detail an exception). | |
* | |
* @return \Drupal\Core\Url | |
* The display handlers URL object. | |
* | |
* @throws \InvalidArgumentException | |
* Thrown when the display plugin does not have a URL to return. | |
*/ | |
public function getUrlInfo($display_id = '') { | |
$this->initDisplay(); | |
if (!$this->display_handler instanceof DisplayRouterInterface) { | |
throw new \InvalidArgumentException("You cannot generate a URL for the display '$display_id'"); | |
} | |
return $this->display_handler->getUrlInfo(); | |
} | |
/** | |
* Gets the base path used for this view. | |
* | |
* @return string|false | |
* The base path used for the view or FALSE if setting the display fails. | |
*/ | |
public function getPath() { | |
if (!empty($this->override_path)) { | |
return $this->override_path; | |
} | |
if (empty($this->display_handler)) { | |
if (!$this->setDisplay('default')) { | |
return FALSE; | |
} | |
} | |
return $this->display_handler->getPath(); | |
} | |
/** | |
* Gets the current user. | |
* | |
* Views plugins can receive the current user in order to not need dependency | |
* injection. | |
* | |
* @return \Drupal\Core\Session\AccountInterface | |
* The current user. | |
*/ | |
public function getUser() { | |
return $this->user; | |
} | |
/** | |
* Creates a duplicate ViewExecutable object. | |
* | |
* Makes a copy of this view that has been sanitized of handlers, any runtime | |
* data, ID, and UUID. | |
*/ | |
public function createDuplicate() { | |
return $this->storage->createDuplicate()->getExecutable(); | |
} | |
/** | |
* Unsets references so that a $view object may be properly garbage collected. | |
*/ | |
public function destroy() { | |
foreach ($this::getHandlerTypes() as $type => $info) { | |
if (isset($this->$type)) { | |
foreach ($this->{$type} as $handler) { | |
$handler->destroy(); | |
} | |
} | |
} | |
if (isset($this->style_plugin)) { | |
$this->style_plugin->destroy(); | |
} | |
$reflection = new \ReflectionClass($this); | |
$defaults = $reflection->getDefaultProperties(); | |
// The external dependencies should not be reset. This is not generated by | |
// the execution of a view. | |
unset($defaults['storage'], $defaults['user'], $defaults['request'], $defaults['routeProvider']); | |
foreach ($defaults as $property => $default) { | |
$this->{$property} = $default; | |
} | |
} | |
/** | |
* Makes sure the view is completely valid. | |
* | |
* @return array | |
* An array of error strings. This will be empty if there are no validation | |
* errors. | |
*/ | |
public function validate() { | |
$errors = array(); | |
$this->initDisplay(); | |
$current_display = $this->current_display; | |
foreach ($this->displayHandlers as $id => $display) { | |
if (!empty($display)) { | |
if (!empty($display->display['deleted'])) { | |
continue; | |
} | |
$result = $this->displayHandlers->get($id)->validate(); | |
if (!empty($result) && is_array($result)) { | |
$errors[$id] = $result; | |
} | |
} | |
} | |
$this->setDisplay($current_display); | |
return $errors; | |
} | |
/** | |
* Provides a list of views handler types used in a view. | |
* | |
* This also provides some information about the views handler types. | |
* | |
* @return array | |
* An array of associative arrays containing: | |
* - title: The title of the handler type. | |
* - ltitle: The lowercase title of the handler type. | |
* - stitle: A singular title of the handler type. | |
* - lstitle: A singular lowercase title of the handler type. | |
* - plural: Plural version of the handler type. | |
* - (optional) type: The actual internal used handler type. This key is | |
* just used for header,footer,empty to link to the internal type: area. | |
*/ | |
public static function getHandlerTypes() { | |
return Views::getHandlerTypes(); | |
} | |
/** | |
* Returns the valid types of plugins that can be used. | |
* | |
* @return array | |
* An array of plugin type strings. | |
*/ | |
public static function getPluginTypes($type = NULL) { | |
return Views::getPluginTypes($type); | |
} | |
/** | |
* Adds an instance of a handler to the view. | |
* | |
* Items may be fields, filters, sort criteria, or arguments. | |
* | |
* @param string $display_id | |
* The machine name of the display. | |
* @param string $type | |
* The type of handler being added. | |
* @param string $table | |
* The name of the table this handler is from. | |
* @param string $field | |
* The name of the field this handler is from. | |
* @param array $options | |
* (optional) Extra options for this instance. Defaults to an empty array. | |
* @param string $id | |
* (optional) A unique ID for this handler instance. Defaults to NULL, in | |
* which case one will be generated. | |
* | |
* @return string | |
* The unique ID for this handler instance. | |
*/ | |
public function addHandler($display_id, $type, $table, $field, $options = array(), $id = NULL) { | |
$types = $this::getHandlerTypes(); | |
$this->setDisplay($display_id); | |
$data = $this->viewsData->get($table); | |
$fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']); | |
if (empty($id)) { | |
$id = $this->generateHandlerId($field, $fields); | |
} | |
// If the desired type is not found, use the original value directly. | |
$handler_type = !empty($types[$type]['type']) ? $types[$type]['type'] : $type; | |
$fields[$id] = array( | |
'id' => $id, | |
'table' => $table, | |
'field' => $field, | |
) + $options; | |
if (isset($data['table']['entity type'])) { | |
$fields[$id]['entity_type'] = $data['table']['entity type']; | |
} | |
if (isset($data[$field]['entity field'])) { | |
$fields[$id]['entity_field'] = $data[$field]['entity field']; | |
} | |
// Load the plugin ID if available. | |
if (isset($data[$field][$handler_type]['id'])) { | |
$fields[$id]['plugin_id'] = $data[$field][$handler_type]['id']; | |
} | |
$this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields); | |
return $id; | |
} | |
/** | |
* Generates a unique ID for an handler instance. | |
* | |
* These handler instances are typically fields, filters, sort criteria, or | |
* arguments. | |
* | |
* @param string $requested_id | |
* The requested ID for the handler instance. | |
* @param array $existing_items | |
* An array of existing handler instances, keyed by their IDs. | |
* | |
* @return string | |
* A unique ID. This will be equal to $requested_id if no handler instance | |
* with that ID already exists. Otherwise, it will be appended with an | |
* integer to make it unique, e.g., "{$requested_id}_1", | |
* "{$requested_id}_2", etc. | |
*/ | |
public static function generateHandlerId($requested_id, $existing_items) { | |
$count = 0; | |
$id = $requested_id; | |
while (!empty($existing_items[$id])) { | |
$id = $requested_id . '_' . ++$count; | |
} | |
return $id; | |
} | |
/** | |
* Gets an array of handler instances for the current display. | |
* | |
* @param string $type | |
* The type of handlers to retrieve. | |
* @param string $display_id | |
* (optional) A specific display machine name to use. If NULL, the current | |
* display will be used. | |
* | |
* @return array | |
* An array of handler instances of a given type for this display. | |
*/ | |
public function getHandlers($type, $display_id = NULL) { | |
$old_display_id = !empty($this->current_display) ? $this->current_display : 'default'; | |
$this->setDisplay($display_id); | |
if (!isset($display_id)) { | |
$display_id = $this->current_display; | |
} | |
// Get info about the types so we can get the right data. | |
$types = static::getHandlerTypes(); | |
$handlers = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']); | |
// Restore initial display id (if any) or set to 'default'. | |
if ($display_id != $old_display_id) { | |
$this->setDisplay($old_display_id); | |
} | |
return $handlers; | |
} | |
/** | |
* Gets the configuration of a handler instance on a given display. | |
* | |
* @param string $display_id | |
* The machine name of the display. | |
* @param string $type | |
* The type of handler to retrieve. | |
* @param string $id | |
* The ID of the handler to retrieve. | |
* | |
* @return array|null | |
* Either the handler instance's configuration, or NULL if the handler is | |
* not used on the display. | |
*/ | |
public function getHandler($display_id, $type, $id) { | |
// Get info about the types so we can get the right data. | |
$types = static::getHandlerTypes(); | |
// Initialize the display | |
$this->setDisplay($display_id); | |
// Get the existing configuration | |
$fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']); | |
return isset($fields[$id]) ? $fields[$id] : NULL; | |
} | |
/** | |
* Sets the configuration of a handler instance on a given display. | |
* | |
* @param string $display_id | |
* The machine name of the display. | |
* @param string $type | |
* The type of handler being set. | |
* @param string $id | |
* The ID of the handler being set. | |
* @param array|null $item | |
* An array of configuration for a handler, or NULL to remove this instance. | |
* | |
* @see set_item_option() | |
*/ | |
public function setHandler($display_id, $type, $id, $item) { | |
// Get info about the types so we can get the right data. | |
$types = static::getHandlerTypes(); | |
// Initialize the display. | |
$this->setDisplay($display_id); | |
// Get the existing configuration. | |
$fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']); | |
if (isset($item)) { | |
$fields[$id] = $item; | |
} | |
// Store. | |
$this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields); | |
} | |
/** | |
* Removes configuration for a handler instance on a given display. | |
* | |
* @param string $display_id | |
* The machine name of the display. | |
* @param string $type | |
* The type of handler being removed. | |
* @param string $id | |
* The ID of the handler being removed. | |
*/ | |
public function removeHandler($display_id, $type, $id) { | |
// Get info about the types so we can get the right data. | |
$types = static::getHandlerTypes(); | |
// Initialize the display. | |
$this->setDisplay($display_id); | |
// Get the existing configuration. | |
$fields = $this->displayHandlers->get($display_id)->getOption($types[$type]['plural']); | |
// Unset the item. | |
unset($fields[$id]); | |
// Store. | |
$this->displayHandlers->get($display_id)->setOption($types[$type]['plural'], $fields); | |
} | |
/** | |
* Sets an option on a handler instance. | |
* | |
* Use this only if you have just 1 or 2 options to set; if you have many, | |
* consider getting the handler instance, adding the options and using | |
* set_item() directly. | |
* | |
* @param string $display_id | |
* The machine name of the display. | |
* @param string $type | |
* The type of handler being set. | |
* @param string $id | |
* The ID of the handler being set. | |
* @param string $option | |
* The configuration key for the value being set. | |
* @param mixed $value | |
* The value being set. | |
* | |
* @see set_item() | |
*/ | |
public function setHandlerOption($display_id, $type, $id, $option, $value) { | |
$item = $this->getHandler($display_id, $type, $id); | |
$item[$option] = $value; | |
$this->setHandler($display_id, $type, $id, $item); | |
} | |
/** | |
* Enables admin links on the rendered view. | |
* | |
* @param bool $show_admin_links | |
* TRUE if the admin links should be shown. | |
*/ | |
public function setShowAdminLinks($show_admin_links) { | |
$this->showAdminLinks = (bool) $show_admin_links; | |
} | |
/** | |
* Returns whether admin links should be rendered on the view. | |
* | |
* @return bool | |
* TRUE if admin links should be rendered, else FALSE. | |
*/ | |
public function getShowAdminLinks() { | |
if (!isset($this->showAdminLinks)) { | |
return $this->getDisplay()->getOption('show_admin_links'); | |
} | |
return $this->showAdminLinks; | |
} | |
/** | |
* Merges all plugin default values for each display. | |
*/ | |
public function mergeDefaults() { | |
$this->initDisplay(); | |
// Initialize displays and merge all plugin defaults. | |
foreach ($this->displayHandlers as $display) { | |
$display->mergeDefaults(); | |
} | |
} | |
/** | |
* Provides a full array of possible theme functions to try for a given hook. | |
* | |
* @param string $hook | |
* The hook to use. This is the base theme/template name. | |
* | |
* @return array | |
* An array of theme hook suggestions. | |
*/ | |
public function buildThemeFunctions($hook) { | |
$themes = array(); | |
$display = isset($this->display_handler) ? $this->display_handler->display : NULL; | |
$id = $this->storage->id(); | |
if ($display) { | |
$themes[] = $hook . '__' . $id . '__' . $display['id']; | |
$themes[] = $hook . '__' . $display['id']; | |
// Add theme suggestions for each single tag. | |
foreach (Tags::explode($this->storage->get('tag')) as $tag) { | |
$themes[] = $hook . '__' . preg_replace('/[^a-z0-9]/', '_', strtolower($tag)); | |
} | |
if ($display['id'] != $display['display_plugin']) { | |
$themes[] = $hook . '__' . $id . '__' . $display['display_plugin']; | |
$themes[] = $hook . '__' . $display['display_plugin']; | |
} | |
} | |
$themes[] = $hook . '__' . $id; | |
$themes[] = $hook; | |
return $themes; | |
} | |
/** | |
* Determines if this view has form elements. | |
* | |
* @return bool | |
* TRUE if this view contains handlers with views form implementations, | |
* FALSE otherwise. | |
*/ | |
public function hasFormElements() { | |
foreach ($this->field as $field) { | |
if (property_exists($field, 'views_form_callback') || method_exists($field, 'viewsForm')) { | |
return TRUE; | |
} | |
} | |
$area_handlers = array_merge(array_values($this->header), array_values($this->footer)); | |
$empty = empty($this->result); | |
foreach ($area_handlers as $area) { | |
if (method_exists($area, 'viewsForm') && !$area->viewsFormEmpty($empty)) { | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
/** | |
* Gets dependencies for the view. | |
* | |
* @see \Drupal\views\Entity\View::calculateDependencies() | |
* @see \Drupal\views\Entity\View::getDependencies() | |
* | |
* @return array | |
* An array of dependencies grouped by type (module, theme, entity). | |
*/ | |
public function getDependencies() { | |
return $this->storage->calculateDependencies()->getDependencies(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function serialize() { | |
return serialize([ | |
// Only serialize the storage entity ID. | |
$this->storage->id(), | |
$this->current_display, | |
$this->args, | |
$this->current_page, | |
$this->exposed_input, | |
$this->exposed_raw_input, | |
$this->exposed_data, | |
$this->dom_id, | |
$this->executed, | |
]); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function unserialize($serialized) { | |
list($storage, $current_display, $args, $current_page, $exposed_input, $exposed_raw_input, $exposed_data, $dom_id, $executed) = unserialize($serialized); | |
$this->setRequest(\Drupal::request()); | |
$this->user = \Drupal::currentUser(); | |
$this->storage = \Drupal::entityManager()->getStorage('view')->load($storage); | |
$this->setDisplay($current_display); | |
$this->setArguments($args); | |
$this->setCurrentPage($current_page); | |
$this->setExposedInput($exposed_input); | |
$this->exposed_data = $exposed_data; | |
$this->exposed_raw_input = $exposed_raw_input; | |
$this->dom_id = $dom_id; | |
$this->initHandlers(); | |
// If the display was previously executed, execute it now. | |
if ($executed) { | |
$this->execute($this->current_display); | |
} | |
} | |
} |