Lines 98.58% 279 / 283
Methods 97.61% 41 / 42
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 addRequiredJoins 100.00% 6 / 6 100.00% 1 / 1 1
 getEntityMapping 100.00% 44 / 44 100.00% 1 / 1 2
 getReferenceMapping 100.00% 3 / 3 100.00% 1 / 1 1
 addConditionAvailabilityId 100.00% 2 / 2 100.00% 1 / 1 1
 addConditionScopeId 100.00% 2 / 2 100.00% 1 / 1 1
 addConditionAppointmentHours 100.00% 4 / 4 100.00% 1 / 1 1
 addConditionOpeningHours 100.00% 4 / 4 100.00% 1 / 1 1
 addConditionDoubleTypes 100.00% 6 / 6 100.00% 1 / 1 1
 addConditionSkipOld 100.00% 4 / 4 100.00% 1 / 1 1
 addConditionOnlyOld 100.00% 4 / 4 100.00% 1 / 1 1
 addConditionTimeframe 100.00% 6 / 6 100.00% 1 / 1 1
 addConditionDate 100.00% 11 / 11 100.00% 1 / 1 1
 addConditionAppointmentTime 100.00% 4 / 4 100.00% 1 / 1 1
 reverseEntityMapping 100.00% 42 / 42 100.00% 1 / 1 6
 getJoinExpression 100.00% 18 / 18 100.00% 1 / 1 1
 postProcess 100.00% 10 / 10 100.00% 1 / 1 4
 [BO\Zmsbackend\Query\Base] __construct 88.23% 30 / 34 0.00% 0 / 1 10.16
 [BO\Zmsbackend\Query\Base] __toString n/a 0 / 0 n/a 0 / 0 4
 [BO\Zmsbackend\Query\Base] getName 100.00% 1 / 1 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] addSelect 100.00% 4 / 4 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] setDistinctSelect 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] setResolveLevel 100.00% 3 / 3 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] getResolveLevel 100.00% 3 / 3 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] getAlias 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] getTablename 100.00% 3 / 3 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addTable 100.00% 4 / 4 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addTableAlias 100.00% 4 / 4 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addResolvedReferences 100.00% 11 / 11 100.00% 1 / 1 3
 [BO\Zmsbackend\Query\Base] setWithEntities 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addJoin 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] leftJoin 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] innerJoin 100.00% 5 / 5 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] getSql 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] getParameters 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] expression 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addEntityMapping 100.00% 3 / 3 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] getPrefixed 100.00% 1 / 1 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] getPrefixedList 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] addReferenceMapping 100.00% 3 / 3 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] addLimit 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] addValues 100.00% 2 / 2 100.00% 1 / 1 1
 [BO\Zmsbackend\Query\Base] postProcessJoins 100.00% 4 / 4 100.00% 1 / 1 2
 [BO\Zmsbackend\Query\Base] shouldLoadEntity 100.00% 3 / 3 100.00% 1 / 1 2
8class Availability extends \BO\Zmsbackend\Query\Base implements \BO\Zmsbackend\Query\MappingInterface
9{
10    /**
11     * @var String TABLE mysql table reference
12     */
13    const string TABLE = 'oeffnungszeit';
14
15    const string TEMPORARY_DELETE = 'DELETE FROM oeffnungszeit WHERE `comment` = "--temporary--"';
16
17    const string QUERY_GET_LOCK = '
18        SELECT OeffnungszeitID FROM oeffnungszeit WHERE OeffnungszeitID = :availabilityId FOR UPDATE
19    ';
20
21    /**
22     * @return void
23     */
24    #[\Override]
25    public function addRequiredJoins()
26    {
27         $this->leftJoin(
28             new \BO\Zmsbackend\Query\Alias(\BO\Zmsbackend\Query\Scope::TABLE, 'availabilityscope'),
29             'availability.scope_id',
30             '=',
31             'availabilityscope.StandortID'
32         );
33    }
34
35    /**
36     * @return (\BO\Zmsbackend\Query\Builder\Expression|string)[]
37     *
38     */
39    #[\Override]
40    public function getEntityMapping($type = null)
41    {
42        $mapping = [
43            'id' => 'availability.OeffnungszeitID',
44            'scope__id' => 'availability.scope_id',
45            'bookable__startInDays' => self::expression(
46                'CAST(
47                    IF(`availability`.`open_from_days` = "0" OR `availability`.`open_from_days`, `availability`.`open_from_days`, `availabilityscope`.`Termine_ab`)
48                    AS SIGNED)'
49            ),
50            'bookable__endInDays' => self::expression(
51                'IF((`availability`.`open_from_days` = "0" AND `availability`.`open_until_days` = "0") OR `availability`.`open_until_days`, `availability`.`open_until_days`, `availabilityscope`.`Termine_bis`)'
52            ),
53            'description' => 'availability.comment',
54            'startDate' => 'availability.start_date',
55            'startTime' => self::expression(
56                'IF(`availability`.`appointment_start_time`,`availability`.`appointment_start_time`,`availability`.`start_time`)'
57            ),
58            'endDate' => 'availability.end_date',
59            'endTime' => self::expression(
60                'IF(`availability`.`appointment_start_time`, `availability`.`appointment_end_time`, `availability`.`end_time`)'
61            ),
62            'lastChange' => 'availability.updated_at',
63            'version' => 'availability.version',
64            'multipleSlotsAllowed' => 'availability.multiple_slots_allowed',
65            'repeat__afterWeeks' => 'availability.every_x_weeks',
66            'repeat__weekOfMonth' => 'availability.every_other_week',
67            'slotTimeInMinutes' => self::expression('FLOOR(TIME_TO_SEC(`availability`.`time_slot`) / 60)') ,
68            // dependant function on this IF(): \BO\Zmsbackend\Availablity\Service\Availablity::readList()
69            'type' => self::expression(
70                "IF(`availability`.`appointment_start_time`, 'appointment', 'openinghours')"
71            ),
72            'weekday__monday' => self::expression('`availability`.`weekday` & 2'),
73            'weekday__tuesday' => self::expression('`availability`.`weekday` & 4'),
74            'weekday__wednesday' => self::expression('`availability`.`weekday` & 8'),
75            'weekday__thursday' => self::expression('`availability`.`weekday` & 16'),
76            'weekday__friday' => self::expression('`availability`.`weekday` & 32'),
77            'weekday__saturday' => self::expression('`availability`.`weekday` & 64'),
78            'weekday__sunday' => self::expression('`availability`.`weekday` & 1'),
79            'workstationCount__intern' => 'availability.appointment_workstation_count',
80            'workstationCount__public' => self::expression(
81                'GREATEST(0, `availability`.`appointment_workstation_count` - `availability`.`internet_reduction`)'
82            )
83        ];
84        if ('openinghours' == $type) {
85            // Test if following line is needed: type mapping with IF() a few lines before
86            //$mapping['type'] = self::expression('"openinghours"');
87            $mapping['startTime'] = 'availability.start_time';
88            $mapping['endTime'] = 'availability.end_time';
89        }
90        return $mapping;
91    }
92
93    /**
94     * @return \BO\Zmsbackend\Query\Builder\Expression[]
95     *
96     */
97    #[\Override]
98    public function getReferenceMapping()
99    {
100        return [
101            'scope__$ref' => self::expression('CONCAT("/scope/", `availability`.`scope_id`, "/")'),
102        ];
103    }
104
105    public function addConditionAvailabilityId(int|string $availabilityId): static
106    {
107        $this->query->where('availability.OeffnungszeitID', '=', $availabilityId);
108        return $this;
109    }
110
111    public function addConditionScopeId($scopeId): static
112    {
113        $this->query->where('availabilityscope.StandortID', '=', $scopeId);
114        return $this;
115    }
116
117    public function addConditionAppointmentHours(): static
118    {
119        $this->query
120            ->where('availability.appointment_start_time', '!=', '00:00:00')
121            ->where('availability.appointment_end_time', '!=', '00:00:00');
122        return $this;
123    }
124
125    public function addConditionOpeningHours(): static
126    {
127        $this->query
128            ->where('availability.start_time', '!=', '00:00:00')
129            ->where('availability.end_time', '!=', '00:00:00');
130        return $this;
131    }
132
133    /**
134     * Used to identify old availabilities as appointment and openinghours
135     *
136     * @psalm-api
137     */
138    public function addConditionDoubleTypes(): static
139    {
140        $this->query
141            ->where('availability.appointment_start_time', '!=', '00:00:00')
142            ->where('availability.appointment_end_time', '!=', '00:00:00')
143            ->where('availability.start_time', '!=', '00:00:00')
144            ->where('availability.end_time', '!=', '00:00:00');
145        return $this;
146    }
147
148    public function addConditionSkipOld(\DateTimeInterface $dateTime): static
149    {
150        $date = $dateTime->format('Y-m-d');
151        $this->query
152            ->where('availability.end_date', '>=', $date);
153        return $this;
154    }
155
156    /**
157     * Used to identify availabilities whose End Date was more than 4 weeks ago
158     *
159     * @psalm-api
160     */
161    public function addConditionOnlyOld(\DateTimeInterface $dateTime): static
162    {
163        $date = $dateTime->format('Y-m-d');
164        $this->query
165            ->where('availability.end_date', '<=', $date);
166        return $this;
167    }
168
169   /**
170     * Identify availabilities between two dates
171     */
172    public function addConditionTimeframe(\DateTimeInterface $startDate, \DateTimeInterface $endDate): static
173    {
174        $this->query->where(function (\BO\Zmsbackend\Query\Builder\ConditionBuilder $condition) use ($startDate, $endDate) {
175            $condition
176                ->andWith('availability.start_date', '<=', $endDate->format('Y-m-d'))
177                ->andWith('availability.end_date', '>=', $startDate->format('Y-m-d'));
178        });
179        return $this;
180    }
181
182    public function addConditionDate(\DateTimeInterface $dateTime): static
183    {
184        $date = $dateTime->format('Y-m-d');
185        $this->query
186            ->where('availability.start_date', '<=', $date)
187            ->where('availability.end_date', '>=', $date);
188        //-- match weekday
189        $this->query->where(self::expression("availability.weekday & POW(2, DAYOFWEEK('$date') - 1)"), '>=', '1');
190        //-- match week
191        $this->query->where(self::expression("
192            (
193                (
194                    availability.every_x_weeks
195                    AND FLOOR(
196                        (
197                            FLOOR(UNIX_TIMESTAMP('$date'))
198                            - FLOOR(UNIX_TIMESTAMP(availability.start_date)))
199                            / 86400
200                            / 7
201                        )
202                        % availability.every_x_weeks = 0
203                )
204                OR (
205                    availability.every_other_week
206                    AND (
207                        CEIL(DAYOFMONTH('$date') / 7) = availability.every_other_week
208                        OR (
209                            availability.every_other_week = 5
210                            AND CEIL(LAST_DAY('$date') / 7) = CEIL(DAYOFMONTH('$date') / 7)
211                        )
212                    )
213                )
214                OR (availability.every_x_weeks = 0 AND availability.every_other_week = 0)
215            ) AND 1
216            "), '=', '1');
217        return $this;
218    }
219
220    public function addConditionAppointmentTime(\DateTimeInterface $dateTime): static
221    {
222        $time = $dateTime->format('H:i:s');
223        $this->query->where("availability.appointment_start_time", '<=', $time);
224        $this->query->where("availability.appointment_end_time", '>', $time);
225
226        return $this;
227    }
228
229    /**
230     * @return (int|mixed|string)[]
231     *
232     */
233    public function reverseEntityMapping(\BO\Zmsentities\Availability $entity): array
234    {
235        $data = array();
236        $data['scope_id'] = $entity['scope']['id'];
237        $data['open_from_days'] = $entity['bookable']['startInDays'];
238        $data['open_until_days'] = $entity['bookable']['endInDays'];
239        $data['comment'] = $entity['description'];
240        $data['start_date'] = $entity->getStartDateTime()->format('Y-m-d');
241        $data['end_date'] = $entity->getEndDateTime()->format('Y-m-d');
242        $data['version'] = $entity['version'];
243        if ('openinghours' == $entity['type']) {
244            $data['start_time'] = $entity['startTime'];
245            $data['end_time'] = $entity['endTime'];
246            $data['appointment_start_time'] = 0;
247            $data['appointment_end_time'] = 0;
248        } else {
249            $data['start_time'] = 0;
250            $data['end_time'] = 0;
251            $data['appointment_start_time'] = $entity['startTime'];
252            $data['appointment_end_time'] = $entity['endTime'];
253        }
254        $data['every_x_weeks'] = $entity['repeat']['afterWeeks'];
255        $data['every_other_week'] = $entity['repeat']['weekOfMonth'];
256        $data['time_slot'] = gmdate("H:i", $entity['slotTimeInMinutes'] * 60);
257        $data['multiple_slots_allowed'] = $entity['multipleSlotsAllowed'] ? 1 : 0;
258        $wochentagBinaryCoded = 0;
259        $binaryCodes = [
260            'sunday' => 1,
261            'monday' => 2,
262            'tuesday' => 4,
263            'wednesday' => 8,
264            'thursday' => 16,
265            'friday' => 32,
266            'saturday' => 64,
267            ];
268        foreach ($entity['weekday'] as $weekday => $isActive) {
269            if ($isActive) {
270                $wochentagBinaryCoded |= $binaryCodes[$weekday];
271            }
272        }
273        $data['weekday'] = $wochentagBinaryCoded;
274        $data['appointment_workstation_count'] = $entity['workstationCount']['intern'];
275        $data['internet_reduction'] =
276            $entity['workstationCount']['intern'] - $entity['workstationCount']['public'];
277
278        $data = array_filter($data, function ($value) {
279            return ($value !== null && $value !== false);
280        });
281            return $data;
282    }
283
284    public static function getJoinExpression(string $process, string $availability): \BO\Zmsbackend\Query\Builder\Expression
285    {
286        // UNIX_TIMESTAMP is relative here, no dependency to TIMEZONE
287        return self::expression("
288            $availability.scope_id = $process.StandortID
289            AND $availability.OeffnungszeitID IS NOT NULL
290
291            -- match weekday
292            AND $availability.weekday & POW(2, DAYOFWEEK($process.Datum) - 1)
293
294            -- match week
295            AND (
296                (
297                    $availability.every_x_weeks
298                    AND FLOOR(
299                        (
300                            FLOOR(UNIX_TIMESTAMP($process.Datum))
301                            - FLOOR(UNIX_TIMESTAMP($availability.start_date)))
302                            / 86400
303                            / 7
304                        )
305                        % $availability.every_x_weeks = 0
306                )
307                OR (
308                    $availability.every_other_week
309                    AND (
310                        CEIL(DAYOFMONTH($process.Datum) / 7) = $availability.every_other_week
311                        OR (
312                            $availability.every_other_week = 5
313                            AND CEIL(LAST_DAY($process.Datum) / 7) = CEIL(DAYOFMONTH($process.Datum) / 7)
314                        )
315                    )
316                )
317                OR ($availability.every_x_weeks = 0 AND $availability.every_other_week = 0)
318            )
319
320            -- match time and date
321            AND $process.Uhrzeit >= $availability.appointment_start_time
322            AND $process.Uhrzeit < $availability.appointment_end_time
323            AND $process.Datum >= $availability.start_date
324            AND $process.Datum <= $availability.end_date
325            ");
326    }
327
328    #[\Override]
329    public function postProcess($data)
330    {
331        $startDateKey = $this->getPrefixed("startDate");
332        $endDateKey = $this->getPrefixed("endDate");
333        $lastChangeKey = $this->getPrefixed("lastChange");
334        $startDate = $data[$startDateKey] ?? null;
335        $endDate = $data[$endDateKey] ?? null;
336        $lastChange = $data[$lastChangeKey] ?? null;
337        $data[$startDateKey] = $startDate !== null ? (new \DateTime($startDate))->getTimestamp() : null;
338        $data[$endDateKey] = $endDate !== null ? (new \DateTime($endDate))->getTimestamp() : null;
339        $data[$lastChangeKey] = $lastChange !== null ? (new \DateTime($lastChange . \BO\Zmsbackend\Connection\Select::$connectionTimezone))->getTimestamp() : null;
340        return $data;
341    }
342}

Inherited from BO\Zmsbackend\Query\Base

96    public function __construct(
97        $queryType,
98        $prefix = '',
99        string|false $name = false,
100        mixed $resolveLevel = null,
101        array $withEntities = []
102    ) {
103        $this->prefix = $prefix;
104        $this->name = $name;
105        $this->withEntities = $withEntities;
106        $this->setResolveLevel($resolveLevel);
107        $dialect = new MySQL();
108        if (self::SELECT === $queryType) {
109            $this->query = new Select($dialect);
110            $this->addSelect();
111        } elseif (self::INSERT === $queryType) {
112            $this->query = new Insert($dialect);
113            $this->addTable();
114        } elseif (self::UPDATE === $queryType) {
115            $this->query = new Update($dialect);
116            $this->addTableAlias();
117        } elseif (self::REPLACE === $queryType) {
118            $this->query = new INSERT($dialect);
119            $this->query->queryBaseStatement('REPLACE INTO');
120            $this->addTable();
121        } elseif (self::DELETE === $queryType) {
122            $this->query = new Delete($dialect);
123            $this->query->queryBaseStatement('DELETE ' . $this::getAlias() . ' FROM');
124            $this->addTableAlias();
125        } elseif ($queryType instanceof self) {
126            $this->query = $queryType->query;
127            // Share join-alias state with the parent query (intentional by-ref).
128            /** @psalm-suppress UnsupportedPropertyReferenceUsage */
129            $this->joinedAliasList =& $queryType->joinedAliasList;
130            $this->resolveLevel = $queryType->resolveLevel - 1;
131        } elseif ($queryType instanceof QueryBuilder) {
132            $this->query = $queryType;
133        } else {
134            throw new \InvalidArgumentException(
135                'Unsupported query type for ' . static::class . ': '
136                . (is_object($queryType) ? $queryType::class : gettype($queryType))
137            );
138        }
139        if ($this->query instanceof Select) {
140            $this->addRequiredJoins();
141        }
142    }
147    public function __toString()
148    {
149        if ($this->name) {
150            $name = $this->name . '_' . $this->prefix . (string) $this->resolveLevel;
151            if (!isset(static::$sqlCache[$name])) {
152                static::$sqlCache[$name] = $this->getSql();
153            }
154            return static::$sqlCache[$name];
155        }
156        if ($this->currentSqlString) {
157            $sql = $this->currentSqlString;
158        } else {
159            $sql = $this->getSql();
160        }
161        return $sql;
162    }
164    public function getName()
165    {
166        return $this->name ? $this->name : get_class($this);
167    }
174    protected function addSelect(): static
175    {
176        $table = $this::getTablename();
177        $alias = $this::getAlias();
178        $this->query->from($table, $alias);
179        return $this;
180    }
182    public function setDistinctSelect(): void
183    {
184        $this->query->queryBaseStatement('SELECT DISTINCT');
185    }
187    public function setResolveLevel(int|null $resolveLevel): static
188    {
189        if ($resolveLevel !== null) {
190            $this->resolveLevel = $resolveLevel;
191        }
192        return $this;
193    }
195    public function getResolveLevel()
196    {
197        if (null === $this->resolveLevel) {
198            throw new \Exception("Required setting for resolveReferenceLevel missing in " . get_class($this));
199        }
200        return $this->resolveLevel;
201    }
210    public static function getAlias()
211    {
212        $class = get_called_class();
213        $alias = constant($class . '::ALIAS');
214        if (null === $alias) {
215            $alias = lcfirst(preg_replace('#^.*\\\#', '', $class));
216        }
217        return $alias;
218    }
225    public static function getTablename()
226    {
227        $class = get_called_class();
228        $table = constant($class . '::TABLE');
229        return $table;
230    }
237    protected function addTable(): static
238    {
239        $table = $this::getTablename();
240        $alias = $this::getAlias();
241        $this->query->table($table, $alias);
242        return $this;
243    }
250    protected function addTableAlias(): static
251    {
252        $table = $this::getTablename();
253        $alias = $this::getAlias();
254        $this->query->table(self::expression($table . ' ' . $alias));
255        return $this;
256    }
273    public function addResolvedReferences($depth): static
274    {
275        $this->setResolveLevel($depth);
276        if ($depth > 0) {
277            $queryList = $this->addJoin();
278            foreach ($queryList as $query) {
279                $query->setResolveLevel($depth);
280                $query->setWithEntities($this->withEntities);
281                $query->addResolvedReferences($depth - 1);
282                $query->addEntityMapping();
283            }
284            $this->joinedQueryList = $queryList;
285        } else {
286            $this->addReferenceMapping();
287        }
288        return $this;
289    }
294    public function setWithEntities($withEntities = []): void
295    {
296        $this->withEntities = $withEntities;
297    }
304    protected function addJoin()
305    {
306        return [];
307    }
309    protected function leftJoin(Alias $alias, string|Expression|null $left = null, string|null $operator = null, string|null $right = null): QueryBuilder
310    {
311        $aliasId = $alias->getAliasIdentifier();
312        if (!in_array($aliasId, $this->joinedAliasList)) {
313            $this->joinedAliasList[] = $aliasId;
314            $this->query->leftJoin($alias, $left, $operator, $right);
315        } else {
316            //throw new \Exception("Tried to add Alias ".$aliasId);
317        }
318        return $this->query;
319    }
321    protected function innerJoin(Alias $alias, string|null $left = null, string|null $operator = null, string|null $right = null): QueryBuilder
322    {
323        $aliasId = $alias->getAliasIdentifier();
324        if (!in_array($aliasId, $this->joinedAliasList)) {
325            $this->joinedAliasList[] = $aliasId;
326            $this->query->join($alias, $left, $operator, $right);
327        }
328        return $this->query;
329    }
337    public function getSql()
338    {
339        $this->currentSqlString = (string)$this->query;
340        return $this->currentSqlString;
341    }
348    public function getParameters()
349    {
350        return $this->query->params();
351    }
368    protected static function expression(string $string)
369    {
370        return new Expression($string);
371    }
379    public function addEntityMapping(mixed $type = null): static
380    {
381        // Concrete query classes provide getEntityMapping(); not all declare MappingInterface.
382        /** @psalm-suppress UndefinedMethod, TooManyArguments */
383        $entityMapping = $this->getPrefixedList($this->getEntityMapping($type));
384        $this->query->select($entityMapping);
385        return $this;
386    }
388    protected function getPrefixed($prefix): string
389    {
390        return $this->prefix . $prefix;
391    }
393    protected function getPrefixedList(array $unprefixedList): array
394    {
395        $prefixed = [];
396        foreach ($unprefixedList as $key => $value) {
397            $prefixed[$this->getPrefixed($key)] = $value;
398        }
399        return $prefixed;
400    }
405    protected function addReferenceMapping(): static
406    {
407        $referenceMapping = $this->getPrefixedList($this->getReferenceMapping());
408        $this->query->select($referenceMapping);
409        return $this;
410    }
412    public function addLimit(int $count, ?int $offset = null): static
413    {
414        $this->query->limit($count);
415        if ($offset) {
416            $this->query->offset($offset);
417        }
418        return $this;
419    }
424    public function addValues(array $values): static
425    {
426        $this->query->values($values);
427        return $this;
428    }
445    public function postProcessJoins(array $data)
446    {
447        $data = $this->postProcess($data);
448        foreach ($this->joinedQueryList as $query) {
449            $data = $query->postProcess($data);
450        }
451        return $data;
452    }
454    public function shouldLoadEntity(string $name): bool
455    {
456        if (empty($this->withEntities)) {
457            return true;
458        }
459
460        return in_array($name, $this->withEntities);
461    }