• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MichaelJ2324 / PHP-REST-Client / 13117986415

03 Feb 2025 04:21PM UTC coverage: 93.907% (-0.5%) from 94.384%
13117986415

push

github

web-flow
Merge pull request #15 from MichaelJ2324/3.x

v3.0.3 Fix Response Handling in Auth + Default no Action on Model

26 of 32 new or added lines in 3 files covered. (81.25%)

1048 of 1116 relevant lines covered (93.91%)

1.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.49
/src/Endpoint/Abstracts/AbstractModelEndpoint.php
1
<?php
2

3
namespace MRussell\REST\Endpoint\Abstracts;
4

5
use MRussell\REST\Endpoint\Interfaces\EndpointInterface;
6
use MRussell\REST\Exception\Endpoint\InvalidRequest;
7
use GuzzleHttp\Psr7\Response;
8
use MRussell\REST\Endpoint\Data\AbstractEndpointData;
9
use MRussell\REST\Endpoint\Data\DataInterface;
10
use MRussell\REST\Endpoint\Interfaces\ModelInterface;
11
use MRussell\REST\Endpoint\Traits\ArrayObjectAttributesTrait;
12
use MRussell\REST\Endpoint\Traits\ClearAttributesTrait;
13
use MRussell\REST\Endpoint\Traits\GetAttributesTrait;
14
use MRussell\REST\Endpoint\Traits\ParseResponseBodyToArrayTrait;
15
use MRussell\REST\Endpoint\Traits\PropertiesTrait;
16
use MRussell\REST\Endpoint\Traits\SetAttributesTrait;
17
use MRussell\REST\Exception\Endpoint\MissingModelId;
18
use MRussell\REST\Exception\Endpoint\UnknownModelAction;
19

20
/**
21
 * Class AbstractModelEndpoint
22
 * @package MRussell\REST\Endpoint\Abstracts
23
 */
24
abstract class AbstractModelEndpoint extends AbstractSmartEndpoint implements ModelInterface, DataInterface
25
{
26
    use ArrayObjectAttributesTrait;
27
    use GetAttributesTrait;
28
    use SetAttributesTrait;
29
    use PropertiesTrait;
30
    use ClearAttributesTrait;
31
    use ParseResponseBodyToArrayTrait;
32

33
    public const PROPERTY_RESPONSE_PROP = 'response_prop';
34

35
    public const PROPERTY_MODEL_KEY = 'id_key';
36

37
    public const DEFAULT_MODEL_KEY = 'id';
38

39
    public const MODEL_ID_VAR = 'id';
40

41
    public const MODEL_ACTION_CREATE = 'create';
42

43
    public const MODEL_ACTION_RETRIEVE = 'retrieve';
44

45
    public const MODEL_ACTION_UPDATE = 'update';
46

47
    public const MODEL_ACTION_DELETE = 'delete';
48

49
    public const EVENT_BEFORE_SAVE = 'before_save';
50

51
    public const EVENT_AFTER_SAVE = 'after_save';
52

53
    public const EVENT_BEFORE_DELETE = 'before_delete';
54

55
    public const EVENT_AFTER_DELETE = 'after_delete';
56

57
    public const EVENT_BEFORE_RETRIEVE = 'before_retrieve';
58

59
    public const EVENT_AFTER_RETRIEVE = 'after_retrieve';
60

61
    public const EVENT_BEFORE_SYNC = 'before_sync';
62

63
    /**
64
     * The ID Field used by the Model
65
     */
66
    protected static string $_DEFAULT_MODEL_KEY = self::DEFAULT_MODEL_KEY;
67

68
    /**
69
     * List of actions
70
     */
71
    protected static array $_DEFAULT_ACTIONS = [self::MODEL_ACTION_CREATE => 'POST', self::MODEL_ACTION_RETRIEVE => 'GET', self::MODEL_ACTION_UPDATE => 'PUT', self::MODEL_ACTION_DELETE => 'DELETE'];
72

73
    /**
74
     * List of available actions and their associated Request Method
75
     */
76
    protected array $_actions = [];
77

78
    /**
79
     * Current action being executed
80
     */
81
    protected string $_action = '';
82

83
    public static function defaultModelKey(string $key = null): string
1✔
84
    {
85
        if (!empty($key)) {
1✔
86
            static::$_DEFAULT_MODEL_KEY = $key;
1✔
87
        }
88

89
        return static::$_DEFAULT_MODEL_KEY;
1✔
90
    }
91

92
    public function getKeyProperty(): string
1✔
93
    {
94
        return $this->getProperty(self::PROPERTY_MODEL_KEY) ?? static::defaultModelKey();
1✔
95
    }
96

97
    public function getId(): string|int|null
×
98
    {
99
        return $this->get($this->getKeyProperty()) ?? null;
×
100
    }
101

102
    //Overloads
103
    public function __construct(array $properties = [], array $urlArgs = [])
1✔
104
    {
105
        parent::__construct($properties, $urlArgs);
1✔
106
        foreach (static::$_DEFAULT_ACTIONS as $action => $method) {
1✔
107
            $this->_actions[$action] = $method;
1✔
108
        }
109
    }
110

111
    public function __call($name, $arguments): EndpointInterface
2✔
112
    {
113
        if (array_key_exists($name, $this->_actions)) {
2✔
114
            return $this->setCurrentAction($name, $arguments)->execute();
1✔
115
        }
116

117
        throw new UnknownModelAction([static::class, $name]);
1✔
118
    }
119

120
    /**
121
     * @inheritdoc
122
     */
123
    public function reset(): static
1✔
124
    {
125
        parent::reset();
1✔
126
        return $this->clear();
1✔
127
    }
128

NEW
129
    public function execute(array $options = []): static
×
130
    {
NEW
131
        if (empty($this->_action)) {
×
NEW
132
            if (!empty($this->getId())) {
×
NEW
133
                $this->setCurrentAction(self::MODEL_ACTION_RETRIEVE);
×
134
            } else {
NEW
135
                $this->setCurrentAction(self::MODEL_ACTION_CREATE);
×
136
            }
137
        }
NEW
138
        return parent::execute($options);
×
139
    }
140

141
    /**
142
     * @inheritdoc
143
     * @throws InvalidRequest
144
     */
145
    public function retrieve($id = null): static
2✔
146
    {
147
        $this->setCurrentAction(self::MODEL_ACTION_RETRIEVE);
2✔
148
        $idKey = $this->getKeyProperty();
2✔
149
        if ($id !== null) {
2✔
150
            if (isset($this->_attributes[$idKey])) {
1✔
151
                $this->clear();
1✔
152
            }
153

154
            $this->set($idKey, $id);
1✔
155
        } elseif (!isset($this->_attributes[$idKey])) {
2✔
156
            throw new MissingModelId([$this->_action, static::class]);
1✔
157
        }
158

159
        $this->triggerEvent(self::EVENT_BEFORE_RETRIEVE);
1✔
160
        $this->execute();
1✔
161
        $this->triggerEvent(self::EVENT_AFTER_RETRIEVE);
1✔
162
        return $this;
1✔
163
    }
164

165
    /**
166
     * @inheritdoc
167
     * @throws InvalidRequest
168
     */
169
    public function save(): static
1✔
170
    {
171
        if (!empty($this->getId())) {
1✔
172
            $this->setCurrentAction(self::MODEL_ACTION_UPDATE);
1✔
173
        } else {
174
            $this->setCurrentAction(self::MODEL_ACTION_CREATE);
1✔
175
        }
176

177
        $this->triggerEvent(self::EVENT_BEFORE_SAVE);
1✔
178
        $this->execute();
1✔
179
        $this->triggerEvent(self::EVENT_AFTER_SAVE);
1✔
180
        return $this;
1✔
181
    }
182

183
    /**
184
     * @inheritdoc
185
     */
186
    public function delete(): static
1✔
187
    {
188
        $this->setCurrentAction(self::MODEL_ACTION_DELETE);
1✔
189
        $this->triggerEvent(self::EVENT_BEFORE_DELETE);
1✔
190
        $this->execute();
1✔
191
        $this->triggerEvent(self::EVENT_AFTER_DELETE);
1✔
192
        return $this;
1✔
193
    }
194

195
    /**
196
     * Set the current action taking place on the Model
197
     */
198
    public function setCurrentAction(string $action, array $actionArgs = []): static
1✔
199
    {
200
        if (array_key_exists($action, $this->_actions)) {
1✔
201
            $this->_action = $action;
1✔
202
            $this->configureAction($this->_action, $actionArgs);
1✔
203
        }
204

205
        return $this;
1✔
206
    }
207

208
    /**
209
     * Get the current action taking place on the Model
210
     */
211
    public function getCurrentAction(): string
1✔
212
    {
213
        return $this->_action;
1✔
214
    }
215

216
    /**
217
     * Update any properties or data based on the current action
218
     * - Called when setting the Current Action
219
     * @param $action
220
     */
221
    protected function configureAction(string $action, array $arguments = []): void
4✔
222
    {
223
        $this->setProperty(self::PROPERTY_HTTP_METHOD, $this->_actions[$action]);
4✔
224
    }
225

226
    /**
227
     * @param AbstractEndpointData $data
228
     * @inheritdoc
229
     */
230
    protected function configurePayload(): mixed
2✔
231
    {
232
        $data = $this->getData();
2✔
233
        switch ($this->getCurrentAction()) {
2✔
234
            case self::MODEL_ACTION_CREATE:
235
            case self::MODEL_ACTION_UPDATE:
236
                $data->set($this->toArray());
1✔
237
                break;
1✔
238
        }
239

240
        $this->triggerEvent(self::EVENT_CONFIGURE_PAYLOAD, $data);
2✔
241
        return $data;
2✔
242
    }
243

244
    protected function setResponse(Response $response): static
1✔
245
    {
246
        parent::setResponse($response);
1✔
247
        $this->parseResponse($response);
1✔
248
        return $this;
1✔
249
    }
250

251
    public function getModelResponseProp(): string
1✔
252
    {
253
        return $this->getProperty(self::PROPERTY_RESPONSE_PROP) ?? "";
1✔
254
    }
255

256
    /**
257
     * Parse the response for use by Model
258
     */
259
    protected function parseResponse(Response $response): void
1✔
260
    {
261
        if ($response->getStatusCode() == 200) {
1✔
262
            switch ($this->getCurrentAction()) {
1✔
263
                case self::MODEL_ACTION_CREATE:
264
                case self::MODEL_ACTION_UPDATE:
265
                case self::MODEL_ACTION_RETRIEVE:
266
                    $body = $this->getResponseContent($response);
1✔
267
                    $this->syncFromApi($this->parseResponseBodyToArray($body, $this->getModelResponseProp()));
1✔
268
                    break;
1✔
269
                case self::MODEL_ACTION_DELETE:
270
                    $this->clear();
1✔
271
                    break;
1✔
272
            }
273
        }
274
    }
275

276
    /**
277
     * Called after Execute if a Request Object exists, and Request returned 200 response
278
     */
279
    protected function syncFromApi(array $model): void
1✔
280
    {
281
        $this->triggerEvent(self::EVENT_BEFORE_SYNC, $model);
1✔
282
        $this->set($model);
1✔
283
    }
284

285
    protected function configureURL(array $urlArgs): string
2✔
286
    {
287
        if (empty($urlArgs[self::MODEL_ID_VAR])) {
2✔
288
            switch ($this->getCurrentAction()) {
2✔
289
                case self::MODEL_ACTION_CREATE:
290
                    $urlArgs[self::MODEL_ID_VAR] = '';
1✔
291
                    break;
1✔
292
                default:
293
                    $idKey = $this->getKeyProperty();
2✔
294
                    $id = $this->get($idKey);
2✔
295
                    $urlArgs[self::MODEL_ID_VAR] = (empty($id) ? '' : $id);
2✔
296
            }
297
        }
298

299
        return parent::configureURL($urlArgs);
2✔
300
    }
301
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc