├── .styleci.yml ├── src ├── Exceptions │ ├── InvalidTransformation.php │ └── NoTransformerSpecified.php ├── ArraySerializer.php └── Fractal.php ├── .editorconfig ├── UPGRADE.md ├── CHANGELOG.md ├── LICENSE.md ├── composer.json ├── CONTRIBUTING.md └── README.md /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel 2 | 3 | linting: true 4 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidTransformation.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/fractalistic", 3 | "description": "A developer friendly wrapper around Fractal", 4 | "keywords": [ 5 | "spatie", 6 | "fractalistic", 7 | "fractal", 8 | "api", 9 | "transform" 10 | ], 11 | "homepage": "https://github.com/spatie/fractalistic", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Freek Van der Herten", 16 | "email": "freek@spatie.be", 17 | "homepage": "https://spatie.be", 18 | "role": "Developer" 19 | } 20 | ], 21 | "require": { 22 | "php": "^5.6|^7.0", 23 | "league/fractal": "^0.17.0" 24 | }, 25 | "require-dev": { 26 | "illuminate/pagination": "~5.3.0|~5.4.0", 27 | "phpunit/phpunit" : "^5.7.21" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Spatie\\Fractalistic\\": "src" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Spatie\\Fractalistic\\Test\\": "tests" 37 | } 38 | }, 39 | "scripts": { 40 | "test": "phpunit" 41 | }, 42 | "config": { 43 | "sort-packages": true 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/spatie/fractalistic). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ phpunit 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A developer friendly wrapper around Fractal 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/fractalistic.svg?style=flat-square)](https://packagist.org/packages/spatie/fractalistic) 4 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 5 | [![Build Status](https://travis-ci.org/spatie/fractalistic.svg?branch=master)](https://travis-ci.org/spatie/fractalistic) 6 | [![Quality Score](https://img.shields.io/scrutinizer/g/spatie/fractalistic.svg?style=flat-square)](https://scrutinizer-ci.com/g/spatie/fractalistic) 7 | [![StyleCI](https://styleci.io/repos/76027929/shield?branch=master)](https://styleci.io/repos/76027929) 8 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/fractalistic.svg?style=flat-square)](https://packagist.org/packages/spatie/fractalistic) 9 | 10 | [Fractal](http://fractal.thephpleague.com/) is an amazing package to transform data before using it in an API. Unfortunately working with Fractal can be a bit verbose. 11 | 12 | Using Fractal data can be transformed like this: 13 | 14 | ```php 15 | use League\Fractal\Manager; 16 | use League\Fractal\Resource\Collection; 17 | 18 | $books = [ 19 | ['id'=>1, 'title'=>'Hogfather', 'characters' => [...]], 20 | ['id'=>2, 'title'=>'Game Of Kill Everyone', 'characters' => [...]] 21 | ]; 22 | 23 | $manager = new Manager(); 24 | 25 | $resource = new Collection($books, new BookTransformer()); 26 | 27 | $manager->parseIncludes('characters'); 28 | 29 | $manager->createData($resource)->toArray(); 30 | ``` 31 | 32 | This package makes that process a tad easier: 33 | 34 | ```php 35 | Fractal::create() 36 | ->collection($books) 37 | ->transformWith(new BookTransformer()) 38 | ->includeCharacters() 39 | ->toArray(); 40 | ``` 41 | 42 | There's also a very short syntax available to quickly transform data: 43 | 44 | ```php 45 | Fractal::create($books, new BookTransformer())->toArray(); 46 | ``` 47 | 48 | If you want to use this package inside Laravel, it's recommend to use [laravel-fractal](https://github.com/spatie/laravel-fractal) instead. That package contains a few more whistles and bells specifically targetted at Laravel users. 49 | 50 | 51 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all 52 | our open source projects [on our website](https://spatie.be/opensource). 53 | 54 | ## Postcardware 55 | 56 | You're free to use this package (it's [MIT-licensed](LICENSE.md)), but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. 57 | 58 | Our address is: Spatie, Samberstraat 69D, 2060 Antwerp, Belgium. 59 | 60 | All postcards we receive are published [on our website](https://spatie.be/en/opensource/postcards). 61 | 62 | ## Install 63 | 64 | You can pull in the package via composer: 65 | 66 | ``` bash 67 | composer require spatie/fractalistic 68 | ``` 69 | 70 | ## Usage 71 | 72 | In the following examples were going to use the following array as example input: 73 | 74 | ```php 75 | $books = [['id'=>1, 'title'=>'Hogfather'], ['id'=>2, 'title'=>'Game Of Kill Everyone']]; 76 | ``` 77 | 78 | But know that any structure that can be looped (for instance a collection) can be used. 79 | 80 | Let's start with a simple transformation. 81 | 82 | ```php 83 | Spatie\Fractalistic\Fractal::create() 84 | ->collection($books) 85 | ->transformWith(function($book) { return ['id' => $book['id']];}) 86 | ->toArray(); 87 | ``` 88 | 89 | This will return: 90 | ```php 91 | ['data' => [['id' => 1], ['id' => 2]] 92 | ``` 93 | 94 | In all following examples it's assumed that you imported the `Spatie\Fractalistic\Fractal` at the top of your php file. 95 | 96 | Instead of using a closure you can also pass [a Transformer](http://fractal.thephpleague.com/transformers/): 97 | 98 | ```php 99 | Fractal::create() 100 | ->collection($books) 101 | ->transformWith(new BookTransformer()) 102 | ->toArray(); 103 | ``` 104 | 105 | You can also pass the classname of the Transformer: 106 | 107 | ```php 108 | Fractal::create() 109 | ->collection($books) 110 | ->transformWith(BookTransformer::class) 111 | ->toArray(); 112 | ``` 113 | 114 | To make your code a bit shorter you could also pass the transform closure, class, or classname as a 115 | second parameter of the `collection`-method: 116 | 117 | ```php 118 | Fractal::create()->collection($books, new BookTransformer())->toArray(); 119 | ``` 120 | 121 | Want to get some sweet json output instead of an array? No problem! 122 | ```php 123 | Fractal::create()->collection($books, new BookTransformer())->toJson(); 124 | ``` 125 | 126 | A single item can also be transformed: 127 | ```php 128 | Fractal::create()->item($books[0], new BookTransformer())->toArray(); 129 | ``` 130 | 131 | ## Using a serializer 132 | 133 | Let's take a look again at the output of the first example: 134 | 135 | ```php 136 | ['data' => [['id' => 1], ['id' => 2]]; 137 | ``` 138 | 139 | Notice that `data`-key? That's part of Fractal's default behaviour. Take a look at 140 | [Fractals's documentation on serializers](http://fractal.thephpleague.com/serializers/) to find out why that happens. 141 | 142 | If you want to use another serializer you can specify one with the `serializeWith`-method. 143 | The `Spatie\Fractalistic\ArraySerializer` comes out of the box. It removes the `data` namespace for 144 | both collections and items. 145 | 146 | ```php 147 | Fractal::create() 148 | ->collection($books) 149 | ->transformWith(function($book) { return ['id' => $book['id']];}) 150 | ->serializeWith(new \Spatie\Fractalistic\ArraySerializer()) 151 | ->toArray(); 152 | 153 | //returns [['id' => 1], ['id' => 2]] 154 | ``` 155 | 156 | You can also pass the serializer classname instead of an instantiation: 157 | 158 | ```php 159 | Fractal::create() 160 | ->collection($books) 161 | ->transformWith(BookTransformer::class) 162 | ->serializeWith(MySerializer::class) 163 | ->toArray(); 164 | ``` 165 | 166 | 167 | ### Changing the default serializer 168 | 169 | You can change the default serializer by providing the classname or an instantiation of your favorite serializer in 170 | the config file. 171 | 172 | ## Using includes 173 | 174 | Fractal provides support for [optionally including data](http://fractal.thephpleague.com/transformers/) on the relationships for 175 | the data you're exporting. You can use Fractal's `parseIncludes` which accepts a string or an array: 176 | 177 | ```php 178 | Fractal::create() 179 | ->collection($this->testBooks, new TestTransformer()) 180 | ->parseIncludes(['characters', 'publisher']) 181 | ->toArray(); 182 | ``` 183 | 184 | To improve readablity you can also use a function named `include` followed by the name 185 | of the include you want to... include: 186 | 187 | ```php 188 | Fractal::create() 189 | ->collection($this->testBooks, new TestTransformer()) 190 | ->includeCharacters() 191 | ->includePublisher() 192 | ->toArray(); 193 | ``` 194 | 195 | ## Using excludes 196 | 197 | Similar to includes Fractal also provides support for [optionally excluding data](http://fractal.thephpleague.com/transformers/) on the relationships for 198 | the data you're exporting. You can use Fractal's `parseExcludes` which accepts a string or an array: 199 | 200 | ```php 201 | Fractal::create() 202 | ->collection($this->testBooks, new TestTransformer()) 203 | ->parseExcludes(['characters', 'publisher']) 204 | ->toArray(); 205 | ``` 206 | 207 | To improve readability you can also use a function named `exclude` followed by the name 208 | of the include you want to... exclude: 209 | 210 | ```php 211 | Fractal::create() 212 | ->collection($this->testBooks, new TestTransformer()) 213 | ->excludeCharacters() 214 | ->excludePublisher() 215 | ->toArray(); 216 | ``` 217 | 218 | ## Including meta data 219 | 220 | Fractal has support for including meta data. You can use `addMeta` which accepts 221 | one or more arrays: 222 | 223 | ```php 224 | Fractal::create() 225 | ->collection($this->testBooks, function($book) { return ['name' => $book['name']];}) 226 | ->addMeta(['key1' => 'value1'], ['key2' => 'value2']) 227 | ->toArray(); 228 | ``` 229 | 230 | This will return the following array: 231 | 232 | ```php 233 | [ 234 | 'data' => [ 235 | ['title' => 'Hogfather'], 236 | ['title' => 'Game Of Kill Everyone'], 237 | ], 238 | 'meta' => [ 239 | ['key1' => 'value1'], 240 | ['key2' => 'value2'], 241 | ] 242 | ]; 243 | ``` 244 | 245 | ## Using pagination 246 | 247 | Fractal provides a Laravel-specific paginator, `IlluminatePaginatorAdapter`, which accepts an instance of Laravel's `LengthAwarePaginator` 248 | and works with paginated Eloquent results. When using some serializers, such as the `JsonApiSerializer`, pagination data can be 249 | automatically generated and included in the result set: 250 | 251 | ```php 252 | $paginator = Book::paginate(5); 253 | $books = $paginator->getCollection(); 254 | 255 | Fractal::create() 256 | ->collection($books, new TestTransformer()) 257 | ->serializeWith(new JsonApiSerializer()) 258 | ->paginateWith(new IlluminatePaginatorAdapter($paginator)) 259 | ->toArray(); 260 | ``` 261 | 262 | ## Using a cursor 263 | 264 | Fractal provides a simple cursor class, `League\Fractal\Pagination\Cursor`. You can use any other cursor class as long as it implements the `League\Fractal\Pagination\CursorInterface` interface. When using it, the cursor information will be automatically included in the result metadata: 265 | 266 | ```php 267 | $books = $paginator->getCollection(); 268 | 269 | $currentCursor = 0; 270 | $previousCursor = null; 271 | $count = count($books); 272 | $newCursor = $currentCursor + $count; 273 | 274 | Fractal::create() 275 | ->collection($books, new TestTransformer()) 276 | ->serializeWith(new JsonApiSerializer()) 277 | ->withCursor(new Cursor($currentCursor, $previousCursor, $newCursor, $count)) 278 | ->toArray(); 279 | ``` 280 | 281 | ## Setting a custom resource name 282 | 283 | Certain serializers wrap the array output with a `data` element. The name of this element can be customized: 284 | 285 | ```php 286 | Fractal::create() 287 | ->collection($this->testBooks, new TestTransformer()) 288 | ->serializeWith(new ArraySerializer()) 289 | ->withResourceName('books') 290 | ->toArray(); 291 | ``` 292 | 293 | ```php 294 | Fractal::create() 295 | ->item($this->testBooks[0], new TestTransformer(), 'book') 296 | ->serializeWith(new ArraySerializer()) 297 | ->toArray(); 298 | ``` 299 | 300 | ## Limit recursion 301 | 302 | To increase or decrease the level of embedded includes you can use `limitRecursion`. 303 | 304 | ```php 305 | Fractal::create() 306 | ->collection($this->testBooks, new TestTransformer()) 307 | ->includesDataThatHasALotOfRecursion 308 | ->limitRecursion(5); 309 | ``` 310 | 311 | If you do not call `limitRecursion` a default value of 10 is used. 312 | 313 | ## Quickly transform data with the short function syntax 314 | 315 | You can also pass arguments to the `fractal`-function itself. The first arguments should be the data you which to transform. The second one should be a transformer or a `closure` that will be used to transform the data. The third one should be a serializer. 316 | 317 | Here are some examples 318 | 319 | ```php 320 | Fractal::create($books, new BookTransformer())->toArray(); 321 | 322 | Fractal::create($books, new BookTransformer(), new ArraySerializer())->toArray(); 323 | 324 | Fractal::create($books, BookTransformer::class, ArraySerializer::class)->toArray(); 325 | 326 | Fractal::create(['item1', 'item2'], function ($item) { 327 | return $item . '-transformed'; 328 | })->toArray(); 329 | ``` 330 | 331 | ## Change log 332 | 333 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 334 | 335 | ## Testing 336 | 337 | ``` bash 338 | $ composer test 339 | ``` 340 | 341 | ## Contributing 342 | 343 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 344 | 345 | ## Security 346 | 347 | If you discover any security related issues, please email freek@spatie.be instead of using the issue tracker. 348 | 349 | ## Credits 350 | 351 | - [Freek Van der Herten](https://twitter.com/freekmurze) 352 | - [All contributors](../../contributors) 353 | 354 | ## About Spatie 355 | Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects [on our website](https://spatie.be/opensource). 356 | 357 | ## License 358 | 359 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 360 | -------------------------------------------------------------------------------- /src/Fractal.php: -------------------------------------------------------------------------------- 1 | data = $data; 66 | $instance->dataType = $instance->determineDataType($data); 67 | $instance->transformer = $transformer ?: null; 68 | $instance->serializer = $serializer ?: null; 69 | 70 | return $instance; 71 | } 72 | 73 | /** @param \League\Fractal\Manager $manager */ 74 | public function __construct(Manager $manager) 75 | { 76 | $this->manager = $manager; 77 | } 78 | 79 | /** 80 | * Set the collection data that must be transformed. 81 | * 82 | * @param mixed $data 83 | * @param null|string|callable|\League\Fractal\TransformerAbstract $transformer 84 | * @param null|string $resourceName 85 | * 86 | * @return $this 87 | */ 88 | public function collection($data, $transformer = null, $resourceName = null) 89 | { 90 | if (! is_null($resourceName)) { 91 | $this->resourceName = $resourceName; 92 | } 93 | 94 | return $this->data('collection', $data, $transformer); 95 | } 96 | 97 | /** 98 | * Set the item data that must be transformed. 99 | * 100 | * @param mixed $data 101 | * @param null|string|callable|\League\Fractal\TransformerAbstract $transformer 102 | * @param null|string $resourceName 103 | * 104 | * @return $this 105 | */ 106 | public function item($data, $transformer = null, $resourceName = null) 107 | { 108 | if (! is_null($resourceName)) { 109 | $this->resourceName = $resourceName; 110 | } 111 | 112 | return $this->data('item', $data, $transformer); 113 | } 114 | 115 | /** 116 | * Set the data that must be transformed. 117 | * 118 | * @param string $dataType 119 | * @param mixed $data 120 | * @param null|string|callable|\League\Fractal\TransformerAbstract $transformer 121 | * 122 | * @return $this 123 | */ 124 | public function data($dataType, $data, $transformer = null) 125 | { 126 | $this->dataType = $dataType; 127 | 128 | $this->data = $data; 129 | 130 | if (! is_null($transformer)) { 131 | $this->transformer = $transformer; 132 | } 133 | 134 | return $this; 135 | } 136 | 137 | /** 138 | * @param mixed $data 139 | * 140 | * @return string 141 | */ 142 | protected function determineDataType($data) 143 | { 144 | if (is_null($data)) { 145 | return 'NullResource'; 146 | } 147 | 148 | if (is_array($data)) { 149 | return 'collection'; 150 | } 151 | 152 | if ($data instanceof Traversable) { 153 | return 'collection'; 154 | } 155 | 156 | return 'item'; 157 | } 158 | 159 | /** 160 | * Set the class or function that will perform the transform. 161 | * 162 | * @param string|callable|\League\Fractal\TransformerAbstract $transformer 163 | * 164 | * @return $this 165 | */ 166 | public function transformWith($transformer) 167 | { 168 | $this->transformer = $transformer; 169 | 170 | return $this; 171 | } 172 | 173 | /** 174 | * Set the serializer to be used. 175 | * 176 | * @param string|\League\Fractal\Serializer\SerializerAbstract $serializer 177 | * 178 | * @return $this 179 | */ 180 | public function serializeWith($serializer) 181 | { 182 | $this->serializer = $serializer; 183 | 184 | return $this; 185 | } 186 | 187 | /** 188 | * Set a Fractal paginator for the data. 189 | * 190 | * @param \League\Fractal\Pagination\PaginatorInterface $paginator 191 | * 192 | * @return $this 193 | */ 194 | public function paginateWith(PaginatorInterface $paginator) 195 | { 196 | $this->paginator = $paginator; 197 | 198 | return $this; 199 | } 200 | 201 | /** 202 | * Set a Fractal cursor for the data. 203 | * 204 | * @param \League\Fractal\Pagination\CursorInterface $cursor 205 | * 206 | * @return $this 207 | */ 208 | public function withCursor(CursorInterface $cursor) 209 | { 210 | $this->cursor = $cursor; 211 | 212 | return $this; 213 | } 214 | 215 | /** 216 | * Specify the includes. 217 | * 218 | * @param array|string $includes Array or string of resources to include. 219 | * 220 | * @return $this 221 | */ 222 | public function parseIncludes($includes) 223 | { 224 | $includes = $this->normalizeIncludesOrExcludes($includes); 225 | 226 | $this->includes = array_merge($this->includes, (array) $includes); 227 | 228 | return $this; 229 | } 230 | 231 | /** 232 | * Specify the excludes. 233 | * 234 | * @param array|string $excludes Array or string of resources to exclude. 235 | * 236 | * @return $this 237 | */ 238 | public function parseExcludes($excludes) 239 | { 240 | $excludes = $this->normalizeIncludesOrExcludes($excludes); 241 | 242 | $this->excludes = array_merge($this->excludes, (array) $excludes); 243 | 244 | return $this; 245 | } 246 | 247 | /** 248 | * Specify the fieldsets to include in the response. 249 | * 250 | * @param array $fieldsets array with key = resourceName and value = fields to include 251 | * (array or comma separated string with field names) 252 | * 253 | * @return $this 254 | */ 255 | public function parseFieldsets(array $fieldsets) 256 | { 257 | foreach ($fieldsets as $key => $fields) { 258 | if (is_array($fields)) { 259 | $fieldsets[$key] = implode(',', $fields); 260 | } 261 | } 262 | 263 | $this->fieldsets = array_merge($this->fieldsets, $fieldsets); 264 | 265 | return $this; 266 | } 267 | 268 | /** 269 | * Normalize the includes an excludes. 270 | * 271 | * @param array|string $includesOrExcludes 272 | * 273 | * @return array|string 274 | */ 275 | protected function normalizeIncludesOrExcludes($includesOrExcludes = '') 276 | { 277 | if (! is_string($includesOrExcludes)) { 278 | return $includesOrExcludes; 279 | } 280 | 281 | return array_map(function ($value) { 282 | return trim($value); 283 | }, explode(',', $includesOrExcludes)); 284 | } 285 | 286 | /** 287 | * Set the meta data. 288 | * 289 | * @param $array,... 290 | * 291 | * @return $this 292 | */ 293 | public function addMeta() 294 | { 295 | foreach (func_get_args() as $meta) { 296 | if (is_array($meta)) { 297 | $this->meta += $meta; 298 | } 299 | } 300 | 301 | return $this; 302 | } 303 | 304 | /** 305 | * Set the resource name, to replace 'data' as the root of the collection or item. 306 | * 307 | * @param string $resourceName 308 | * 309 | * @return $this 310 | */ 311 | public function withResourceName($resourceName) 312 | { 313 | $this->resourceName = $resourceName; 314 | 315 | return $this; 316 | } 317 | 318 | /** 319 | * Upper limit to how many levels of included data are allowed. 320 | * 321 | * @param int $recursionLimit 322 | * 323 | * @return $this 324 | */ 325 | public function limitRecursion(int $recursionLimit) 326 | { 327 | $this->recursionLimit = $recursionLimit; 328 | 329 | return $this; 330 | } 331 | 332 | /** 333 | * Perform the transformation to json. 334 | * 335 | * @param int $options 336 | * 337 | * @return string 338 | */ 339 | public function toJson($options = 0) 340 | { 341 | return $this->createData()->toJson($options); 342 | } 343 | 344 | /** 345 | * Perform the transformation to array. 346 | * 347 | * @return array 348 | */ 349 | public function toArray() 350 | { 351 | return $this->createData()->toArray(); 352 | } 353 | 354 | /** 355 | * Create fractal data. 356 | * 357 | * @return \League\Fractal\Scope 358 | * 359 | * @throws \Spatie\Fractalistic\Exceptions\InvalidTransformation 360 | * @throws \Spatie\Fractalistic\Exceptions\NoTransformerSpecified 361 | */ 362 | public function createData() 363 | { 364 | if (is_null($this->transformer)) { 365 | throw new NoTransformerSpecified(); 366 | } 367 | 368 | if (is_string($this->serializer)) { 369 | $this->serializer = new $this->serializer; 370 | } 371 | 372 | if (! is_null($this->serializer)) { 373 | $this->manager->setSerializer($this->serializer); 374 | } 375 | 376 | $this->manager->setRecursionLimit($this->recursionLimit); 377 | 378 | if (! empty($this->includes)) { 379 | $this->manager->parseIncludes($this->includes); 380 | } 381 | 382 | if (! empty($this->excludes)) { 383 | $this->manager->parseExcludes($this->excludes); 384 | } 385 | 386 | if (! empty($this->fieldsets)) { 387 | $this->manager->parseFieldsets($this->fieldsets); 388 | } 389 | 390 | return $this->manager->createData($this->getResource()); 391 | } 392 | 393 | /** 394 | * Get the resource. 395 | * 396 | * @return \League\Fractal\Resource\ResourceInterface 397 | * 398 | * @throws \Spatie\Fractalistic\Exceptions\InvalidTransformation 399 | */ 400 | public function getResource() 401 | { 402 | $resourceClass = 'League\\Fractal\\Resource\\'.ucfirst($this->dataType); 403 | 404 | if (! class_exists($resourceClass)) { 405 | throw new InvalidTransformation(); 406 | } 407 | 408 | if (is_string($this->transformer)) { 409 | $this->transformer = new $this->transformer; 410 | } 411 | 412 | $resource = new $resourceClass($this->data, $this->transformer, $this->resourceName); 413 | 414 | $resource->setMeta($this->meta); 415 | 416 | if (! is_null($this->paginator)) { 417 | $resource->setPaginator($this->paginator); 418 | } 419 | 420 | if (! is_null($this->cursor)) { 421 | $resource->setCursor($this->cursor); 422 | } 423 | 424 | return $resource; 425 | } 426 | 427 | /** 428 | * Convert the object into something JSON serializable. 429 | */ 430 | public function jsonSerialize() 431 | { 432 | return $this->toArray(); 433 | } 434 | 435 | /** 436 | * Support for magic methods to included data. 437 | * 438 | * @param string $name 439 | * @param array $arguments 440 | * 441 | * @return $this 442 | */ 443 | public function __call($name, array $arguments) 444 | { 445 | if ($this->startsWith($name, ['include'])) { 446 | $includeName = lcfirst(substr($name, strlen('include'))); 447 | 448 | return $this->parseIncludes($includeName); 449 | } 450 | 451 | if ($this->startsWith($name, ['exclude'])) { 452 | $excludeName = lcfirst(substr($name, strlen('exclude'))); 453 | 454 | return $this->parseExcludes($excludeName); 455 | } 456 | 457 | trigger_error('Call to undefined method '.__CLASS__.'::'.$name.'()', E_USER_ERROR); 458 | } 459 | 460 | /** 461 | * Determine if a given string starts with a given substring. 462 | * 463 | * @param string $haystack 464 | * @param string|array $needles 465 | * 466 | * @return bool 467 | */ 468 | protected function startsWith($haystack, $needles) 469 | { 470 | foreach ((array) $needles as $needle) { 471 | if ($needle != '' && substr($haystack, 0, strlen($needle)) === (string) $needle) { 472 | return true; 473 | } 474 | } 475 | 476 | return false; 477 | } 478 | } 479 | --------------------------------------------------------------------------------