Passed
Push — developer ( a3724f...eca833 )
by Radosław
32:15
created

AbstractListView::getApiHeaders()   B

Complexity

Conditions 7
Paths 32

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.6026
c 0
b 0
f 0
cc 7
nc 32
nop 0
1
<?php
2
/**
3
 * The file contains: Abstract class ListView.
4
 *
5
 * @package Model
6
 *
7
 * @copyright YetiForce Sp. z o.o.
8
 * @license YetiForce Public License 3.0 (licenses/LicenseEN.txt or yetiforce.com)
9
 * @author Arkadiusz Adach <[email protected]>
10
 * @author    Mariusz Krzaczkowski <[email protected]>
11
 * @author    Radosław Skrzypczak <[email protected]>
12
 */
13
14
namespace YF\Modules\Base\Model;
15
16
/**
17
 * Abstract class ListView.
18
 */
19
abstract class AbstractListView
20
{
21
	/** @var string Module name. */
22
	protected $moduleName;
23
24
	/** @var string[] Column fields */
25
	protected $fields = [];
26
27
	/** @var array Records list from api. */
28
	protected $recordsList = [];
29
30
	/** @var int Current page. */
31
	private $page = 1;
32
33
	/** @var int The number of items on the page. */
34
	protected $limit = 0;
35
36
	/** @var int Offset. */
37
	protected $offset = 0;
38
39
	/** @var string Sorting direction. */
40
	protected $order;
41
42
	/** @var string Sets the ORDER BY part of the query record list. */
43
	protected $orderField;
44
45
	/** @var array Conditions. */
46
	protected $conditions = [];
47
48
	/** @var bool Use raw data. */
49
	protected $rawData = false;
50
51
	protected $actionName = 'RecordsList';
52
53
	/** @var array Custom views */
54
	protected $customViews;
55
56
	/** @var int Custom view ID */
57
	protected $cvId;
58
59
	/**
60
	 * Get instance.
61
	 *
62
	 * @param string $moduleName
63
	 * @param string $viewName
64
	 *
65
	 * @return self
0 ignored issues
show
Documentation introduced by
Should the return type not be \self?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
66
	 */
67
	public static function getInstance(string $moduleName, string $viewName = 'ListView'): self
68
	{
69
		$handlerModule = \App\Loader::getModuleClassName($moduleName, 'Model', $viewName);
70
		$self = new $handlerModule();
71
		$self->moduleName = $moduleName;
72
		$self->limit = \App\Config::$itemsPrePage ?: 15;
73
		return $self;
74
	}
75
76
	/**
77
	 * Function to get the Module Model.
78
	 *
79
	 * @return string
80
	 */
81
	public function getModuleName(): string
82
	{
83
		return $this->moduleName;
84
	}
85
86
	/**
87
	 * Function to set raw data.
88
	 *
89
	 * @param bool $rawData
90
	 *
91
	 * @return self
92
	 */
93
	public function setRawData(bool $rawData): self
94
	{
95
		$this->rawData = $rawData;
96
		return $this;
97
	}
98
99
	/**
100
	 * Set custom fields.
101
	 *
102
	 * @param array $fields
103
	 *
104
	 * @return self
105
	 */
106
	public function setFields(array $fields): self
107
	{
108
		$this->fields = $fields;
109
		return $this;
110
	}
111
112
	/**
113
	 * Set limit.
114
	 *
115
	 * @param int $limit
116
	 *
117
	 * @return self
118
	 */
119
	public function setLimit(int $limit): self
120
	{
121
		$this->limit = $limit;
122
		return $this;
123
	}
124
125
	/**
126
	 * Set offset.
127
	 *
128
	 * @param int $offset
129
	 *
130
	 * @return self
131
	 */
132
	public function setOffset(int $offset): self
133
	{
134
		$this->offset = $offset;
135
		return $this;
136
	}
137
138
	/**
139
	 * Set order.
140
	 *
141
	 * @param string $field
142
	 * @param string $direction
143
	 *
144
	 * @return self
145
	 */
146
	public function setOrder(string $field, string $direction): self
147
	{
148
		$this->orderField = $field;
149
		$this->order = $direction;
150
		return $this;
151
	}
152
153
	/**
154
	 * Set conditions.
155
	 *
156
	 * @param array $conditions
157
	 *
158
	 * @return void
159
	 */
160
	public function setConditions(array $conditions)
161
	{
162
		$this->conditions = $conditions;
163
	}
164
165
	/**
166
	 * Undocumented function.
167
	 *
168
	 * @param int $cvId
169
	 *
170
	 * @return $this
171
	 */
172
	public function setCvId(int $cvId): self
173
	{
174
		$this->cvId = $cvId;
175
		return $this;
176
	}
177
178
	/**
179
	 * Load a list of records from the API.
180
	 *
181
	 * @return self
182
	 */
183
	public function loadRecordsList(): self
184
	{
185
		$this->recordsList = $this->getFromApi($this->getApiHeaders());
186
		return $this;
187
	}
188
189
	/**
190
	 * Gets headers for api.
191
	 *
192
	 * @return array
193
	 */
194
	public function getApiHeaders(): array
195
	{
196
		$headers = [
197
			'x-row-count' => 1,
198
			'x-row-limit' => $this->limit,
199
			'x-row-offset' => $this->offset
200
		];
201
		if (!empty($this->fields)) {
202
			$headers['x-fields'] = \App\Json::encode($this->fields);
203
		}
204
		if (!empty($this->conditions)) {
205
			$headers['x-condition'] = \App\Json::encode($this->conditions);
206
		}
207
		if ($this->rawData) {
208
			$headers['x-raw-data'] = 1;
209
		}
210
		if (!empty($this->order) && $this->orderField) {
211
			$headers['x-order-by'] = \App\Json::encode([$this->orderField => $this->order]);
212
		}
213
		if ($cvId = $this->getDefaultCustomView()) {
214
			$headers['x-cv-id'] = $cvId;
215
		}
216
		return $headers;
217
	}
218
219
	/**
220
	 * Get data from api.
221
	 *
222
	 * @param array $headers
223
	 *
224
	 * @return array
225
	 */
226
	protected function getFromApi(array $headers): array
227
	{
228
		$api = \App\Api::getInstance();
229
		$api->setCustomHeaders($headers);
230
		return $api->call($this->getModuleName() . '/' . $this->actionName);
231
	}
232
233
	/**
234
	 * Get records list model.
235
	 *
236
	 * @return Record[]
237
	 */
238
	public function getRecordsListModel(): array
239
	{
240
		$recordsModel = [];
241
		if (!empty($this->recordsList['records'])) {
242
			foreach ($this->recordsList['records'] as $id => $value) {
243
				$recordModel = Record::getInstance($this->getModuleName());
244
				if (isset($value['recordLabel'])) {
245
					$recordModel->setName($value['recordLabel']);
246
					unset($value['recordLabel']);
247
				}
248
				$recordModel->setData($value)->setId($id);
249
				$recordsModel[$id] = $recordModel;
250
			}
251
		}
252
		if (!empty($this->recordsList['rawData'])) {
253
			foreach ($this->recordsList['rawData'] as $id => $value) {
254
				$recordsModel[$id]->setRawData($value);
255
			}
256
		}
257
		return $recordsModel;
258
	}
259
260
	/**
261
	 * Get headers of list.
262
	 *
263
	 * @return array
264
	 */
265
	public function getHeaders(): array
266
	{
267
		if (empty($this->recordsList)) {
268
			$headers = ['x-only-column' => 1];
269
			if ($cvId = $this->getDefaultCustomView()) {
270
				$headers['x-cv-id'] = $cvId;
271
			}
272
			$this->recordsList = $this->getFromApi($headers);
273
		}
274
		return $this->recordsList['headers'] ?? [];
275
	}
276
277
	/**
278
	 * Gets custom views.
279
	 *
280
	 * @return array
281
	 */
282
	public function getCustomViews(): array
283
	{
284
		if (null === $this->customViews) {
285
			if (\App\Cache::has('CustomViews', $this->getModuleName())) {
286
				$this->customViews = \App\Cache::get('CustomViews', $this->getModuleName());
0 ignored issues
show
Documentation Bug introduced by
It seems like \App\Cache::get('CustomV...$this->getModuleName()) can also be of type string. However, the property $customViews is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
287
			} else {
288
				$this->customViews = \App\Api::getInstance()->call($this->getModuleName() . '/CustomView') ?: [];
289
				\App\Cache::save('CustomViews', $this->getModuleName(), $this->customViews, \App\Cache::LONG);
290
			}
291
		}
292
		return $this->customViews;
293
	}
294
295
	/**
296
	 * Get default custom view ID.
297
	 *
298
	 * @return int|null
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
299
	 */
300
	public function getDefaultCustomView(): ?int
301
	{
302
		if (!$this->cvId) {
303
			foreach ($this->getCustomViews() as $cvId => $cvData) {
304
				if ($cvData['isDefault']) {
305
					$this->cvId = $cvId;
0 ignored issues
show
Documentation Bug introduced by
It seems like $cvId can also be of type string. However, the property $cvId is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
306
					break;
307
				}
308
			}
309
		}
310
		return $this->cvId;
311
	}
312
313
	/**
314
	 * Get all rows count.
315
	 *
316
	 * @return int
317
	 */
318
	public function getCount(): int
319
	{
320
		return $this->recordsList['numberOfAllRecords'] ?? 0;
321
	}
322
323
	/**
324
	 * Get current page.
325
	 *
326
	 * @return int
327
	 */
328
	public function getPage(): int
329
	{
330
		if (!$this->page) {
331
			$this->page = floor($this->recordsList['numberOfRecords'] / ($this->recordsList['numberOfAllRecords'] ?: 1)) ?: 1;
0 ignored issues
show
Documentation Bug introduced by
It seems like floor($this->recordsList...llRecords'] ?: 1)) ?: 1 can also be of type double. However, the property $page is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
332
		}
333
		return $this->page;
334
	}
335
336
	/**
337
	 * Sets page number.
338
	 *
339
	 * @param int $page
340
	 *
341
	 * @return $this
342
	 */
343
	public function setPage(int $page)
344
	{
345
		$this->page = $page;
346
		return $this;
347
	}
348
349
	/**
350
	 * Is there more pages.
351
	 *
352
	 * @return bool
353
	 */
354
	public function isMorePages(): bool
355
	{
356
		return $this->recordsList['isMorePages'] ?? false;
357
	}
358
}
359