346 lines
7.5 KiB
PHP
346 lines
7.5 KiB
PHP
<?php
|
|
|
|
namespace App\Repositories;
|
|
|
|
use App\Interfaces\BaseRepositoryInterface;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|
|
|
/**
|
|
* Base Repository Implementation
|
|
*
|
|
* Provides common repository functionality for all models.
|
|
* Implements the BaseRepositoryInterface with reusable methods.
|
|
*
|
|
* @author David Valera Melendez <david@valera-melendez.de>
|
|
* @since February 2025
|
|
*/
|
|
abstract class BaseRepository implements BaseRepositoryInterface
|
|
{
|
|
/**
|
|
* The model instance
|
|
*
|
|
* @var Model
|
|
*/
|
|
protected Model $model;
|
|
|
|
/**
|
|
* The query builder instance
|
|
*
|
|
* @var Builder
|
|
*/
|
|
protected Builder $query;
|
|
|
|
/**
|
|
* Create a new repository instance
|
|
*
|
|
* @param Model $model
|
|
*/
|
|
public function __construct(Model $model)
|
|
{
|
|
$this->model = $model;
|
|
$this->resetQuery();
|
|
}
|
|
|
|
/**
|
|
* Get all records
|
|
*
|
|
* @param array $columns
|
|
* @return Collection
|
|
*/
|
|
public function all(array $columns = ['*']): Collection
|
|
{
|
|
$result = $this->query->get($columns);
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Get records with pagination
|
|
*
|
|
* @param int $perPage
|
|
* @param array $columns
|
|
* @return LengthAwarePaginator
|
|
*/
|
|
public function paginate(int $perPage = 15, array $columns = ['*']): LengthAwarePaginator
|
|
{
|
|
$result = $this->query->paginate($perPage, $columns);
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Find a record by ID
|
|
*
|
|
* @param int $id
|
|
* @param array $columns
|
|
* @return Model|null
|
|
*/
|
|
public function find(int $id, array $columns = ['*']): ?Model
|
|
{
|
|
$result = $this->query->find($id, $columns);
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Find a record by ID or throw an exception
|
|
*
|
|
* @param int $id
|
|
* @param array $columns
|
|
* @return Model
|
|
* @throws ModelNotFoundException
|
|
*/
|
|
public function findOrFail(int $id, array $columns = ['*']): Model
|
|
{
|
|
$result = $this->query->findOrFail($id, $columns);
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Find records by criteria
|
|
*
|
|
* @param array $criteria
|
|
* @param array $columns
|
|
* @return Collection
|
|
*/
|
|
public function findBy(array $criteria, array $columns = ['*']): Collection
|
|
{
|
|
$this->applyCriteria($criteria);
|
|
$result = $this->query->get($columns);
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Find a single record by criteria
|
|
*
|
|
* @param array $criteria
|
|
* @param array $columns
|
|
* @return Model|null
|
|
*/
|
|
public function findOneBy(array $criteria, array $columns = ['*']): ?Model
|
|
{
|
|
$this->applyCriteria($criteria);
|
|
$result = $this->query->first($columns);
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Create a new record
|
|
*
|
|
* @param array $data
|
|
* @return Model
|
|
*/
|
|
public function create(array $data): Model
|
|
{
|
|
return $this->model->create($data);
|
|
}
|
|
|
|
/**
|
|
* Update an existing record
|
|
*
|
|
* @param int $id
|
|
* @param array $data
|
|
* @return bool
|
|
*/
|
|
public function update(int $id, array $data): bool
|
|
{
|
|
$model = $this->findOrFail($id);
|
|
return $model->update($data);
|
|
}
|
|
|
|
/**
|
|
* Update or create a record
|
|
*
|
|
* @param array $attributes
|
|
* @param array $values
|
|
* @return Model
|
|
*/
|
|
public function updateOrCreate(array $attributes, array $values = []): Model
|
|
{
|
|
return $this->model->updateOrCreate($attributes, $values);
|
|
}
|
|
|
|
/**
|
|
* Delete a record by ID
|
|
*
|
|
* @param int $id
|
|
* @return bool
|
|
*/
|
|
public function delete(int $id): bool
|
|
{
|
|
$model = $this->findOrFail($id);
|
|
return $model->delete();
|
|
}
|
|
|
|
/**
|
|
* Delete records by criteria
|
|
*
|
|
* @param array $criteria
|
|
* @return int Number of deleted records
|
|
*/
|
|
public function deleteBy(array $criteria): int
|
|
{
|
|
$this->applyCriteria($criteria);
|
|
$result = $this->query->delete();
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Count records
|
|
*
|
|
* @param array $criteria
|
|
* @return int
|
|
*/
|
|
public function count(array $criteria = []): int
|
|
{
|
|
if (!empty($criteria)) {
|
|
$this->applyCriteria($criteria);
|
|
}
|
|
|
|
$result = $this->query->count();
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Check if record exists
|
|
*
|
|
* @param array $criteria
|
|
* @return bool
|
|
*/
|
|
public function exists(array $criteria): bool
|
|
{
|
|
$this->applyCriteria($criteria);
|
|
$result = $this->query->exists();
|
|
$this->resetQuery();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Get records with relationships
|
|
*
|
|
* @param array $relations
|
|
* @return BaseRepositoryInterface
|
|
*/
|
|
public function with(array $relations): BaseRepositoryInterface
|
|
{
|
|
$this->query = $this->query->with($relations);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Order records
|
|
*
|
|
* @param string $column
|
|
* @param string $direction
|
|
* @return BaseRepositoryInterface
|
|
*/
|
|
public function orderBy(string $column, string $direction = 'asc'): BaseRepositoryInterface
|
|
{
|
|
$this->query = $this->query->orderBy($column, $direction);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Limit records
|
|
*
|
|
* @param int $limit
|
|
* @return BaseRepositoryInterface
|
|
*/
|
|
public function limit(int $limit): BaseRepositoryInterface
|
|
{
|
|
$this->query = $this->query->limit($limit);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Apply criteria to the query
|
|
*
|
|
* @param array $criteria
|
|
* @return void
|
|
*/
|
|
protected function applyCriteria(array $criteria): void
|
|
{
|
|
foreach ($criteria as $field => $value) {
|
|
if (is_array($value)) {
|
|
$this->query = $this->query->whereIn($field, $value);
|
|
} elseif (is_null($value)) {
|
|
$this->query = $this->query->whereNull($field);
|
|
} else {
|
|
$this->query = $this->query->where($field, $value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset the query builder
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function resetQuery(): void
|
|
{
|
|
$this->query = $this->model->newQuery();
|
|
}
|
|
|
|
/**
|
|
* Get the model instance
|
|
*
|
|
* @return Model
|
|
*/
|
|
public function getModel(): Model
|
|
{
|
|
return $this->model;
|
|
}
|
|
|
|
/**
|
|
* Set the model instance
|
|
*
|
|
* @param Model $model
|
|
* @return void
|
|
*/
|
|
public function setModel(Model $model): void
|
|
{
|
|
$this->model = $model;
|
|
$this->resetQuery();
|
|
}
|
|
|
|
/**
|
|
* Execute a callback within a database transaction
|
|
*
|
|
* @param callable $callback
|
|
* @return mixed
|
|
* @throws \Throwable
|
|
*/
|
|
protected function transaction(callable $callback)
|
|
{
|
|
return $this->model->getConnection()->transaction($callback);
|
|
}
|
|
|
|
/**
|
|
* Get fresh timestamp for the model
|
|
*
|
|
* @return \Carbon\Carbon
|
|
*/
|
|
protected function freshTimestamp(): \Carbon\Carbon
|
|
{
|
|
return $this->model->freshTimestamp();
|
|
}
|
|
}
|