Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
All notable changes to this project will be documented in this file. This project adheres to
[Semantic Versioning](http://semver.org/) and [this changelog format](http://keepachangelog.com/).

## Unreleased

### Added
- [#315](https://github.com/cloudcreativity/laravel-json-api/issues/315)
Allow developers to use the exact JSON API field name as the relationship method name on their
adapters, plus for default conversion of names in include paths. Although we recommend following
the PSR1 standard of using camel case for method names, this does allow a developer to use snake
case field names with snake case method names.

## [1.0.1] - 2019-03-12

### Fixed
Expand Down
23 changes: 22 additions & 1 deletion src/Adapter/AbstractResourceAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,32 @@ protected function isFillableRelation($field, $record)
}

/**
* @param $field
* Get the method name on this adapter for the supplied JSON API field.
*
* By default we expect the developer to be following the PSR1 standard,
* so the method name on the adapter should use camel case.
*
* However, some developers may prefer to use the actual JSON API field
* name. E.g. they could use `user_history` as the JSON API field name
* and the method name.
*
* Therefore we return the field name if it exactly exists on the adapter,
* otherwise we camelize it.
*
* A developer can use completely different logic by overloading this
* method.
*
* @param string $field
* the JSON API field name.
* @return string|null
* the adapter's method name, or null if none is implemented.
*/
protected function methodForRelation($field)
{
if (method_exists($this, $field)) {
return $field;
}

$method = Str::camelize($field);

return method_exists($this, $method) ? $method : null;
Expand Down
3 changes: 2 additions & 1 deletion src/Eloquent/AbstractAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use CloudCreativity\LaravelJsonApi\Document\ResourceObject;
use CloudCreativity\LaravelJsonApi\Exceptions\RuntimeException;
use CloudCreativity\LaravelJsonApi\Pagination\CursorStrategy;
use CloudCreativity\LaravelJsonApi\Utils\Str;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations;
Expand Down Expand Up @@ -622,7 +623,7 @@ private function guessRelation()
{
list($one, $two, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);

return $caller['function'];
return $this->modelRelationForField($caller['function']);
}

}
40 changes: 39 additions & 1 deletion src/Eloquent/Concerns/IncludesModels.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ trait IncludesModels
*/
protected $includePaths = [];

/**
* Whether Eloquent relations are camel cased.
*
* @var bool
*/
protected $camelCaseRelations = true;

/**
* Add eager loading to the query.
*
Expand Down Expand Up @@ -145,7 +152,38 @@ protected function convertIncludePath($path)
}

return collect(explode('.', $path))->map(function ($segment) {
return Str::camelize($segment);
return $this->modelRelationForField($segment);
})->implode('.');
}

/**
* Convert a JSON API field name to an Eloquent model relation name.
*
* According to the PSR1 spec, method names on classes MUST be camel case.
* However, there seem to be some Laravel developers who snake case
* relationship methods on their models, so that the method name matches
* the snake case format of attributes (column values).
*
* The `$camelCaseRelations` property controls the behaviour of this
* conversion:
*
* - If `true`, a field name of `user-history` or `user_history` will
* expect the Eloquent model relation method to be `userHistory`.
* - If `false`, a field name of `user-history` or `user_history` will
* expect the Eloquent model relation method to be `user_history`. I.e.
* if PSR1 is not being followed, the best guess is that method names
* are snake case.
*
* If the developer has different conversion logic, they should overload
* this method and implement it themselves.
*
* @param string $field
* the JSON API field name.
* @return string
* the expected relation name on the Eloquent model.
*/
protected function modelRelationForField($field)
{
return $this->camelCaseRelations ? Str::camelize($field) : Str::underscore($field);
}
}