1<?php
2
3namespace Drupal\book;
4
5use Drupal\Core\Database\Connection;
6
7/**
8 * Defines a storage class for books outline.
9 */
10class BookOutlineStorage implements BookOutlineStorageInterface {
11
12  /**
13   * Database Service Object.
14   *
15   * @var \Drupal\Core\Database\Connection
16   */
17  protected $connection;
18
19  /**
20   * Constructs a BookOutlineStorage object.
21   */
22  public function __construct(Connection $connection) {
23    $this->connection = $connection;
24  }
25
26  /**
27   * {@inheritdoc}
28   */
29  public function getBooks() {
30    return $this->connection->query("SELECT DISTINCT([bid]) FROM {book}")->fetchCol();
31  }
32
33  /**
34   * {@inheritdoc}
35   */
36  public function hasBooks() {
37    return (bool) $this->connection
38      ->query('SELECT count([bid]) FROM {book}')
39      ->fetchField();
40  }
41
42  /**
43   * {@inheritdoc}
44   */
45  public function loadMultiple($nids, $access = TRUE) {
46    $query = $this->connection->select('book', 'b', ['fetch' => \PDO::FETCH_ASSOC]);
47    $query->fields('b');
48    $query->condition('b.nid', $nids, 'IN');
49
50    if ($access) {
51      $query->addTag('node_access');
52      $query->addMetaData('base_table', 'book');
53    }
54
55    return $query->execute();
56  }
57
58  /**
59   * {@inheritdoc}
60   */
61  public function getChildRelativeDepth($book_link, $max_depth) {
62    $query = $this->connection->select('book');
63    $query->addField('book', 'depth');
64    $query->condition('bid', $book_link['bid']);
65    $query->orderBy('depth', 'DESC');
66    $query->range(0, 1);
67
68    $i = 1;
69    $p = 'p1';
70    while ($i <= $max_depth && $book_link[$p]) {
71      $query->condition($p, $book_link[$p]);
72      $p = 'p' . ++$i;
73    }
74
75    return $query->execute()->fetchField();
76  }
77
78  /**
79   * {@inheritdoc}
80   */
81  public function delete($nid) {
82    return $this->connection->delete('book')
83      ->condition('nid', $nid)
84      ->execute();
85  }
86
87  /**
88   * {@inheritdoc}
89   */
90  public function loadBookChildren($pid) {
91    return $this->connection
92      ->query("SELECT * FROM {book} WHERE [pid] = :pid", [':pid' => $pid])
93      ->fetchAllAssoc('nid', \PDO::FETCH_ASSOC);
94  }
95
96  /**
97   * {@inheritdoc}
98   */
99  public function getBookMenuTree($bid, $parameters, $min_depth, $max_depth) {
100    $query = $this->connection->select('book');
101    $query->fields('book');
102    for ($i = 1; $i <= $max_depth; $i++) {
103      $query->orderBy('p' . $i, 'ASC');
104    }
105    $query->condition('bid', $bid);
106    if (!empty($parameters['expanded'])) {
107      $query->condition('pid', $parameters['expanded'], 'IN');
108    }
109    if ($min_depth != 1) {
110      $query->condition('depth', $min_depth, '>=');
111    }
112    if (isset($parameters['max_depth'])) {
113      $query->condition('depth', $parameters['max_depth'], '<=');
114    }
115    // Add custom query conditions, if any were passed.
116    if (isset($parameters['conditions'])) {
117      foreach ($parameters['conditions'] as $column => $value) {
118        $query->condition($column, $value);
119      }
120    }
121
122    return $query->execute();
123  }
124
125  /**
126   * {@inheritdoc}
127   */
128  public function insert($link, $parents) {
129    return $this->connection
130      ->insert('book')
131      ->fields([
132        'nid' => $link['nid'],
133        'bid' => $link['bid'],
134        'pid' => $link['pid'],
135        'weight' => $link['weight'],
136        ] + $parents
137      )
138      ->execute();
139  }
140
141  /**
142   * {@inheritdoc}
143   */
144  public function update($nid, $fields) {
145    return $this->connection
146      ->update('book')
147      ->fields($fields)
148      ->condition('nid', $nid)
149      ->execute();
150  }
151
152  /**
153   * {@inheritdoc}
154   */
155  public function updateMovedChildren($bid, $original, $expressions, $shift) {
156    $query = $this->connection->update('book');
157    $query->fields(['bid' => $bid]);
158
159    foreach ($expressions as $expression) {
160      $query->expression($expression[0], $expression[1], $expression[2]);
161    }
162
163    $query->expression('depth', '[depth] + :depth', [':depth' => $shift]);
164    $query->condition('bid', $original['bid']);
165    $p = 'p1';
166    for ($i = 1; !empty($original[$p]); $p = 'p' . ++$i) {
167      $query->condition($p, $original[$p]);
168    }
169
170    return $query->execute();
171  }
172
173  /**
174   * {@inheritdoc}
175   */
176  public function countOriginalLinkChildren($original) {
177    return $this->connection->select('book', 'b')
178      ->condition('bid', $original['bid'])
179      ->condition('pid', $original['pid'])
180      ->condition('nid', $original['nid'], '<>')
181      ->countQuery()
182      ->execute()->fetchField();
183  }
184
185  /**
186   * {@inheritdoc}
187   */
188  public function getBookSubtree($link, $max_depth) {
189    $query = $this->connection->select('book', 'b', ['fetch' => \PDO::FETCH_ASSOC]);
190    $query->fields('b');
191    $query->condition('b.bid', $link['bid']);
192
193    for ($i = 1; $i <= $max_depth && $link["p$i"]; ++$i) {
194      $query->condition("p$i", $link["p$i"]);
195    }
196    for ($i = 1; $i <= $max_depth; ++$i) {
197      $query->orderBy("p$i");
198    }
199    return $query->execute();
200  }
201
202}
203