I suggest just starting a new app with latest version and migrate your:
- models
- views
- controllers
- custom code / classes
Over to new app. Older versions are outdated and no new security patches.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
I have laravel project built on v5.x I have migrated laravel version from v5.x code to v7.x. but I have issue on Table relationship on v7.x for example, belongsTo and hasOne relationship between User and Country table works on v5.x but it doesn't work on v7.x. It looks like table left join doesn't work after v7.x migration ----------User.php------------------
class User extends Base {
public function countries()
{
return $this->belongsTo(
\App\Country::class,
'country',
'code'
);
}
}}
--------Country.php-----------------
class Country extends Base {
public function user()
{
return $this->hasOne(
\App\User::class,
'country',
'code'
)->active();
}
}
By the way, I have Resource controller for self api request query parse on v5.x I think there are some updated function on v7.x
<?php
namespace App\Http\Controllers;
use App\Base;
use App\Contracts\ResourceInterface;
use App\Entity;
use App\Traits\HasFees;
use App\Traits\HasImages;
use App\Traits\HasTransactions;
use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Routing\Route;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\MessageBag;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Log;
/**
* Class ResourceController
*/
class ResourceController extends BaseController implements ResourceInterface
{
/**
* The errors array
*
* @var array
*/
protected $errors = [];
/**
* The error messages from the message bag
*
* @var MessageBag
*/
protected $errorMessages = [];
/**
* Default number of items used for pagination
*
* @var int
*/
protected $itemsPerPage = 50;
/**
* All filters that can be used during a query
*
* @var array
*/
protected $filters = [];
/**
* The request to use during the call
*
* @var Request
*/
protected $request = null;
/**
* The original request that was received from the call
*
* @var Request
*/
protected $originalRequest = null;
/**
* Property that will load the main model
*
* @var Model
*/
protected $model = null;
/**
* Property that will load the main resource
*
* @var resource
*/
protected $resource = null;
/**
* Flag to indicate if the resource should use collection
*
* @var bool
*/
protected $resourceCollection = false;
/**
* Flag to indicate if the query builder has aggregates
*
* @var bool
*/
protected $aggregates = false;
/**
* All relations that the loaded model has
*
* @var array
*/
protected $relations = [];
/**
* Relation classes that should not have methods skipped if
* encountered
*
* @var array
*/
protected $relationSkips = [
HasFees::class => [],
HasImages::class => [
'image',
'images',
],
HasTransactions::class => [
'transaction',
'transactions',
],
SoftDeletes::class => [],
];
/**
* All methods that are not a relation
*
* @var array
*/
protected $nonRelationMethods = [
'processEntries',
'shouldUpgradeTier',
'userRefs',
'getRecentlyUsedAddresses',
'getRewardsPaid',
'getRewardsEligibility',
'hasContact',
'getVerificationUserRef',
'processCardOrder',
'processRewards',
'forceDelete',
'boot',
];
/**
* The logged in entity
*
* @var Entity
*/
protected $entity;
/**
* Load the entity if in session as soon as the controller
* instantiates
*/
public function __construct()
{
// Load the entity if present
$this->entity = session('entity');
$this->request = request();
}
/**
* Method to initiate the main controller and route the
* proper method
*
* @return mixed
*
* @throws ModelNotFoundException|\Exception
*/
public function initiate(Request $request)
{
// Reset the flags
$this->resetFlags();
// Set the original request
$this->originalRequest = $request;
// Get the method
$method = $this->originalRequest->getMethod();
// Get route information
$model = $this->originalRequest->route()->parameter('model');
$id = $this->originalRequest->route()->parameter('id');
$override = self::METHOD_MAPPING_OVERRIDES['BACKEND'][$model] ?? [];
// Load the model
if (isset(self::RESOURCE_MAPPING['BACKEND'][$model])) {
if (! $this->loadModel($model, $id)) {
throw new ModelNotFoundException();
} elseif (! $this->loadRequest($this->originalRequest)) {
// Default to original request and set flag
$this->request = $this->originalRequest;
}
if (! $this->loadResource($model)) {
$this->resource = self::RESOURCE_NAMESPACE.'DefaultResource';
}
// If all went fine load all relationships
$this->loadRelations();
} else {
// In case this is a raw override not related to a model,
// just copy over the request
$this->request = $this->originalRequest;
$this->errorMessages = new MessageBag();
}
// Call proper method according to request
$methodParam = 'all';
// Look for any other parameter besides id and model
$availableParam = collect($this->originalRequest->route()->parameters())
->except('model')->keys()->first();
if ($availableParam && isset(self::METHOD_MAPPING[$method][$availableParam])) {
$methodParam = $availableParam;
}
if (isset($override[$method][$methodParam])) {
return $this->{$override[$method][$methodParam]}();
} else {
return $this->{self::METHOD_MAPPING[$method][$methodParam]}();
}
}
/**
* Method to properly reset all flags and start a fresh call
*/
protected function resetFlags()
{
$this->resourceCollection = false;
$this->model = null;
$this->relations = [];
$this->resource = null;
$this->request = null;
$this->originalRequest = null;
}
/**
* Method to load the resource for this call
*
* @param string $model The model that came with the call
* @return bool
*/
public function loadResource($model)
{
$resource = self::RESOURCE_NAMESPACE.'Backend\'.
self::RESOURCE_MAPPING['BACKEND'][$model].
'Resource';
if (! class_exists($resource)) {
// If it doesn't exist just return false
return false;
} else {
// Set the resource
$this->resource = $resource;
}
return true;
}
/**
* Method to properly load the request for the model
*
* @param Request $originalRequest The original request
* @return bool
*/
public function loadRequest(Request $originalRequest)
{
// Create the name
$model = $originalRequest->route()->parameter('model');
$request = self::REQUEST_NAMESPACE.'Backend\'.
self::RESOURCE_MAPPING['BACKEND'][$model].
'Request';
if (! class_exists($request)) {
// If it doesn't exist just return false
return false;
} else {
// Instantiate the request associated with this model
$this->request = new $request(
$originalRequest->query->all(),
$originalRequest->request->all(),
$originalRequest->attributes->all(),
$originalRequest->cookies->all(),
$originalRequest->files->all(),
$originalRequest->server->all(),
$originalRequest->getContent()
);
// Set all needed parameters from original request
$this->request->setMethod($originalRequest->getMethod());
$this->request->setUserResolver($originalRequest->getUserResolver());
$this->request->setRouteResolver($originalRequest->getRouteResolver());
$this->request->setRequestFormat($originalRequest->getRequestFormat());
$this->request->setContainer(Container::getInstance());
$this->request->setJson($originalRequest->json());
// Validate the request
// $this->request->validate();
}
return true;
}
/**
* Method to properly load the model on the request
*
* @param string $model The model that came with the call
* @param int $id The id of the model if any
* @return bool
*/
protected function loadModel($model, $id = null)
{
// Look for the model
if ($model && isset(self::RESOURCE_MAPPING['BACKEND'][$model]) &&
($model = self::MODEL_NAMESPACE.self::RESOURCE_MAPPING['BACKEND'][$model]) &&
class_exists($model)) {
// Make sure that the model properly exists
if ($id && ! ($this->model = $model::find($id))) {
// If id parameter was sent and it doesn't exist, bail
return false;
} elseif (! $id) {
// Instantiate the model
$this->model = new $model();
}
return true;
}
return false;
}
/**
* Method that will load all relations of the loaded model
*
* @param string The model to get the classes
* @return array
*
* @throws \ReflectionException
*/
protected function loadRelations($externalModel = null)
{
$model = $externalModel ?? get_class($this->model);
$reflection = new \ReflectionClass($model);
$relations = [];
foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
if ($method->class != $model ||
! empty($method->getParameters()) ||
$method->getName() == __FUNCTION__ ||
in_array($method->getName(), $this->nonRelationMethods)) {
continue;
} else {
$hasRelationSkipMethod = false;
foreach ($reflection->getTraits() as $trait) {
if (in_array($trait->getName(), array_keys($this->relationSkips))) {
foreach ($trait->getMethods(\ReflectionMethod::IS_PUBLIC) as $traitMethod) {
if ($traitMethod->getName() == $method->getName() &&
! in_array($traitMethod->getName(), $this->relationSkips[$trait->getName()])) {
$hasRelationSkipMethod = true;
break;
}
}
if ($hasRelationSkipMethod) {
break;
}
}
}
if ($hasRelationSkipMethod) {
continue;
}
}
try {
if ($externalModel) {
$invoke = new $externalModel();
} else {
$invoke = $this->model;
}
$return = $method->invoke($invoke);
if ($return instanceof Relation) {
$relations[$method->getName()] = [
'type' => (new \ReflectionClass($return))->getShortName(),
'model' => (new \ReflectionClass($return->getRelated()))->getName(),
'table' => $return->getModel()->getTable(),
'foreignKey' => method_exists($return, 'getQualifiedForeignKeyName') ?
$return->getQualifiedForeignKeyName() :
$return->getQualifiedOwnerKeyName(),
'localKey' => method_exists($return, 'getQualifiedForeignKey') ?
$return->getQualifiedForeignKey() :
$return->getQualifiedParentKeyName(),
];
} elseif (isset($return['relation'])) {
$relations[$method->getName()] = $return['relation'];
}
} catch (\Exception $e) {
} catch (\Throwable $t) {
}
}
if ($externalModel) {
return $relations;
} else {
$this->relations = $relations;
return $this->relations;
}
}
/**
* Method to process all possible nested relation creation
* in the call
*/
protected function processNestedRelationCruds()
{
if ($this->model->getErrorMessages()) {
// We don't want to process relation cruds on a model
// with errors
return false;
}
// Set flag initially to false
$hasRelationCrud = false;
// Look for any relation that may be in the request
foreach ($this->relations as $method => $relation) {
if ($this->model->$method instanceof Collection) {
$exists = $this->model->$method()->get()->count();
} else {
$exists = $this->model->$method;
}
if (! $exists &&
($relationData = $this->request->json($method)) &&
is_array($relationData)) {
// Set the flag to true so we refresh model later
$hasRelationCrud = true;
if (count($relationData) == count($relationData, COUNT_RECURSIVE)) {
// There is a relation in the call try to create it
$this->processRelationCrud($relationData, $relation['model'], $method);
} else {
foreach ($relationData as $data) {
// There is a relation in the call try to create it
$this->processRelationCrud($data, $relation['model'], $method);
}
}
}
}
if ($hasRelationCrud) {
// If we have found relation data refresh the model
$this->refreshModel();
}
}
/**
* Method to properly process a relation crud, it will automatically
* look for the id if it has any and attempt to update it or insert
* new one
*/
protected function processRelationCrud($relationData,
$relationModel,
$relationMethod)
{
if (isset($relationData['id']) &&
($relationModel = $relationModel::find($relationData['id']))) {
// If it has an id it could be an update try looking for the relation
$relationModel->update($relationData);
} else {
// There is a relation in the call try to create it
$this->model->$relationMethod()->save(new $relationModel($relationData));
}
}
/**
* Method to properly apply all wheres in the http query parameters
*
* @param Builder $query The query being built
* @return Builder|array
*/
protected function applyWiths(?Builder &$query = null)
{
if ($this->request->get('with') &&
is_array($this->request->get('with'))) {
// Apply any possible relation
$withs = [];
foreach ($this->request->get('with') as $with) {
$relations = explode('.', $with);
if (method_exists($this->model, $relations[0])) {
$withs[$with] = function ($query) {
$query->latest()->limit($this->itemsPerPage * 10);
};
}
}
if (! $query) {
// If sent a null query, just return withs array
return $withs;
}
// Apply with to query directly
$query->with($withs);
}
return $query ?? [];
}
/**
* Method to fully refresh the model instance and load all relations
*
* @param bool $loadRelations Flag to indicate if relations should be loaded
* @return Model|null
*/
protected function refreshModel($loadRelations = true)
{
// Load any withs we may have
$withs = $this->applyWiths();
// Refresh the model fully
$this->model->refresh();
$this->model->load($withs);
if (! $withs && $loadRelations) {
// If flag is set and no withs were sent on parameters
// load all needed relations
$this->model->load(array_keys($this->relations));
}
return $this->model;
}
/**
* Method to properly map out the proper operator of a
* query call
*
* @param string $string The string to map
* @return string
*/
protected function getOperator($string)
{
switch ($string) {
case self::SEARCH_OPERATORS['NQ']:
$operator = '<>';
break;
case self::SEARCH_OPERATORS['GT']:
$operator = '>';
break;
case self::SEARCH_OPERATORS['LT']:
$operator = '<';
break;
case self::SEARCH_OPERATORS['GTE']:
$operator = '>=';
break;
case self::SEARCH_OPERATORS['LTE']:
$operator = '<=';
break;
case self::SEARCH_OPERATORS['LIKE']:
$operator = 'like';
break;
case self::SEARCH_OPERATORS['EQ']:
default:
$operator = '=';
break;
}
return $operator;
}
/**
* Method to apply any needed ordering
*
* @param Builder $query The query being built
*/
protected function applyOrdering(Builder &$query)
{
if ($this->request->get('order') &&
is_array($this->request->get('order'))) {
// Apply any possible ordering
foreach ($this->request->get('order') as $attribute => $sort) {
$query->orderBy($attribute, $sort);
}
}
}
/**
* Method to apply all possible selects in the request to the query
*
* @param Builder $query The query being built
*/
protected function applySelects(Builder &$query)
{
$aggregate = [];
$selects = $this->request->get('select');
if ($this->request->get('sum')) {
$aggregate['field'] = $this->request->get('sum');
$aggregate['function'] = 'SUM';
} elseif ($this->request->get('count')) {
$aggregate['field'] = $this->request->get('count');
$aggregate['function'] = 'COUNT';
} elseif ($this->request->get('avg')) {
$aggregate['field'] = $this->request->get('avg');
$aggregate['function'] = 'AVG';
}
if (isset($aggregate['field']) && isset($aggregate['function'])) {
// Set flag to false as this won't need to return in a resource
$this->resourceCollection = false;
$this->aggregates = true;
if (strpos($aggregate['field'], "{$this->model->getTable()}.") === false) {
$alias = $aggregate['field'];
$aggregate['field'] = "{$this->model->getTable()}.{$aggregate['field']}";
} else {
$alias = explode('.', $aggregate['field']);
$alias = end($alias);
}
$rawSelect = DB::raw(
"{$aggregate['function']}({$aggregate['field']}) AS ".
"$alias"
);
if (is_array($selects)) {
$selects = array_merge([$rawSelect], $selects);
} else {
$selects[] = $rawSelect;
}
}
if ($selects) {
foreach ($selects as $key => $select) {
if (is_array($select)) {
// Make sure format is correct or skip it as it wont work
if (count($select) == 1 && is_string(end($select))) {
$selects[$key] = DB::raw(
key($select).'('.end($select).') AS '.
key($select).$key
);
} elseif (count($select) == 1 &&
key($select) == 'dateFormat' &&
isset($select['dateFormat']['field']) &&
isset($select['dateFormat']['format'])) {
$selects[$key] = DB::raw(
"DATE_FORMAT({$select['dateFormat']['field']}, ".
"\"{$select['dateFormat']['format']}\") AS ".
key($select).$key
);
} else {
// Continue, this format is not correct
continue;
}
} elseif (is_string($select)) {
$this->parseRelationalAttribute($select, $query);
$select = explode('.', $select);
if (count($select) > 2) {
$select = $select[count($select) - 2].'.'.
end($select);
} else {
$select = implode('.', $select);
}
$selects[$key] = $select;
}
}
$query->select($selects);
}
}
/**
* Method that will process the where data before it goes
* to the query builder
*
* @param array $data The data coming from the array in the query
* @param string $attribute The attribute being created
* @param Builder $query The query being created
* @return array
*/
protected function getWhereData($data, &$attribute, &$query)
{
// Parse the attribute
$this->parseRelationalAttribute($attribute, $query);
$whereData = [];
if (is_array($data)) {
$operator = $this->getOperator(key($data));
$value = end($data);
if (in_array($operator, self::WILDCARD_OPERATORS) &&
strpos($value, '%') === false) {
$value = "%{$value}%";
}
$whereData = [
'operator' => $this->getOperator(key($data)),
'value' => $value,
];
}
return $whereData;
}
/**
* Method to properly apply all wheres in the http query parameters
*
* @param Builder $query The query being built
*/
protected function applyWheres(Builder &$query)
{
if (($and = $this->request->get('and')) &&
is_array($this->request->get('and'))) {
$query->where(function ($query) use ($and) {
foreach ($and as $attribute => $ands) {
foreach ($ands as $data) {
if ($data = $this->getWhereData($data, $attribute, $query)) {
if (($relationalAttributes = explode('.', $attribute)) &&
count($relationalAttributes) > 1 &&
count(explode('_', $relationalAttributes[0])) == 1) {
$attributeName = array_pop($relationalAttributes);
$relationName = implode('.', $relationalAttributes);
if ($data['value'] == 'null') {
$query->whereHas($relationName, function ($query) use ($attributeName) {
$query->whereNull($attributeName);
});
} elseif ($data['value'] == 'notNull') {
$query->whereHas($relationName, function ($query) use ($attributeName) {
$query->whereNotNull($attributeName);
});
} else {
$query->whereHas($relationName, function ($query) use ($data, $attributeName) {
$query->where(
$attributeName,
$data['operator'],
$data['value']
);
});
}
} else {
if ($data['value'] == 'null') {
$query->whereNull($attribute);
} elseif ($data['value'] == 'notNull') {
$query->whereNotNull($attribute);
} else {
$query->where(
$attribute,
$data['operator'],
$data['value']
);
}
}
}
}
}
});
}
if (($or = $this->request->get('or')) &&
is_array($this->request->get('or'))) {
$query->where(function ($query) use ($or) {
foreach ($or as $attribute => $ors) {
foreach ($ors as $data) {
if ($data = $this->getWhereData($data, $attribute, $query)) {
$query->orWhere(
$attribute,
$data['operator'],
$data['value']
);
}
}
}
});
}
if (($in = $this->request->get('in')) &&
is_array($this->request->get('in'))) {
foreach ($this->request->get('in') as $attribute => $in) {
$query->whereIn($attribute, $in);
}
}
if (($date = $this->request->get('date')) &&
is_array($this->request->get('date'))) {
foreach ($date as $attribute => $dates) {
foreach ($dates as $operator => $value) {
$query->whereDate(
$attribute,
$this->getOperator($operator),
$value
);
}
}
}
}
/**
* Method to help apply any filters sent during a request
*
* @return Builder
*/
public function applyFilters(Builder $builder)
{
if ($this->filters) {
foreach ($this->filters as $query => $field) {
if (request()->has($query)) {
$builder->where($field, request()->get($query));
}
}
}
return $builder;
}
/**
* Method that will build needed groupings for the query
*/
protected function applyGrouping(Builder &$query)
{
if (($group = $this->request->get('group')) &&
is_array($this->request->get('group'))) {
foreach ($group as $attribute => $grouping) {
// Parse the attribute
$this->parseRelationalAttribute($attribute, $query);
if (is_array($grouping)) {
switch (key($grouping)) {
case 'month':
case 'year':
case 'day':
case 'hour':
case 'minute':
case 'week':
$attribute = DB::raw(key($grouping)."({$attribute})");
break;
}
}
// Add the grouping
$query->groupBy($attribute);
}
}
}
/**
* Method that will parse the attribute and check if there is a
* relation
*
* @param string $attribute The attribute to parse
* @param Builder $query The query being built
* @return bool
*/
protected function parseRelationalAttribute($attribute, Builder &$query)
{
$relationalAttributes = explode('.', $attribute);
if (count($relationalAttributes) > 1) {
// Pop out the last part as it is the field
array_pop($relationalAttributes);
foreach ($relationalAttributes as $key => $relationalAttribute) {
if ($key > 0) {
if (substr($relationalAttributes[$key - 1], -3, 3) == 'ies') {
$relationalAttributes[$key - 1] = str_replace(
'ies',
'y',
$relationalAttributes[$key - 1]
);
} elseif (substr($relationalAttributes[$key - 1], -1, 1) == 's') {
$relationalAttributes[$key - 1] = str_replace(
's',
'',
$relationalAttributes[$key - 1]
);
}
$externalModelParts = explode('_', $relationalAttributes[$key - 1]);
$externalModel = ucfirst(reset($externalModelParts));
array_shift($externalModelParts);
foreach ($externalModelParts as $externalModelPart) {
$externalModel .= ucfirst($externalModelPart);
}
$relations = $this->loadRelations('App\'.$externalModel);
} else {
$relations = $this->relations;
}
// Set the relation table
$relationAttribute = null;
$fromMethod = null;
foreach ($relations as $method => $relation) {
if ($relation['table'] == $relationalAttribute ||
$method == $relationalAttribute) {
if ($method == $relationalAttribute) {
$fromMethod = $method;
}
$relationAttribute = $relation;
break;
}
}
if ($relationAttribute['type'] == 'Custom') {
// Make sure we have joined the local key
$this->parseRelationalAttribute(
$relationAttribute['localKey'],
$query
);
}
if ($query->getQuery()->joins) {
foreach ($query->getQuery()->joins as $join) {
if ($join->table == $relationAttribute['table']) {
return false;
}
}
}
if ($relationAttribute) {
$table = $relationAttribute['table'];
$foreignKey = $relationAttribute['foreignKey'];
if ($fromMethod) {
$table .= " as {$fromMethod}";
$foreignKey = explode('.', $foreignKey);
$foreignKey = "{$fromMethod}.{$foreignKey[1]}";
}
// Add the relational attribute table to the query
$query->leftJoin(
$table,
$foreignKey,
'=',
$relationAttribute['localKey']
);
}
}
}
return true;
}
/**
* Method used to properly set the loaded resource to the response
*
* @param object $resource The resource to return in the response
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
*/
public function resource($resource)
{
if ($this->request->get('withDeleted') &&
$resource instanceof SoftDeletes) {
// If parameter set, make so we pull with deleted records
$resource->withTrashed();
}
if ($resource instanceof $this->model &&
method_exists($resource, 'getErrorMessages')) {
// Set any errors
$this->errorMessages = $resource->getErrorMessages();
$this->errors = $this->errorMessages;
}
if ($this->resourceCollection) {
$resource = $this->resource::collection(
$resource->paginate($this->itemsPerPage)
);
} else {
if ($this->aggregates || $resource->getQuery()->groups) {
$resource = collect(
DB::connection('mysql')->select(
$resource->toSql(),
$resource->getBindings()
)
);
} elseif (! ($resource instanceof $this->model)) {
$resource = $resource->first();
}
$resource = new $this->resource($resource);
}
return $this->resourceResponse($resource);
}
/**
* Resource wrapper to standardize responses
*
* @param resource $resource The resource to wrap
* @param int $status The http status code
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
*/
public function resourceResponse(JsonResource $resource, $status = 200)
{
// Catch the origin content array
// $originalContent = $resource->toResponse(Request::capture())->getOriginalContent();
$originalContent = (array)$resource->toResponse(Request::capture())->getData();
$request = $this->request ?? Request::capture();
if ($this->errorMessages) {
// Set the errors
$originalContent['error'] = $this->errorMessages;
}
$originalContentData = $originalContent;
if ($this->model &&
(method_exists($this->model, 'setDataAttribute') ||
in_array('data', $this->model->getFillable())) &&
isset($originalContentData['data'])) {
// If data is an attribute in the mode through getters or filters
// clear it out
unset($originalContentData['data']);
}
if (count($originalContent) == count($originalContent, COUNT_RECURSIVE) ||
! isset($originalContentData['data'])) {
if (isset($originalContent['data']) && ! $originalContent['data']) {
$originalContent = [];
}
// If the array is not recursive it means it merged the data wrapper wrong
// so we need to rewrap it
$originalContent = [
'data' => $originalContent,
'error' => $this->errorMessages ? $this->errorMessages->getMessages() : [],
];
// Clean the original content and do a final check
unset($originalContent['data']['links']);
unset($originalContent['data']['meta']);
if (isset($originalContent->data->data) &&
count($originalContent['data']) == 1) {
$originalContent['data'] = $originalContent->data->data;
}
if (isset($originalContentData['links'])) {
$originalContent['links'] = $originalContentData['links'];
}
if (isset($originalContentData['meta'])) {
$originalContent['meta'] = $originalContentData['meta'];
}
}
if (isset($originalContent['data']) &&
($request->method() == 'POST' ||
$request->method() == 'PATCH' ||
$request->method() == 'PUT')) {
// If this is a request that touched data, only load relations
// that has data to the response
$originalContent['data'] = collect($originalContent['data'])
->filter(function ($item, $attribute) {
if ((is_array($item) && ! $item) ||
($this->model &&
! in_array($attribute, $this->model->getFillable()) &&
$item === null)) {
return false;
}
return true;
})->toArray();
}
// Do a final check to make sure the data is properly set
if (isset($originalContent->data->data->id) ||
isset($originalContent->data->data[0]->id)) {
$originalContent['data'] = $originalContent->data->data;
}
$response = array_merge([
'success' => $this->errors ? false : true,
], $originalContent);
return response($response, $status);
}
/**
* The general response wrapper
*
* @param array $data The data that should be appended to response
* @param int $status The http status code of the response
* @return \Illuminate\Http\JsonResponse
*/
public function response($data = [], $status = 200)
{
if ($data instanceof Base) {
// If this is an instance of base, just make to an array
$data = $data->toArray();
} elseif ($this->model &&
method_exists($this->model, 'getErrorMessages')) {
// Set any errors
$this->errorMessages = $this->model->errorMessages;
$this->errors = $this->errorMessages->getMessages();
}
$json = [
'success' => $this->getErrors() ? false : true,
];
if ($this->errorMessages &&
($errors = $this->errorMessages->getMessages())) {
$json['error'] = $errors;
} elseif ($this->getErrors()) {
$json['error'] = $this->getErrors();
} elseif (empty($data)) {
$json['data'] = null;
} elseif (is_array($data) ||
is_object($data)) {
$json['data'] = $data;
}
// Clear errors after sending before sending response
$this->errors = [];
return response()->json($json, $status);
}
/**
* Fallback to process an existing model with simple update, query or
* delete
*
* @param Base $model The model to process
* @param int $id The id of the resource
* @param bool $delete Flag indicating if a delete should be done
* @param bool $query Flag indicating if only a query should be done
* @return bool|Base
*/
protected function processExistingModel(Base $model,
$id,
bool $delete = false,
bool $query = false)
{
if ($model = $model::find($id)) {
if (! $query) {
// Found the model, try to delete it or update it
return $delete ?
$model->delete() :
$this->processModel($model);
}
return $model;
}
$this->setError(
'The resource sent was not found',
1
);
return false;
}
/**
* Method that will get the results of models and paginate it
*
* @param Base $model The model to query for
* @param array $withs All the relations to load
* @param bool $asArray Flag indicating if the result should be
* returned as an array
* @return mixed
*/
protected function getResults(Base $model, $withs = [], $asArray = true)
{
// Load all possible query parameters
$filters = $model->getFillable();
// Set any possible sorting
$sort = request()->get('sort');
if (! in_array($sort, $filters)) {
$sort = 'updated_at';
}
$order = request()->get('order');
if (strtolower($order) != 'asc' &&
strtolower($order) != 'desc') {
$order = 'desc';
}
// Set the amount of items per page
$itemsPerPage = request()->get('itemsPerPage');
if (! $itemsPerPage ||
$itemsPerPage > $this->itemsPerPage) {
// We allow to set items per page, but we have a limit of 50
$itemsPerPage = $this->itemsPerPage;
}
$modelClass = get_class($model);
$query = $modelClass::with($withs)
->orderBy($sort, $order);
if (method_exists($model, 'entity') &&
$this->getAuthedUser()) {
$query->whereEntityId($this->entity->id);
}
foreach ($filters as $filter) {
if ($filterValue = request()->get($filter)) {
// For numbers always equal strings go for like
$operator = is_numeric($filterValue) ? '=' : 'LIKE';
$search = $operator == 'LIKE' ? "%{$filterValue}%" : $filterValue;
$query->where($filter, $operator, $search);
}
}
$results = $query->paginate($itemsPerPage);
return $asArray ? $results->toArray() : $results;
}
/**
* Get the current logged in user
*
* @return Entity
*/
protected function getAuthedUser()
{
return $this->entity = session('entity');
}
/**
* Fallback method created to get the new error format
* of the model and converted back to the old format
* (will be removed soon)
*
*
* @return Model|bool
*/
protected function processModel(Base $model)
{
// Fill in the model with data sent on the request
$model->fill(request()->json()->all());
if (in_array('entity_id', $model->getFillable()) &&
$this->getAuthedUser()) {
// Force the entity id to always be the logged in entity
$model->entity()->associate($this->entity);
}
if (! $model->save()) {
// Try to save, if it fails register any errors
if ($model->getErrorMessages()) {
$errors = 0;
foreach ($model->getErrorMessages() as $errorMessages) {
foreach ($errorMessages as $errorMessage) {
$this->setError($errorMessage, $errors);
$errors++;
}
}
}
// Failed to save the model, bail
return false;
}
// All went good, return the model
return $model;
}
/**
* Get validation parameters and process validations
*
* @param array $validations The array of validation rules
* @return bool
*/
protected function processValidations(array $validations)
{
$validation = Validator::make(
request()->json()->all(),
$validations
);
if ($validation->fails()) {
foreach ($validation->getMessageBag()->getMessages() as $errorMessages) {
$errors = 0;
foreach ($errorMessages as $errorMessage) {
$this->setError($errorMessage, $errors);
$errors++;
}
}
return false;
}
return true;
}
/**
* Method that will help get data from the request
*
* @param string $key The key go grab from the request
* @param string $method The method to use while looking for the
* key
* @return mixed
*/
protected function request($key = null,
$method = 'json')
{
$request = request();
if (method_exists(request(), $method)) {
$request = $request->$method();
}
return $key ? $request->get($key) : $request->all();
}
/**
* Method that will get all data from the method selected
*
* @param string $method The method to get all the data from
* @return array
*/
protected function requestAll($method = 'json')
{
return $this->request(null, $method);
}
...
}
Please or to participate in this conversation.