Path: blob/1.0-develop/app/Repositories/Eloquent/EloquentRepository.php
7460 views
<?php12namespace Pterodactyl\Repositories\Eloquent;34use Illuminate\Http\Request;5use Webmozart\Assert\Assert;6use Illuminate\Support\Collection;7use Illuminate\Database\Eloquent\Model;8use Pterodactyl\Repositories\Repository;9use Illuminate\Database\Eloquent\Builder;10use Illuminate\Database\Query\Expression;11use Illuminate\Database\Eloquent\ModelNotFoundException;12use Illuminate\Contracts\Pagination\LengthAwarePaginator;13use Pterodactyl\Contracts\Repository\RepositoryInterface;14use Pterodactyl\Exceptions\Model\DataValidationException;15use Pterodactyl\Exceptions\Repository\RecordNotFoundException;1617abstract class EloquentRepository extends Repository implements RepositoryInterface18{19protected bool $useRequestFilters = false;2021/**22* Determines if the repository function should use filters off the request object23* present when returning results. This allows repository methods to be called in API24* context's such that we can pass through ?filter[name]=Dane&sort=desc for example.25*/26public function usingRequestFilters(bool $usingFilters = true): self27{28$this->useRequestFilters = $usingFilters;2930return $this;31}3233/**34* Returns the request instance.35*/36protected function request(): Request37{38return $this->app->make(Request::class);39}4041/**42* Paginate the response data based on the page para.43*/44protected function paginate(Builder $instance, int $default = 50): LengthAwarePaginator45{46if (!$this->useRequestFilters) {47return $instance->paginate($default);48}4950return $instance->paginate($this->request()->query('per_page', $default));51}5253/**54* Return an instance of the eloquent model bound to this55* repository instance.56*/57public function getModel(): Model58{59return $this->model;60}6162/**63* Return an instance of the builder to use for this repository.64*/65public function getBuilder(): Builder66{67return $this->getModel()->newQuery();68}6970/**71* Create a new record in the database and return the associated model.72*73* @throws DataValidationException74*/75public function create(array $fields, bool $validate = true, bool $force = false): Model|bool76{77$instance = $this->getBuilder()->newModelInstance();78($force) ? $instance->forceFill($fields) : $instance->fill($fields);7980if (!$validate) {81$saved = $instance->skipValidation()->save();82} else {83if (!$saved = $instance->save()) {84throw new DataValidationException($instance->getValidator(), $instance);85}86}8788return ($this->withFresh) ? $instance->fresh() : $saved;89}9091/**92* Find a model that has the specific ID passed.93*94* @throws RecordNotFoundException95*/96public function find(int $id): Model97{98try {99return $this->getBuilder()->findOrFail($id, $this->getColumns());100} catch (ModelNotFoundException) {101throw new RecordNotFoundException();102}103}104105/**106* Find a model matching an array of where clauses.107*/108public function findWhere(array $fields): Collection109{110return $this->getBuilder()->where($fields)->get($this->getColumns());111}112113/**114* Find and return the first matching instance for the given fields.115*116* @throws RecordNotFoundException117*/118public function findFirstWhere(array $fields): Model119{120try {121return $this->getBuilder()->where($fields)->firstOrFail($this->getColumns());122} catch (ModelNotFoundException) {123throw new RecordNotFoundException();124}125}126127/**128* Return a count of records matching the passed arguments.129*/130public function findCountWhere(array $fields): int131{132return $this->getBuilder()->where($fields)->count($this->getColumns());133}134135/**136* Delete a given record from the database.137*/138public function delete(int $id, bool $destroy = false): int139{140return $this->deleteWhere(['id' => $id], $destroy);141}142143/**144* Delete records matching the given attributes.145*/146public function deleteWhere(array $attributes, bool $force = false): int147{148$instance = $this->getBuilder()->where($attributes);149150return ($force) ? $instance->forceDelete() : $instance->delete();151}152153/**154* Update a given ID with the passed array of fields.155*156* @throws DataValidationException157* @throws RecordNotFoundException158*/159public function update(int $id, array $fields, bool $validate = true, bool $force = false): Model|bool160{161try {162$instance = $this->getBuilder()->where('id', $id)->firstOrFail();163} catch (ModelNotFoundException) {164throw new RecordNotFoundException();165}166167($force) ? $instance->forceFill($fields) : $instance->fill($fields);168169if (!$validate) {170$saved = $instance->skipValidation()->save();171} else {172if (!$saved = $instance->save()) {173throw new DataValidationException($instance->getValidator(), $instance);174}175}176177return ($this->withFresh) ? $instance->fresh() : $saved;178}179180/**181* Update a model using the attributes passed.182*/183public function updateWhere(array $attributes, array $values): int184{185return $this->getBuilder()->where($attributes)->update($values);186}187188/**189* Perform a mass update where matching records are updated using whereIn.190* This does not perform any model data validation.191*/192public function updateWhereIn(string $column, array $values, array $fields): int193{194Assert::notEmpty($column, 'First argument passed to updateWhereIn must be a non-empty string.');195196return $this->getBuilder()->whereIn($column, $values)->update($fields);197}198199/**200* Update a record if it exists in the database, otherwise create it.201*202* @throws DataValidationException203* @throws RecordNotFoundException204*/205public function updateOrCreate(array $where, array $fields, bool $validate = true, bool $force = false): Model|bool206{207foreach ($where as $item) {208Assert::true(is_scalar($item) || is_null($item), 'First argument passed to updateOrCreate should be an array of scalar or null values, received an array value of %s.');209}210211try {212$instance = $this->setColumns('id')->findFirstWhere($where);213} catch (RecordNotFoundException) {214return $this->create(array_merge($where, $fields), $validate, $force);215}216217return $this->update($instance->id, $fields, $validate, $force);218}219220/**221* Return all records associated with the given model.222*223* @deprecated Just use the model224*/225public function all(): Collection226{227return $this->getBuilder()->get($this->getColumns());228}229230/**231* Return a paginated result set using a search term if set on the repository.232*/233public function paginated(int $perPage): LengthAwarePaginator234{235return $this->getBuilder()->paginate($perPage, $this->getColumns());236}237238/**239* Insert a single or multiple records into the database at once skipping240* validation and mass assignment checking.241*/242public function insert(array $data): bool243{244return $this->getBuilder()->insert($data);245}246247/**248* Insert multiple records into the database and ignore duplicates.249*/250public function insertIgnore(array $values): bool251{252if (empty($values)) {253return true;254}255256foreach ($values as $key => $value) {257ksort($value);258$values[$key] = $value;259}260261$bindings = array_values(array_filter(array_flatten($values, 1), function ($binding) {262return !$binding instanceof Expression;263}));264265$grammar = $this->getBuilder()->toBase()->getGrammar();266$table = $grammar->wrapTable($this->getModel()->getTable());267$columns = $grammar->columnize(array_keys(reset($values)));268269$parameters = collect($values)->map(function ($record) use ($grammar) {270return sprintf('(%s)', $grammar->parameterize($record));271})->implode(', ');272273$statement = "insert ignore into $table ($columns) values $parameters";274275return $this->getBuilder()->getConnection()->statement($statement, $bindings);276}277278/**279* Get the amount of entries in the database.280*281* @deprecated just use the count method off a model282*/283public function count(): int284{285return $this->getBuilder()->count();286}287}288289290