1<?php
2
3namespace dokuwiki\plugin\struct\meta;
4
5/**
6 * Class QueryWhere
7 * @package dokuwiki\plugin\struct\meta
8 */
9class QueryBuilderWhere
10{
11    /** @var  QueryBuilderWhere[]|string */
12    protected $statement;
13    /** @var string */
14    protected $type = 'AND';
15    /** @var QueryBuilder */
16    protected $QB;
17
18    /**
19     * Create a new WHERE clause
20     *
21     * @param QueryBuilder $QB The QueryBuilder to which this where-clause belongs
22     * @param string $type The type of the statement, either 'AND' or 'OR'
23     * @param null|string $statement The statement or null if this should hold sub statments
24     */
25    public function __construct(QueryBuilder $QB, $type = 'AND', $statement = null)
26    {
27        $this->QB = $QB;
28        $this->type = $type;
29        if ($statement === null) {
30            $this->statement = [];
31        } else {
32            $this->statement = $statement;
33        }
34    }
35
36    /**
37     * Adds another AND clause
38     *
39     * @param string $statement
40     * @return $this
41     */
42    public function whereAnd($statement)
43    {
44        return $this->where('AND', $statement);
45    }
46
47    /**
48     * Adds another OR clause
49     *
50     * @param $statement
51     * @return $this
52     */
53    public function whereOr($statement)
54    {
55        return $this->where('OR', $statement);
56    }
57
58    /**
59     * Add a new AND sub clause on which more statements can be added
60     *
61     * @return QueryBuilderWhere
62     */
63    public function whereSubAnd()
64    {
65        return $this->where('AND', null);
66    }
67
68    /**
69     * Add a new OR sub clause on which more statements can be added
70     *
71     * @return QueryBuilderWhere
72     */
73    public function whereSubOr()
74    {
75        return $this->where('OR', null);
76    }
77
78    /**
79     * Adds another statement to this sub clause
80     *
81     * @param string $op either AND or OR
82     * @param null|string $statement null creates a new sub clause
83     * @return $this|QueryBuilderWhere
84     * @throws StructException when this is not a sub clause
85     */
86    public function where($op = 'AND', $statement = null)
87    {
88        if (!is_array($this->statement)) {
89            throw new StructException('This WHERE is not a sub clause and can not have additional clauses');
90        }
91        if ($op != 'AND' && $op != 'OR') {
92            throw new StructException('Bad logical operator');
93        }
94        $where = new QueryBuilderWhere($this->QB, $op, $statement);
95        $this->statement[] = $where;
96
97        if ($statement) {
98            return $this;
99        } else {
100            return $where;
101        }
102    }
103
104    /**
105     * @return QueryBuilder
106     */
107    public function getQB()
108    {
109        return $this->QB;
110    }
111
112    /**
113     * @param bool $first is this the first where statement? Then the type is ignored
114     * @return string
115     */
116    public function toSQL($first = true)
117    {
118        if (!$this->statement) return '';
119
120        $sql = ' ';
121        if (!$first) $sql .= $this->type . ' ';
122
123        if (is_array($this->statement)) {
124            $first = true;
125            $sql .= '(';
126            foreach ($this->statement as $where) {
127                $sql .= $where->toSQL($first);
128                $first = false;
129            }
130            $sql .= ' )';
131        } else {
132            $sql .= $this->statement;
133        }
134
135        return $sql;
136    }
137}
138