%PDF- %GIF98; %PNG;
Server : ApacheSystem : Linux host.digitalbabaji.in 4.18.0-513.11.1.el8_9.x86_64 #1 SMP Wed Jan 17 02:00:40 EST 2024 x86_64 User : addictionfreeind ( 1003) PHP Version : 7.2.34 Disable Function : exec,passthru,shell_exec,system Directory : /home/addictionfreeind/public_html/admin1/vendor/froiden/laravel-rest-api/src/ |
Upload File : |
<?php namespace Froiden\RestAPI;
use Carbon\Carbon;
use Closure;
use DateTimeInterface;
use Froiden\RestAPI\Exceptions\RelatedResourceNotFoundException;
use Froiden\RestAPI\Exceptions\ResourceNotFoundException;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Str;
class ApiModel extends Model
{
/**
* List of fields that are visible by default. Only these fields
* are selected and returned from database
*
* @var array
*/
protected $default = ["id"];
/**
* List of fields that are always hidden. Unless modified, these
* fields are not visible when object is serialised. To comply with
* Rest architecture, its recommended to hide all relation fields
* (like, user_id, student_id)
*
* @var array
*/
protected $hidden = ["created_at", "updated_at", "pivot"];
/**
* List of fields on which filters are allowed to be applied. For security
* reasons we cannot allow filters to be allowed on arbitrary fields
* @var array
*/
protected $filterable = ["id"];
/**
* List of relation attributes found during parsing of request, to be used during saving action
* @var array
*/
protected $relationAttributes = [];
protected $guarded = [];
/**
* Raw attributes as sent in request. To be used in setters of various attributes
* @var array
*/
protected $raw = [];
//region Metadata functions
/**
* Name of table of this model
*
* @return string
*/
public static function getTableName()
{
return (new static)->table;
}
/**
* Date fields in this model
*
* @return array
*/
public static function getDateFields()
{
return (new static)->dates;
}
/**
* List of custom fields (attributes) that are appended by default
* ($appends array)
*
* @return array
*/
public static function getAppendFields()
{
return (new static)->appends;
}
/**
* List of fields to display by default ($defaults array)
*
* @return array
*/
public static function getDefaultFields()
{
return (new static)->default;
}
/**
* Return the $relationKeys array
*
* @return mixed
*/
public static function getRelationKeyFields()
{
return (new static)->relationKeys;
}
/**
* Returns list of fields on which filter is allowed to be applied
*
* @return array
*/
public static function getFilterableFields()
{
return (new static)->filterable;
}
/**
* Checks if given relation exists on the model
*
* @param $relation
* @return bool
*/
public static function relationExists($relation)
{
// Check if relation name in modal is in camel case or not
if (config("api.relation_case", 'snakecase') === 'camelcase') {
return (method_exists(new static(), $relation) ?? false) || (method_exists(new static(), Str::camel($relation)) ?? false);
}
return method_exists(new static(), $relation);
}
//endregion
/**
* Prepare a date for array / JSON serialization. Override base method in Model to suite our needs
*
* @param \DateTime $date
* @return string
*/
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format("c");
}
/**
* Return a timestamp as DateTime object.
*
* @param mixed $value
* @return \Carbon\Carbon
*/
protected function asDateTime($value)
{
// If this value is already a Carbon instance, we shall just return it as is.
// This prevents us having to re-instantiate a Carbon instance when we know
// it already is one, which wouldn't be fulfilled by the DateTime check.
if ($value instanceof Carbon) {
return $value;
}
// If the value is already a DateTime instance, we will just skip the rest of
// these checks since they will be a waste of time, and hinder performance
// when checking the field. We will just return the DateTime right away.
if ($value instanceof DateTimeInterface) {
return new Carbon(
$value->format('Y-m-d H:i:s.u'), $value->getTimeZone()
);
}
// If this value is an integer, we will assume it is a UNIX timestamp's value
// and format a Carbon object from this timestamp. This allows flexibility
// when defining your date fields as they might be UNIX timestamps here.
if (is_numeric($value)) {
return Carbon::createFromTimestamp($value);
}
// If the value is in simply year, month, day format, we will instantiate the
// Carbon instances from that format. Again, this provides for simple date
// fields on the database, while still supporting Carbonized conversion.
if (preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value)) {
return Carbon::createFromFormat('Y-m-d', $value)->startOfDay();
}
// Parse ISO 8061 date
if (preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\\+(\d{2}):(\d{2})$/', $value)) {
return Carbon::createFromFormat('Y-m-d\TH:i:s+P', $value);
}
elseif (preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2}T(\d{2}):(\d{2}):(\d{2})\\.(\d{1,3})Z)$/', $value)) {
return Carbon::createFromFormat('Y-m-d\TH:i:s.uZ', $value);
}
// Finally, we will just assume this date is in the format used by default on
// the database connection and use that format to create the Carbon object
// that is returned back out to the developers after we convert it here.
return Carbon::createFromFormat($this->getDateFormat(), $value);
}
/**
* Eagerly load the relationship on a set of models.
*
* @param array $models
* @param string $name
* @param \Closure $constraints
* @return array
*/
protected function loadRelation(array $models, $name, Closure $constraints)
{
// First we will "back up" the existing where conditions on the query so we can
// add our eager constraints. Then we will merge the wheres that were on the
// query back to it in order that any where conditions might be specified.
$relation = $this->getRelation($name);
$relation->addEagerConstraints($models);
call_user_func($constraints, $relation);
$models = $relation->initRelation($models, $name);
// Once we have the results, we just match those back up to their parent models
// using the relationship instance. Then we just return the finished arrays
// of models which have been eagerly hydrated and are readied for return.
$results = $relation->getEager();
return $relation->match($models, $results, $name);
}
/**
* Fill the model with an array of attributes.
*
* @param array $attributes
* @param bool $relations If the attributes also contain relations
* @return Model
*/
public function fill(array $attributes = [])
{
$this->raw = $attributes;
$excludes = config("api.excludes");
foreach ($attributes as $key => $attribute) {
// Guarded attributes should be removed
if (in_array($key, $excludes)) {
unset($attributes[$key]);
}
else if (method_exists($this, $key) && ((is_array($attribute) || is_null($attribute)))) {
// Its a relation
$this->relationAttributes[$key] = $attribute;
// For belongs to relation, while filling, we need to set relation key.
$relation = call_user_func([$this, $key]);
if ($relation instanceof BelongsTo) {
$primaryKey = $relation->getRelated()->getKeyName();
if ($attribute !== null) {
// If key value is not set in request, we create new object
if (!isset($attribute[$primaryKey])) {
throw new RelatedResourceNotFoundException('Resource for relation "' . $key . '" not found');
}
else {
$model = $relation->getRelated()->find($attribute[$primaryKey]);
if (!$model) {
// Resource not found
throw new ResourceNotFoundException();
}
}
}
$relationKey = $relation->getForeignKeyName();
$this->setAttribute($relationKey, ($attribute === null) ? null : $model->getKey());
}
unset($attributes[$key]);
}
}
return parent::fill($attributes);
}
public function save(array $options = [])
{
// Belongs to relation needs to be set before, because we need the parent's Id
foreach ($this->relationAttributes as $key => $relationAttribute) {
/** @var Relation $relation */
$relation = call_user_func([$this, $key]);
if ($relation instanceof BelongsTo) {
$primaryKey = $relation->getRelated()->getKeyName();
if ($relationAttribute !== null) {
// If key value is not set in request, we create new object
if (!isset($relationAttribute[$primaryKey])) {
throw new RelatedResourceNotFoundException('Resource for relation "' . $key . '" not found');
}
else {
$model = $relation->getRelated()->find($relationAttribute[$primaryKey]);
if (!$model) {
// Resource not found
throw new RelatedResourceNotFoundException('Resource for relation "' . $key . '" not found');
}
}
}
$relationKey = $relation->getForeignKeyName();
$this->setAttribute($relationKey, ($relationAttribute === null) ? null : $model->getKey());
unset($this->relationAttributes[$key]);
}
}
parent::save($options);
// Fill all other relations
foreach ($this->relationAttributes as $key => $relationAttribute) {
/** @var Relation $relation */
$relation = call_user_func([$this, $key]);
$primaryKey = $relation->getRelated()->getKeyName();
if ($relation instanceof HasOne || $relation instanceof HasMany) {
if ($relation instanceof HasOne) {
$relationAttribute = [$relationAttribute];
}
$relationKey = explode(".", $relation->getQualifiedParentKeyName())[1];
foreach ($relationAttribute as $val) {
if ($val !== null) {
if (!isset($val[$primaryKey])) {
throw new RelatedResourceNotFoundException('Resource for relation "' . $key . '" not found');
}
else {
/** @var Model $model */
$model = $relation->getRelated()->find($val[$primaryKey]);
if (!$model) {
// Resource not found
throw new RelatedResourceNotFoundException('Resource for relation "' . $key . '" not found');
}
// Only update relation key to attach $model to $this object
$model->{$relationKey} = $this->getKey();
$model->save();
}
}
}
}
else if ($relation instanceof BelongsToMany) {
$relatedIds = [];
// Value is an array of related models
foreach ($relationAttribute as $val) {
if ($val !== null) {
if (!isset($val[$primaryKey])) {
throw new RelatedResourceNotFoundException('Resource for relation "' . $key . '" not found');
}
else {
/** @var Model $model */
$model = $relation->getRelated()->find($val[$primaryKey]);
if (!$model) {
// Resource not found
throw new RelatedResourceNotFoundException('Resource for relation "' . $key . '" not found');
}
}
}
if ($val !== null) {
if(isset($val['pivot'])) {
// We have additional fields other than primary key
// that need to be saved to pivot table
/*
[
{
"id": 12, // Primary key
"pivot": {
"count": 8 // Pivot table column
}
}
]
*/
$relatedIds[$model->getKey()] = $val['pivot'];
}
else {
// We just have ids
$relatedIds[] = $model->getKey();
}
}
}
$relation->sync($relatedIds);
}
}
}
}