Completed
Pull Request — master (#186)
by Vladimir
06:39 queued 03:08
created

QueryBuilderFlex::except()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
use Pixie\QueryBuilder\QueryBuilderHandler;
4
5
/**
6
 * @since 0.10.3
7
 */
8
class QueryBuilderFlex extends QueryBuilderHandler
9
{
10
    /** @var Model|string The FQN of the model object this QueryBuilder instance is for */
11
    private $modelType = null;
12
13
    /** @var int The amount of results per page with regards to result pagination */
14
    private $resultsPerPage;
15
16
    //
17
    // Factories
18
    //
19
20
    /**
21
     * Create a QueryBuilder instance for a specific table.
22
     *
23
     * @param  string $tableName
24
     *
25
     * @throws Exception If there is no database connection configured.
26
     *
27
     * @return QueryBuilderFlex
28
     */
29 View Code Duplication
    public static function createForTable($tableName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
30
    {
31
        Database::getInstance();
32
33
        $connection = Service::getQueryBuilderConnection();
34
        $qbBase = new QueryBuilderFlex($connection);
35
36
        $queryBuilder = $qbBase->table($tableName);
37
38
        return $queryBuilder;
39
    }
40
41
    /**
42
     * Creeate a QueryBuilder instance to work with a Model.
43
     *
44
     * @param  string $modelType The FQN for the model that
45
     *
46
     * @throws Exception If there is no database connection configured.
47
     *
48
     * @return QueryBuilderFlex
49
     */
50 View Code Duplication
    public static function createForModel($modelType)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
51
    {
52
        Database::getInstance();
53
54
        $connection = Service::getQueryBuilderConnection();
55
        $qbBase = new QueryBuilderFlex($connection);
56
57
        $queryBuilder = $qbBase->table(constant("$modelType::TABLE"));
58
        $queryBuilder->setModelType($modelType);
59
60
        return $queryBuilder;
61
    }
62
63
    //
64
    // Overridden QueryBuilder Functions
65
    //
66
67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function limit($limit)
71
    {
72
        $this->resultsPerPage = $limit;
73
74
        return parent::limit($limit);
75
    }
76
77
    //
78
    // QueryBuilderFlex unique functions
79
    //
80
81
    /**
82
     * Request that only non-deleted Models should be returned.
83
     *
84
     * @return static
85
     */
86
    public function active()
87
    {
88
        $type = $this->modelType;
89
        $column = $type::DELETED_COLUMN;
90
91
        if ($column === null) {
92
            @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
93
                'The use of the status column is deprecated. Update this model to use the DELETED_* constants.',
94
                E_USER_DEPRECATED
95
            );
96
97
            return $this->whereIn('status', $type::getActiveStatuses());
98
        }
99
100
        return $this->whereNot($column, '=', $type::DELETED_VALUE);
101
    }
102
103
    /**
104
     * Get the amount of pages this query would have.
105
     *
106
     * @return int
107
     */
108
    public function countPages()
109
    {
110
        return (int)ceil($this->count() / $this->resultsPerPage);
111
    }
112
113
    /**
114
     * Request that a specific model is not returned.
115
     *
116
     * @param  Model|int $model The ID or model you don't want to get
117
     *
118
     * @return static
119
     */
120
    public function except($model)
121
    {
122
        if ($model instanceof Model) {
123
            $model = $model->getId();
124
        }
125
126
        $this->whereNot('id', '=', $model);
127
128
        return $this;
129
    }
130
131
    /**
132
     * Only show results from a specific page.
133
     *
134
     * This method will automatically take care of the calculations for a correct OFFSET.
135
     *
136
     * @param  int|null $page The page number (or null to show all pages - counting starts from 0)
137
     *
138
     * @return static
139
     */
140
    public function fromPage($page)
141
    {
142
        if ($page === null) {
143
            $this->offset($page);
144
145
            return $this;
146
        }
147
148
        $page = intval($page);
149
        $page = ($page <= 0) ? 1 : $page;
150
151
        $this->offset((min($page, $this->countPages()) - 1) * $this->resultsPerPage);
152
153
        return $this;
154
    }
155
156
    /**
157
     * Perform the query and get the results as Models.
158
     *
159
     * @param  bool $fastFetch Whether to perform one query to load all the model data instead of fetching them one by
160
     *                         one (ignores cache)
161
     *
162
     * @return array
163
     */
164
    public function getModels($fastFetch = false)
165
    {
166
        /** @var Model $type */
167
        $type = $this->modelType;
168
        $columns = ($fastFetch) ? $type::getEagerColumns() : ['*'];
169
170
        $this->select($columns);
171
        $this->setFetchMode(PDO::FETCH_ASSOC);
172
173
        /** @var array $results */
174
        $results = $this->get();
175
176
        if ($fastFetch) {
177
            return $type::createFromDatabaseResults($results);
178
        }
179
180
        return $type::arrayIdToModel(array_column($results, 'id'));
181
    }
182
183
    /**
184
     * Set the model this QueryBuilder will be working this.
185
     *
186
     * This information is used for automatically retrieving table names, eager columns, and lazy columns for these
187
     * models.
188
     *
189
     * @param  string $modelType The FQN of the model this QueryBuilder will be working with
190
     *
191
     * @return $this
192
     */
193
    public function setModelType($modelType)
194
    {
195
        $this->modelType = $modelType;
196
197
        return $this;
198
    }
199
200
    /**
201
     * Make sure that Models invisible to a player are not returned.
202
     *
203
     * Note that this method does not take PermissionModel::canBeSeenBy() into
204
     * consideration for performance purposes, so you will have to override this
205
     * in your query builder if necessary.
206
     *
207
     * @param  Player $player      The player in question
208
     * @param  bool   $showDeleted Use false to hide deleted models even from admins
209
     *
210
     * @return static
211
     */
212
    public function visibleTo(Player $player, $showDeleted = false)
213
    {
214
        $type = $this->modelType;
215
216
        if (is_subclass_of($this->modelType, PermissionModel::class) &&
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if \PermissionModel::class can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
217
            $player->hasPermission(constant("$type::EDIT_PERMISSION"))
218
        ) {
219
            // The player is an admin who can see the hidden models
220
            if (!$showDeleted) {
221
                $col = constant("$type::DELETED_COLUMN");
222
223
                if ($col !== null) {
224
                    $this->whereNot($col, '=', constant("$type::DELETED_VALUE"));
225
                }
226
            }
227
        } else {
228
            return $this->active();
229
        }
230
231
        return $this;
232
    }
233
}
234