Completed
Push — master ( 5e287c...36811c )
by Alexander
03:40
created

SuccessResponseFactory::transformPivot()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Flugg\Responder\Factories;
4
5
use Flugg\Responder\Contracts\Manager;
6
use Flugg\Responder\Contracts\Transformable;
7
use Illuminate\Contracts\Pagination\LengthAwarePaginator as Paginator;
8
use Illuminate\Database\Eloquent\Builder;
9
use Illuminate\Database\Eloquent\Model;
10
use Illuminate\Database\Eloquent\Relations\Pivot;
11
use Illuminate\Http\JsonResponse;
12
use Illuminate\Support\Collection;
13
use InvalidArgumentException;
14
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
15
use League\Fractal\Resource\Collection as FractalCollection;
16
use League\Fractal\Resource\Item as FractalItem;
17
use League\Fractal\Resource\NullResource as FractalNull;
18
use League\Fractal\Resource\ResourceInterface;
19
20
/**
21
 *
22
 *
23
 * @package Laravel Responder
24
 * @author  Alexander Tømmerås <[email protected]>
25
 * @license The MIT License
26
 */
27
class SuccessResponseFactory extends ResponseFactory
28
{
29
    /**
30
     * Generate a successful JSON response.
31
     *
32
     * @param  mixed $data
33
     * @param  int   $statusCode
34
     * @param  array $meta
35
     * @return JsonResponse
36
     */
37
    public function make( $data = null, $statusCode = 200, $meta = [ ] ):JsonResponse
38
    {
39
        $resource = $this->transform( $data );
40
        $resource->setMeta( $meta );
41
42
        $data = $this->serialize( $resource );
43
        $data = $this->includeStatusCode( $statusCode, $data );
44
45
        return parent::make( $data, $statusCode );
46
    }
47
48
    /**
49
     * Transforms the data.
50
     *
51
     * @param  mixed $data
52
     * @param  mixed $transformer
53
     * @return ResourceInterface
54
     */
55
    public function transform( $data = null, $transformer = null ):ResourceInterface
56
    {
57
        if ( is_null( $data ) ) {
58
            return new FractalNull();
59
        }
60
61
        $transforms = [
62
            Transformable::class => 'transformModel',
63
            Collection::class => 'transformCollection',
64
            Builder::class => 'transformBuilder',
65
            Paginator::class => 'transformPaginator',
66
            Pivot::class => 'transformPivot'
67
        ];
68
69
        foreach ( $transforms as $class => $transform ) {
70
            if ( $data instanceof $class ) {
71
                return $this->$transform( $data, $transformer );
72
            }
73
        }
74
75
        throw new InvalidArgumentException( 'Data must be one or multiple models implementing the Transformable contract.' );
76
    }
77
78
    /**
79
     * Transform a transformable Eloquent model.
80
     *
81
     * @param  Model $model
82
     * @param  mixed $transformer
83
     * @return FractalItem
84
     */
85 View Code Duplication
    protected function transformModel( Model $model, $transformer = null ):FractalItem
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
86
    {
87
        $transformer = $transformer ?: $model::transformer();
88
89
        if ( is_null( $transformer ) ) {
90
            return new FractalItem( $model, function () use ( $model ) {
91
                return $model->toArray();
92
            } );
93
        }
94
95
        return $this->transformData( $model, new $transformer( $model ), $model->getTable() );
96
    }
97
98
    /**
99
     * Transform a collection of Eloquent models.
100
     *
101
     * @param  Collection $collection
102
     * @param  mixed      $transformer
103
     * @return FractalCollection
104
     */
105 View Code Duplication
    protected function transformCollection( Collection $collection, $transformer = null ):FractalCollection
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
    {
107
        $model = $this->resolveModel( $collection );
108
        $transformer = $transformer ?: $model::transformer();
109
110
        if ( is_null( $transformer ) ) {
111
            return new FractalCollection( $collection, function () use ( $collection ) {
112
                return $collection->toArray();
113
            } );
114
        }
115
116
        return $this->transformData( $collection, new $transformer( $model ), $model->getTable() );
117
    }
118
119
    /**
120
     * Transform an Eloquent builder.
121
     *
122
     * @param  Builder $query
123
     * @param  mixed   $transformer
124
     * @return FractalCollection
125
     */
126
    protected function transformBuilder( Builder $query, $transformer = null ):FractalCollection
127
    {
128
        return $this->transformCollection( $query->get(), $transformer );
129
    }
130
131
    /**
132
     * Transform paginated data using Laravel's paginator.
133
     *
134
     * @param  Paginator $paginator
135
     * @param  mixed     $transformer
136
     * @return FractalCollection
137
     */
138
    protected function transformPaginator( Paginator $paginator, $transformer = null ):FractalCollection
139
    {
140
        $resource = $this->transformCollection( $paginator->getCollection(), $transformer );
141
        $resource->setPaginator( new IlluminatePaginatorAdapter( $paginator ) );
142
143
        return $resource;
144
    }
145
146
    /**
147
     * Transform paginated data using Laravel's paginator.
148
     *
149
     * @param  Pivot $pivot
150
     * @param  mixed $transformer
151
     * @return ResourceInterface
152
     */
153
    protected function transformPivot( Pivot $pivot, $transformer = null ):ResourceInterface
154
    {
155
        return $this->transformData( $pivot, $transformer );
156
    }
157
158
    /**
159
     * Transform the data using the given transformer.
160
     *
161
     * @param  Transformable|Collection $data
162
     * @param  mixed                    $transformer
163
     * @param  string|null              $resourceKey
164
     * @return ResourceInterface
165
     */
166
    protected function transformData( $data, $transformer, string $resourceKey = null ):ResourceInterface
167
    {
168
        $class = $data instanceof Model ? FractalItem::class : FractalCollection::class;
169
        $resource = new $class( $data, $transformer );
170
171
        if ( is_string( $resourceKey ) ) {
172
            $resource->setResourceKey( $resourceKey );
173
        }
174
175
        return $resource;
176
    }
177
178
    /**
179
     * Serializes the data.
180
     *
181
     * @param  ResourceInterface $resource
182
     * @return array
183
     */
184
    protected function serialize( ResourceInterface $resource ):array
185
    {
186
        $manager = app( Manager::class );
187
188
        $data = $resource->getData();
189
        $model = $data instanceof Collection ? $this->resolveModel( $data ) : $data;
190
191
        if ( ! is_null( $data ) ) {
192
            $transformer = $model::transformer();
193
            $includes = is_string( $transformer ) ? ( new $transformer( $model ) )->getAvailableIncludes() : [ ];
194
            $manager = $manager->parseIncludes( $includes );
195
        }
196
197
        return $manager->createData( $resource )->toArray();
198
    }
199
200
    /**
201
     * Here we prepend a status code to the response data, if status code is enabled in
202
     * the configuration file.
203
     *
204
     * @param  int   $statusCode
205
     * @param  array $data
206
     * @return array
207
     */
208
    protected function includeStatusCode( int $statusCode, array $data ):array
209
    {
210
        if ( ! $this->includeStatusCode ) {
211
            return $data;
212
        }
213
214
        return array_merge( [
215
            'status' => $statusCode
216
        ], $data );
217
    }
218
219
    /**
220
     * Resolves model class path from a collection of models.
221
     *
222
     * @param  Collection $collection
223
     * @return Transformable
224
     * @throws InvalidArgumentException
225
     */
226
    protected function resolveModel( Collection $collection ):Transformable
227
    {
228
        $class = $collection->first();
229
230
        if ( ! $class instanceof Transformable ) {
231
            throw new InvalidArgumentException( 'Data must only contain models implementing the Transformable contract.' );
232
        }
233
234
        $collection->each( function ( $model ) use ( $class ) {
235
            if ( get_class( $model ) !== get_class( $class ) ) {
236
                throw new InvalidArgumentException( 'You cannot transform arrays or collections with multiple model types.' );
237
            }
238
        } );
239
240
        return $class;
241
    }
242
}