3 namespace Drupal\Core\Database\Query;
5 use Drupal\Core\Database\Connection;
8 * Query extender for pager queries.
10 * This is the "default" pager mechanism. It creates a paged query with a fixed
11 * number of entries per page.
13 * When adding this extender along with other extenders, be sure to add
14 * PagerSelectExtender last, so that its range and count are based on the full
17 class PagerSelectExtender extends SelectExtender {
20 * The highest element we've autogenerated so far.
24 public static $maxElement = 0;
27 * The number of elements per page to allow.
31 protected $limit = 10;
34 * The unique ID of this pager on this page.
38 protected $element = NULL;
41 * The count query that will be used for this pager.
43 * @var \Drupal\Core\Database\Query\SelectInterface
45 protected $customCountQuery = FALSE;
47 public function __construct(SelectInterface $query, Connection $connection) {
48 parent::__construct($query, $connection);
50 // Add pager tag. Do this here to ensure that it is always added before
51 // preExecute() is called.
52 $this->addTag('pager');
56 * Override the execute method.
58 * Before we run the query, we need to add pager-based range() instructions
61 public function execute() {
62 // By calling preExecute() here, we force it to preprocess the extender
63 // object rather than just the base query object. That means
64 // hook_query_alter() gets access to the extended object.
65 if (!$this->preExecute($this)) {
69 // A NULL limit is the "kill switch" for pager queries.
70 if (empty($this->limit)) {
73 $this->ensureElement();
75 $total_items = $this->getCountQuery()->execute()->fetchField();
76 $current_page = pager_default_initialize($total_items, $this->limit, $this->element);
77 $this->range($current_page * $this->limit, $this->limit);
79 // Now that we've added our pager-based range instructions, run the query normally.
80 return $this->query->execute();
84 * Ensure that there is an element associated with this query.
85 * If an element was not specified previously, then the value of the
86 * $maxElement counter is taken, after which the counter is incremented.
88 * After running this method, access $this->element to get the element for this
91 protected function ensureElement() {
92 if (!isset($this->element)) {
93 $this->element = self::$maxElement++;
98 * Specify the count query object to use for this pager.
100 * You will rarely need to specify a count query directly. If not specified,
101 * one is generated off of the pager query itself.
103 * @param \Drupal\Core\Database\Query\SelectInterface $query
104 * The count query object. It must return a single row with a single column,
105 * which is the total number of records.
107 public function setCountQuery(SelectInterface $query) {
108 $this->customCountQuery = $query;
112 * Retrieve the count query for this pager.
114 * The count query may be specified manually or, by default, taken from the
115 * query we are extending.
117 * @return \Drupal\Core\Database\Query\SelectInterface
118 * A count query object.
120 public function getCountQuery() {
121 if ($this->customCountQuery) {
122 return $this->customCountQuery;
125 return $this->query->countQuery();
130 * Specify the maximum number of elements per page for this query.
132 * The default if not specified is 10 items per page.
134 * @param int|false $limit
135 * An integer specifying the number of elements per page. If passed a false
136 * value (FALSE, 0, NULL), the pager is disabled.
138 public function limit($limit = 10) {
139 $this->limit = $limit;
144 * Specify the element ID for this pager query.
146 * The element is used to differentiate different pager queries on the same
147 * page so that they may be operated independently. If you do not specify an
148 * element, every pager query on the page will get a unique element. If for
149 * whatever reason you want to explicitly define an element for a given query,
150 * you may do so here.
152 * Setting the element here also increments the static $maxElement counter,
153 * which is used for determining the $element when there's none specified.
155 * Note that no collision detection is done when setting an element ID
156 * explicitly, so it is possible for two pagers to end up using the same ID
157 * if both are set explicitly.
160 * Element ID that is used to differentiate different pager queries.
162 public function element($element) {
163 $this->element = $element;
164 if ($element >= self::$maxElement) {
165 self::$maxElement = $element + 1;