Skip to content

Commit bef8dd9

Browse files
Merge pull request #326 from cloudcreativity/issue315
[Feature] Allow snake case relation names
2 parents 19893c4 + 66053e4 commit bef8dd9

File tree

4 files changed

+72
-3
lines changed

4 files changed

+72
-3
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
All notable changes to this project will be documented in this file. This project adheres to
33
[Semantic Versioning](http://semver.org/) and [this changelog format](http://keepachangelog.com/).
44

5+
## Unreleased
6+
7+
### Added
8+
- [#315](https://github.com/cloudcreativity/laravel-json-api/issues/315)
9+
Allow developers to use the exact JSON API field name as the relationship method name on their
10+
adapters, plus for default conversion of names in include paths. Although we recommend following
11+
the PSR1 standard of using camel case for method names, this does allow a developer to use snake
12+
case field names with snake case method names.
13+
514
## [1.0.1] - 2019-03-12
615

716
### Fixed

src/Adapter/AbstractResourceAdapter.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,32 @@ protected function isFillableRelation($field, $record)
197197
}
198198

199199
/**
200-
* @param $field
200+
* Get the method name on this adapter for the supplied JSON API field.
201+
*
202+
* By default we expect the developer to be following the PSR1 standard,
203+
* so the method name on the adapter should use camel case.
204+
*
205+
* However, some developers may prefer to use the actual JSON API field
206+
* name. E.g. they could use `user_history` as the JSON API field name
207+
* and the method name.
208+
*
209+
* Therefore we return the field name if it exactly exists on the adapter,
210+
* otherwise we camelize it.
211+
*
212+
* A developer can use completely different logic by overloading this
213+
* method.
214+
*
215+
* @param string $field
216+
* the JSON API field name.
201217
* @return string|null
218+
* the adapter's method name, or null if none is implemented.
202219
*/
203220
protected function methodForRelation($field)
204221
{
222+
if (method_exists($this, $field)) {
223+
return $field;
224+
}
225+
205226
$method = Str::camelize($field);
206227

207228
return method_exists($this, $method) ? $method : null;

src/Eloquent/AbstractAdapter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use CloudCreativity\LaravelJsonApi\Document\ResourceObject;
2727
use CloudCreativity\LaravelJsonApi\Exceptions\RuntimeException;
2828
use CloudCreativity\LaravelJsonApi\Pagination\CursorStrategy;
29+
use CloudCreativity\LaravelJsonApi\Utils\Str;
2930
use Illuminate\Database\Eloquent\Builder;
3031
use Illuminate\Database\Eloquent\Model;
3132
use Illuminate\Database\Eloquent\Relations;
@@ -622,7 +623,7 @@ private function guessRelation()
622623
{
623624
list($one, $two, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
624625

625-
return $caller['function'];
626+
return $this->modelRelationForField($caller['function']);
626627
}
627628

628629
}

src/Eloquent/Concerns/IncludesModels.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ trait IncludesModels
7979
*/
8080
protected $includePaths = [];
8181

82+
/**
83+
* Whether Eloquent relations are camel cased.
84+
*
85+
* @var bool
86+
*/
87+
protected $camelCaseRelations = true;
88+
8289
/**
8390
* Add eager loading to the query.
8491
*
@@ -145,7 +152,38 @@ protected function convertIncludePath($path)
145152
}
146153

147154
return collect(explode('.', $path))->map(function ($segment) {
148-
return Str::camelize($segment);
155+
return $this->modelRelationForField($segment);
149156
})->implode('.');
150157
}
158+
159+
/**
160+
* Convert a JSON API field name to an Eloquent model relation name.
161+
*
162+
* According to the PSR1 spec, method names on classes MUST be camel case.
163+
* However, there seem to be some Laravel developers who snake case
164+
* relationship methods on their models, so that the method name matches
165+
* the snake case format of attributes (column values).
166+
*
167+
* The `$camelCaseRelations` property controls the behaviour of this
168+
* conversion:
169+
*
170+
* - If `true`, a field name of `user-history` or `user_history` will
171+
* expect the Eloquent model relation method to be `userHistory`.
172+
* - If `false`, a field name of `user-history` or `user_history` will
173+
* expect the Eloquent model relation method to be `user_history`. I.e.
174+
* if PSR1 is not being followed, the best guess is that method names
175+
* are snake case.
176+
*
177+
* If the developer has different conversion logic, they should overload
178+
* this method and implement it themselves.
179+
*
180+
* @param string $field
181+
* the JSON API field name.
182+
* @return string
183+
* the expected relation name on the Eloquent model.
184+
*/
185+
protected function modelRelationForField($field)
186+
{
187+
return $this->camelCaseRelations ? Str::camelize($field) : Str::underscore($field);
188+
}
151189
}

0 commit comments

Comments
 (0)