Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
restmanager.php
1<?php
2
3namespace Bitrix\Rest\Engine;
4
22
23class RestManager extends \IRestService
24{
25 public const DONT_CALCULATE_COUNT = -1;
26
28 protected $restServer;
30 private $pageNavigation;
32 private $calculateTotalCount = true;
33
34 public static function onFindMethodDescription($potentialAction)
35 {
36 $restManager = new static();
37 $potentialActionData = ScopeManager::getInstance()->getMethodInfo($potentialAction);
38
39 $request = new \Bitrix\Main\HttpRequest(
40 Context::getCurrent()->getServer(),
41 ['action' => $potentialActionData['method']],
42 [], [], []
43 );
44
45 $router = new Engine\Router($request);
46 $controllersConfig = Configuration::getInstance($router->getModule());
47 if (empty($controllersConfig['controllers']['restIntegration']['enabled']))
48 {
49 return false;
50 }
51
53 list($controller) = $router->getControllerAndAction();
54 if (!$controller || $controller instanceof Engine\DefaultController)
55 {
56 return false;
57 }
58
59 return [
60 'scope' => static::getModuleScopeAlias($potentialActionData['scope']),
61 'callback' => [
62 $restManager, 'processMethodRequest'
63 ]
64 ];
65 }
66
67 public static function getModuleScopeAlias($moduleId)
68 {
69 if($moduleId === 'tasks')
70 {
71 return 'task';
72 }
73
74 return $moduleId;
75 }
76
77 private static function getAlternativeScope($scope): ?array
78 {
79 if ($scope === \Bitrix\Rest\Api\User::SCOPE_USER)
80 {
81 return [
82 \Bitrix\Rest\Api\User::SCOPE_USER_BRIEF,
83 \Bitrix\Rest\Api\User::SCOPE_USER_BASIC,
84 ];
85 }
86
87 return null;
88 }
89
90 public static function fillAlternativeScope($scope, $scopeList)
91 {
92 if (!in_array($scope, $scopeList, true))
93 {
94 $altScopeList = static::getAlternativeScope($scope);
95 if (is_array($altScopeList))
96 {
97 $hasScope = array_intersect($scopeList, $altScopeList);
98 if (count($hasScope) > 0)
99 {
100 $scopeList[] = $scope;
101 }
102 }
103 }
104
105 return $scopeList;
106 }
107
119 public function processMethodRequest(array $params, $start, \CRestServer $restServer)
120 {
121 $start = intval($start);
122 $this->initialize($restServer, $start);
123
124 $errorCollection = new ErrorCollection();
125 $method = $restServer->getMethod();
126 $methodData = ScopeManager::getInstance()->getMethodInfo($method);
127
128 $request = new \Bitrix\Main\HttpRequest(
129 Context::getCurrent()->getServer(),
130 ['action' => $methodData['method']],
131 [], [], []
132 );
133 $router = new Engine\Router($request);
134
136 [$controller, $action] = Resolver::getControllerAndAction(
137 $router->getVendor(),
138 $router->getModule(),
139 $router->getAction(),
141 );
142 if (!$controller)
143 {
144 throw new RestException("Unknown {$method}. There is not controller in module {$router->getModule()}");
145 }
146
147 $this->calculateTotalCount = true;
148 if ((int)$start === self::DONT_CALCULATE_COUNT)
149 {
150 $this->calculateTotalCount = false;
151 }
152
153 $autoWirings = $this->getAutoWirings();
154
155 $this->registerAutoWirings($autoWirings);
156 $result = $controller->run($action, [$params, ['__restServer' => $restServer, '__calculateTotalCount' => $this->calculateTotalCount]]);
157 $this->unRegisterAutoWirings($autoWirings);
158
159 if ($result instanceof Engine\Response\File)
160 {
161 return $result->send();
162 }
163
164 if ($result instanceof HttpResponse)
165 {
166 if ($result instanceof Errorable)
167 {
168 $errorCollection->add($result->getErrors());
169 }
170
171 $result = $result->getContent();
172 }
173
174 if ($result instanceof RestException)
175 {
176 throw $result;
177 }
178
179 if ($result === null)
180 {
181 $errorCollection->add($controller->getErrors());
182 if (!$errorCollection->isEmpty())
183 {
184 throw $this->createExceptionFromErrors($errorCollection->toArray());
185 }
186 }
187
188 return $this->processData($result);
189 }
190
195 private function initialize(\CRestServer $restServer, int $start): void
196 {
197 $pageNavigation = new PageNavigation('nav');
198 $pageNavigation->setPageSize(static::LIST_LIMIT);
199 if ($start > 0)
200 {
201 $pageNavigation->setCurrentPage((int)($start / static::LIST_LIMIT) + 1);
202 }
203
204 $this->pageNavigation = $pageNavigation;
205 $this->restServer = $restServer;
206 }
207
214 private function getNavigationData(Engine\Response\DataType\Page $page): array
215 {
216 if (!$this->calculateTotalCount)
217 {
218 return [];
219 }
220
221 $result = [];
222 $offset = $this->pageNavigation->getOffset();
223 $total = $page->getTotalCount();
224
225 $currentPageSize = count($page->getItems());
226
227 if ($offset + $currentPageSize < $total)
228 {
229 $result['next'] = $offset + $currentPageSize;
230 }
231
232 $result['total'] = $total;
233
234 return $result;
235 }
236
237
238 private function processData($result)
239 {
240 if ($result instanceof DateTime)
241 {
242 return \CRestUtil::convertDateTime($result);
243 }
244
245 if ($result instanceof Date)
246 {
247 return \CRestUtil::convertDate($result);
248 }
249
250 if ($result instanceof Uri)
251 {
252 return $this->convertAjaxUriToRest($result);
253 }
254
255 if ($result instanceof Engine\Response\DataType\Page)
256 {
257 if (method_exists($result, 'getId'))
258 {
259 $data = [$result->getId() => $this->processData($result->getIterator())];
260 }
261 else
262 {
263 $data = $this->processData($result->getIterator());
264 }
265
266 return array_merge($data, $this->getNavigationData($result));
267 }
268
269 if ($result instanceof Contract\Arrayable)
270 {
271 $result = $result->toArray();
272 }
273
274 if (is_array($result))
275 {
276 foreach ($result as $key => $item)
277 {
278 if ($item instanceof Engine\Response\DataType\ContentUri)
279 {
280 $result[$key . "Machine"] = $this->processData($item);
281 $result[$key] = $this->processData(new Uri($item));
282 }
283 else
284 {
285 $result[$key] = $this->processData($item);
286 }
287
288 }
289 }
290 elseif ($result instanceof \Traversable)
291 {
292 $newResult = [];
293 foreach ($result as $key => $item)
294 {
295 $newResult[$key] = $this->processData($item);
296 }
297
298 $result = $newResult;
299 }
300
301 return $result;
302 }
303
304 private function convertAjaxUriToRest(Uri $uri)
305 {
306 if (!($uri instanceof Engine\Response\DataType\ContentUri))
307 {
308 return $uri->getUri();
309 }
310
311 $endPoint = Engine\UrlManager::getInstance()->getEndPoint(Engine\UrlManager::ABSOLUTE_URL);
312 if ($uri->getPath() !== $endPoint->getPath())
313 {
314 return $uri->getUri();
315 }
316
317 if ($uri->getHost() && $uri->getHost() !== $endPoint->getHost())
318 {
319 return $uri->getUri();
320 }
321
322 parse_str($uri->getQuery(), $params);
323 if (empty($params['action']))
324 {
325 return $uri->getUri();
326 }
327
328 return \CRestUtil::getSpecialUrl($params['action'], $params, $this->restServer);
329 }
330
331 private function getRestEndPoint()
332 {
333 return \Bitrix\Main\Config\Option::get('rest', 'rest_server_path', '/rest');
334 }
335
340 private function createExceptionFromErrors(array $errors)
341 {
342 if(!$errors)
343 {
344 return null;
345 }
346
347 $firstError = reset($errors);
348
349 return new RestException($firstError->getMessage(), $firstError->getCode());
350 }
351
355 private function registerAutoWirings(array $autoWirings): void
356 {
357 foreach ($autoWirings as $parameter)
358 {
359 AutoWire\Binder::registerGlobalAutoWiredParameter($parameter);
360 }
361 }
362
366 private function unRegisterAutoWirings(array $autoWirings): void
367 {
368 foreach ($autoWirings as $parameter)
369 {
370 AutoWire\Binder::unRegisterGlobalAutoWiredParameter($parameter);
371 }
372 }
373
377 private function getAutoWirings(): array
378 {
379 $buildRules = [
380 'restServer' => [
381 'class' => \CRestServer::class,
382 'constructor' => function() {
383 return $this->restServer;
384 },
385 ],
386 'pageNavigation' => [
387 'class' => PageNavigation::class,
388 'constructor' => function() {
389 return $this->pageNavigation;
390 },
391 ],
392 ];
393
394 $autoWirings = [];
395 foreach ($buildRules as $rule)
396 {
397 $autoWirings[] = new AutoWire\Parameter($rule['class'], $rule['constructor']);
398 }
399
400 return $autoWirings;
401 }
402}
static getCurrent()
Definition context.php:241
static getControllerAndAction($vendor, $module, $action, $scope=Controller::SCOPE_AJAX)
Definition resolver.php:23
static getModuleScopeAlias($moduleId)
static fillAlternativeScope($scope, $scopeList)