Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
15 | trait MakesApiRequests |
||
16 | { |
||
17 | /** |
||
18 | * Assert that the response is a valid success response. |
||
19 | * |
||
20 | * @param mixed $data |
||
21 | * @param int $status |
||
22 | * @return $this |
||
23 | */ |
||
24 | View Code Duplication | protected function seeSuccess($data = null, $status = 200) |
|
|
|||
25 | { |
||
26 | $response = $this->seeSuccessResponse($data, $status); |
||
27 | $this->seeSuccessData($response->getData(true)['data']); |
||
28 | |||
29 | return $this; |
||
30 | } |
||
31 | |||
32 | /** |
||
33 | * Assert that the response is a valid success response. |
||
34 | * |
||
35 | * @param mixed $data |
||
36 | * @param int $status |
||
37 | * @return $this |
||
38 | */ |
||
39 | View Code Duplication | protected function seeSuccessEquals($data = null, $status = 200) |
|
40 | { |
||
41 | $response = $this->seeSuccessResponse($data, $status); |
||
42 | $this->seeJsonEquals($response->getData(true)); |
||
43 | |||
44 | return $this; |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * Assert that the response data contains the given structure. |
||
49 | * |
||
50 | * @param mixed $data |
||
51 | * @return $this |
||
52 | */ |
||
53 | protected function seeSuccessStructure($data = null) |
||
54 | { |
||
55 | $this->seeJsonStructure([ |
||
56 | 'data' => $data, |
||
57 | ]); |
||
58 | |||
59 | return $this; |
||
60 | } |
||
61 | |||
62 | /** |
||
63 | * Assert that the response is a valid success response. |
||
64 | * |
||
65 | * @param mixed $data |
||
66 | * @param int $status |
||
67 | * @return \Illuminate\Http\JsonResponse |
||
68 | */ |
||
69 | protected function seeSuccessResponse($data = null, $status = 200): JsonResponse |
||
70 | { |
||
71 | $response = $this->app->make(Responder::class)->success($data, $status); |
||
72 | |||
73 | $this->seeStatusCode($response->getStatusCode())->seeJson([ |
||
74 | 'success' => true, |
||
75 | 'status' => $response->getStatusCode(), |
||
76 | ])->seeJsonStructure(['data']); |
||
77 | |||
78 | return $response; |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Assert that the response data contains given values. |
||
83 | * |
||
84 | * @param mixed $data |
||
85 | * @return $this |
||
86 | */ |
||
87 | protected function seeSuccessData($data = null) |
||
88 | { |
||
89 | collect($data)->each(function ($value, $key) { |
||
90 | if (is_array($value)) { |
||
91 | $this->seeSuccessData($value); |
||
92 | } else { |
||
93 | $this->seeJson([$key => $value]); |
||
94 | } |
||
95 | }); |
||
96 | |||
97 | return $this; |
||
98 | } |
||
99 | |||
100 | /** |
||
101 | * Decodes JSON response and returns the data. |
||
102 | * |
||
103 | * @param string|array|null $attributes |
||
104 | * @return array |
||
105 | */ |
||
106 | protected function getSuccessData($attributes = null) |
||
107 | { |
||
108 | $rawData = $this->decodeResponseJson()['data']; |
||
109 | |||
110 | if (is_null($attributes)) { |
||
111 | return $rawData; |
||
112 | } elseif (is_string($attributes)) { |
||
113 | return array_get($rawData, $attributes); |
||
114 | } |
||
115 | |||
116 | $data = []; |
||
117 | |||
118 | foreach ($attributes as $attribute) { |
||
119 | $data[] = array_get($rawData, $attribute); |
||
120 | } |
||
121 | |||
122 | return $data; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Assert that the response is a valid error response. |
||
127 | * |
||
128 | * @param string $error |
||
129 | * @param int|null $status |
||
130 | * @return $this |
||
131 | */ |
||
132 | protected function seeError(string $error, int $status = null) |
||
133 | { |
||
134 | if (! is_null($status)) { |
||
135 | $this->seeStatusCode($status); |
||
136 | } |
||
137 | |||
138 | if ($this->app->config->get('responder.status_code')) { |
||
139 | $this->seeJson([ |
||
140 | 'status' => $status, |
||
141 | ]); |
||
142 | } |
||
143 | |||
144 | return $this->seeJson([ |
||
145 | 'success' => false, |
||
146 | ])->seeJsonSubset([ |
||
147 | 'error' => [ |
||
148 | 'code' => $error, |
||
149 | ], |
||
150 | ]); |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * Asserts that the status code of the response matches the given code. |
||
155 | * |
||
156 | * @param int $status |
||
157 | * @return $this |
||
158 | */ |
||
159 | abstract protected function seeStatusCode($status); |
||
160 | |||
161 | /** |
||
162 | * Assert that the response contains JSON. |
||
163 | * |
||
164 | * @param array|null $data |
||
165 | * @param bool $negate |
||
166 | * @return $this |
||
167 | */ |
||
168 | abstract public function seeJson(array $data = null, $negate = false); |
||
169 | |||
170 | /** |
||
171 | * Assert that the JSON response has a given structure. |
||
172 | * |
||
173 | * @param array|null $structure |
||
174 | * @param array|null $responseData |
||
175 | * @return $this |
||
176 | */ |
||
177 | abstract public function seeJsonStructure(array $structure = null, $responseData = null); |
||
178 | |||
179 | /** |
||
180 | * Assert that the response is a superset of the given JSON. |
||
181 | * |
||
182 | * @param array $data |
||
183 | * @return $this |
||
184 | */ |
||
185 | abstract protected function seeJsonSubset(array $data); |
||
186 | |||
187 | /** |
||
188 | * Assert that the response contains an exact JSON array. |
||
189 | * |
||
190 | * @param array $data |
||
191 | * @return $this |
||
192 | */ |
||
193 | abstract public function seeJsonEquals(array $data); |
||
194 | |||
195 | /** |
||
196 | * Validate and return the decoded response JSON. |
||
197 | * |
||
198 | * @return array |
||
199 | */ |
||
200 | abstract protected function decodeResponseJson(); |
||
201 | } |
||
202 |
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.