diff --git a/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php b/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php index 064aa92d97..2b0e05a618 100644 --- a/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php +++ b/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php @@ -20,10 +20,11 @@ use Alchemy\Phrasea\Model\Entities\Order; use Alchemy\Phrasea\Model\Entities\OrderElement; use Alchemy\Phrasea\Model\RecordReferenceInterface; use Alchemy\Phrasea\Order\OrderElementTransformer; -use Alchemy\Phrasea\Order\OrderElementViewModel; +use Alchemy\Phrasea\Order\OrderElementView; use Alchemy\Phrasea\Order\OrderFiller; use Alchemy\Phrasea\Order\OrderTransformer; -use Alchemy\Phrasea\Order\OrderViewModel; +use Alchemy\Phrasea\Order\OrderView; +use Alchemy\Phrasea\Order\OrderViewBuilder; use Alchemy\Phrasea\Record\RecordReference; use Alchemy\Phrasea\Record\RecordReferenceCollection; use Assert\Assertion; @@ -74,7 +75,7 @@ class ApiOrderController extends BaseOrderController { $page = max((int) $request->get('page', '1'), 1); $perPage = min(max((int)$request->get('per_page', '10'), 1), 100); - $fractal = $this->parseIncludes($request->get('includes', [])); + $fractal = $this->buildFractalManager($request->get('includes', [])); $routeGenerator = function ($page) use ($perPage) { return $this->app->path('api_v2_orders_index', [ @@ -95,8 +96,10 @@ class ApiOrderController extends BaseOrderController ; } - $collection = $this->buildOrderViewModels($builder->getQuery()->getResult()); - $this->fillViewModels($collection, $fractal->getRequestedIncludes()); + $collection = $this->getViewBuilder()->buildViews( + $builder->getQuery()->getResult(), + $fractal->getRequestedIncludes() + ); $resource = new Collection($collection, $this->getOrderTransformer()); @@ -118,15 +121,13 @@ class ApiOrderController extends BaseOrderController { $order = $this->findOr404($orderId); - $fractal = $this->parseIncludes($request->get('includes', [])); + $fractal = $this->buildFractalManager($request->get('includes', [])); if ($order->getUser()->getId() !== $this->getAuthenticatedUser()->getId()) { throw new AccessDeniedHttpException(sprintf('Cannot access order "%d"', $order->getId())); } - $model = $this->buildOrderViewModel($order); - $this->fillViewModels([$model], $fractal->getRequestedIncludes()); - + $model = $this->getViewBuilder()->buildView($order, $fractal->getRequestedIncludes()); $resource = new Item($model, $this->getOrderTransformer()); return $this->returnResourceResponse($request, $fractal, $resource); @@ -209,7 +210,7 @@ class ApiOrderController extends BaseOrderController * @param string|array $includes * @return Manager */ - private function parseIncludes($includes) + private function buildFractalManager($includes) { $fractal = new Manager(); @@ -226,7 +227,7 @@ class ApiOrderController extends BaseOrderController */ private function returnResourceResponse(Request $request, $includes, ResourceInterface $resource) { - $fractal = $includes instanceof Manager ? $includes : $this->parseIncludes($includes); + $fractal = $includes instanceof Manager ? $includes : $this->buildFractalManager($includes); return Result::create($request, $fractal->createData($resource)->toArray())->createResponse(); } @@ -248,162 +249,12 @@ class ApiOrderController extends BaseOrderController return $elementIds; } - /** - * @param OrderViewModel[] $models - * @param array $includes - * @return void - */ - private function fillViewModels(array $models, array $includes) + private function getViewBuilder() { - if (!in_array('elements', $includes, true)) { - return; - } - - $elements = $this->gatherElements($models); - - $allElements = $elements ? call_user_func_array('array_merge', $elements) : []; - $allElements = array_combine( - array_map(function (OrderElement $element) { - return $element->getId(); - }, $allElements), - $allElements + return new OrderViewBuilder( + $this->app, + $this->getApplicationBox(), + $this->app['service.media_subdef'] ); - - if (!$allElements) { - return; - } - - $collectionToDataboxMap = $this->mapBaseIdToDataboxId($allElements); - - $records = RecordReferenceCollection::fromListExtractor( - $allElements, - function (OrderElement $element) use ($collectionToDataboxMap) { - return isset($collectionToDataboxMap[$element->getBaseId()]) - ? [$collectionToDataboxMap[$element->getBaseId()], $element->getRecordId()] - : null; - }, - function (array $data) { - list ($databoxId, $recordId) = $data; - - return RecordReference::createFromDataboxIdAndRecordId($databoxId, $recordId); - } - ); - - $this->createOrderElementViewModels($models, $elements, $records); - - if (!in_array('elements.resource_links', $includes, true)) { - return; - } - - // Load all records - $records->toRecords($this->getApplicationBox()); - - // Load all subdefs - $subdefs = $this->app['service.media_subdef']->findSubdefsFromRecordReferenceCollection($records); - \media_Permalink_Adapter::getMany($this->app, $subdefs); - - $orderableSubdefs = []; - - foreach ($subdefs as $subdef) { - $databoxId = $subdef->get_sbas_id(); - $recordId = $subdef->get_record_id(); - - if (!isset($orderableSubdefs[$databoxId][$recordId])) { - $orderableSubdefs[$databoxId][$recordId] = []; - } - - $orderableSubdefs[$databoxId][$recordId][] = $subdef; - } - - foreach ($models as $model) { - foreach ($model->getElements() as $element) { - $databoxId = $collectionToDataboxMap[$element->getElement()->getBaseId()]; - $recordId = $element->getElement()->getRecordId(); - - if (isset($orderableSubdefs[$databoxId][$recordId])) { - $element->setOrderableMediaSubdefs($orderableSubdefs[$databoxId][$recordId]); - } - } - } - } - - /** - * @param Order[] $orders - * @return OrderViewModel[] - */ - private function buildOrderViewModels(array $orders) - { - Assertion::allIsInstanceOf($orders, Order::class); - - return array_map(function (Order $order) { - return new OrderViewModel($order); - }, $orders); - } - - private function buildOrderViewModel(Order $order) - { - return new OrderViewModel($order); - } - - /** - * @param OrderViewModel[] $models - * @return OrderElement[][] - */ - private function gatherElements(array $models) - { - Assertion::allIsInstanceOf($models, OrderViewModel::class); - - $elements = []; - - foreach ($models as $index => $model) { - $elements[$index] = $model->getOrder()->getElements()->toArray(); - } - - return $elements; - } - - /** - * @param OrderElement[] $elements - * @return array - */ - private function mapBaseIdToDataboxId(array $elements) - { - $baseIds = array_keys(array_reduce($elements, function (array &$baseIds, OrderElement $element) { - $baseIds[$element->getBaseId()] = true; - - return $baseIds; - }, [])); - - $collectionToDataboxMap = []; - - foreach ($this->app['repo.collection-references']->findMany($baseIds) as $collectionReference) { - $collectionToDataboxMap[$collectionReference->getBaseId()] = $collectionReference->getDataboxId(); - } - - return $collectionToDataboxMap; - } - - /** - * @param OrderViewModel[] $orderViewModels - * @param OrderElement[][] $elements - * @param RecordReferenceInterface[]|RecordReferenceCollection $records - * @return void - */ - private function createOrderElementViewModels(array $orderViewModels, $elements, $records) - { - $user = $this->getAuthenticatedUser(); - - foreach ($orderViewModels as $index => $model) { - $models = []; - - /** @var OrderElement $element */ - foreach ($elements[$index] as $elementIndex => $element) { - if (isset($records[$element->getId()])) { - $models[$elementIndex] = new OrderElementViewModel($element, $records[$element->getId()], $user); - } - } - - $model->setViewElements($models); - } } } diff --git a/lib/Alchemy/Phrasea/Order/OrderElementTransformer.php b/lib/Alchemy/Phrasea/Order/OrderElementTransformer.php index 7b49837daf..a7878f344e 100644 --- a/lib/Alchemy/Phrasea/Order/OrderElementTransformer.php +++ b/lib/Alchemy/Phrasea/Order/OrderElementTransformer.php @@ -31,7 +31,7 @@ class OrderElementTransformer extends TransformerAbstract $this->urlGenerator = $urlGenerator; } - public function transform(OrderElementViewModel $model) + public function transform(OrderElementView $model) { $element = $model->getElement(); $record = $model->getRecordReference(); @@ -54,7 +54,7 @@ class OrderElementTransformer extends TransformerAbstract return $data; } - public function includeResourceLinks(OrderElementViewModel $model, ParamBag $params = null) + public function includeResourceLinks(OrderElementView $model, ParamBag $params = null) { $ttl = null; diff --git a/lib/Alchemy/Phrasea/Order/OrderElementViewModel.php b/lib/Alchemy/Phrasea/Order/OrderElementView.php similarity index 88% rename from lib/Alchemy/Phrasea/Order/OrderElementViewModel.php rename to lib/Alchemy/Phrasea/Order/OrderElementView.php index 9440f54a7e..a4d2c31135 100644 --- a/lib/Alchemy/Phrasea/Order/OrderElementViewModel.php +++ b/lib/Alchemy/Phrasea/Order/OrderElementView.php @@ -15,7 +15,7 @@ use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Model\RecordReferenceInterface; use Assert\Assertion; -class OrderElementViewModel +class OrderElementView { /** * @var OrderElement @@ -39,6 +39,7 @@ class OrderElementViewModel /** * OrderElementViewModel constructor. + * * @param OrderElement $element * @param RecordReferenceInterface $record * @param User $user @@ -50,16 +51,25 @@ class OrderElementViewModel $this->user = $user; } + /** + * @return OrderElement + */ public function getElement() { return $this->element; } + /** + * @return RecordReferenceInterface + */ public function getRecordReference() { return $this->record; } + /** + * @return User + */ public function getAuthenticatedUser() { return $this->user; @@ -75,6 +85,9 @@ class OrderElementViewModel $this->subdefs = $subdefs instanceof \Traversable ? iterator_to_array($subdefs) : $subdefs; } + /** + * @return \media_subdef[] + */ public function getOrderableMediaSubdefs() { return $this->subdefs; diff --git a/lib/Alchemy/Phrasea/Order/OrderTransformer.php b/lib/Alchemy/Phrasea/Order/OrderTransformer.php index 9775031da1..9838e9dafa 100644 --- a/lib/Alchemy/Phrasea/Order/OrderTransformer.php +++ b/lib/Alchemy/Phrasea/Order/OrderTransformer.php @@ -28,7 +28,7 @@ class OrderTransformer extends TransformerAbstract $this->elementTransformer = $elementTransformer; } - public function transform(OrderViewModel $view) + public function transform(OrderView $view) { $order = $view->getOrder(); @@ -47,7 +47,7 @@ class OrderTransformer extends TransformerAbstract return $data; } - public function includeElements(OrderViewModel $order) + public function includeElements(OrderView $order) { $elements = $order->getElements(); diff --git a/lib/Alchemy/Phrasea/Order/OrderViewModel.php b/lib/Alchemy/Phrasea/Order/OrderView.php similarity index 87% rename from lib/Alchemy/Phrasea/Order/OrderViewModel.php rename to lib/Alchemy/Phrasea/Order/OrderView.php index 6acb27bb90..cd43659ba1 100644 --- a/lib/Alchemy/Phrasea/Order/OrderViewModel.php +++ b/lib/Alchemy/Phrasea/Order/OrderView.php @@ -13,14 +13,15 @@ namespace Alchemy\Phrasea\Order; use Alchemy\Phrasea\Model\Entities\Order; use Assert\Assertion; -class OrderViewModel +class OrderView { /** * @var Order */ private $order; + /** - * @var OrderElementViewModel[] + * @var OrderElementView[] */ private $viewElements = []; @@ -33,11 +34,11 @@ class OrderViewModel } /** - * @param $viewElements + * @param OrderElementView[] $viewElements */ public function setViewElements($viewElements) { - Assertion::allIsInstanceOf($viewElements, OrderElementViewModel::class); + Assertion::allIsInstanceOf($viewElements, OrderElementView::class); $this->viewElements = $viewElements instanceof \Traversable ? iterator_to_array($viewElements) : $viewElements; } @@ -51,7 +52,7 @@ class OrderViewModel } /** - * @return OrderElementViewModel[] + * @return OrderElementView[] */ public function getElements() { diff --git a/lib/Alchemy/Phrasea/Order/OrderViewBuilder.php b/lib/Alchemy/Phrasea/Order/OrderViewBuilder.php new file mode 100644 index 0000000000..88f5dc6600 --- /dev/null +++ b/lib/Alchemy/Phrasea/Order/OrderViewBuilder.php @@ -0,0 +1,222 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\Phrasea\Order; + +use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Databox\Subdef\MediaSubdefService; +use Alchemy\Phrasea\Model\Entities\Order; +use Alchemy\Phrasea\Model\Entities\OrderElement; +use Alchemy\Phrasea\Model\Entities\User; +use Alchemy\Phrasea\Model\RecordReferenceInterface; +use Alchemy\Phrasea\Record\RecordReference; +use Alchemy\Phrasea\Record\RecordReferenceCollection; +use Assert\Assertion; + +class OrderViewBuilder +{ + + /** + * @var Application + */ + private $application; + + /** + * @var \appbox + */ + private $applicationBox; + + /** + * @var MediaSubdefService + */ + private $mediaSubdefService; + + /** + * @param Application $application + * @param \appbox $appbox + * @param MediaSubdefService $subdefService + */ + public function __construct(Application $application, \appbox $appbox, MediaSubdefService $subdefService) + { + $this->application = $application; + $this->applicationBox = $appbox; + $this->mediaSubdefService = $subdefService; + } + + public function buildView(Order $order, array $includes) + { + $view = new OrderView($order); + + $this->fillViews([$view], $includes); + + return $view; + } + + /** + * @param Order[] $orders + * @param string[] $includes + * @return OrderView[] + */ + public function buildViews(array $orders, array $includes) + { + Assertion::allIsInstanceOf($orders, Order::class); + + $views = array_map(function (Order $order) { + return new OrderView($order); + }, $orders); + + $this->fillViews($views, $includes); + + return $views; + } + + /** + * @param OrderView[] $views + * @param array $includes + * @return void + */ + private function fillViews(array $views, array $includes) + { + if (!in_array('elements', $includes, true)) { + return; + } + + $elements = $this->gatherElements($views); + + $allElements = $elements ? call_user_func_array('array_merge', $elements) : []; + $allElements = array_combine( + array_map(function (OrderElement $element) { + return $element->getId(); + }, $allElements), + $allElements + ); + + if (!$allElements) { + return; + } + + $collectionToDataboxMap = $this->mapBaseIdToDataboxId($allElements); + + $records = RecordReferenceCollection::fromListExtractor( + $allElements, + function (OrderElement $element) use ($collectionToDataboxMap) { + return isset($collectionToDataboxMap[$element->getBaseId()]) + ? [$collectionToDataboxMap[$element->getBaseId()], $element->getRecordId()] + : null; + }, + function (array $data) { + list ($databoxId, $recordId) = $data; + + return RecordReference::createFromDataboxIdAndRecordId($databoxId, $recordId); + } + ); + + $this->createOrderElementViews($views, $elements, $records); + + if (!in_array('elements.resource_links', $includes, true)) { + return; + } + + // Load all records + $records->toRecords($this->applicationBox); + + // Load all subdefs + $subdefs = $this->mediaSubdefService->findSubdefsFromRecordReferenceCollection($records); + \media_Permalink_Adapter::getMany($this->application, $subdefs); + + $orderableSubdefs = []; + + foreach ($subdefs as $subdef) { + $databoxId = $subdef->get_sbas_id(); + $recordId = $subdef->get_record_id(); + + if (!isset($orderableSubdefs[$databoxId][$recordId])) { + $orderableSubdefs[$databoxId][$recordId] = []; + } + + $orderableSubdefs[$databoxId][$recordId][] = $subdef; + } + + foreach ($views as $model) { + foreach ($model->getElements() as $element) { + $databoxId = $collectionToDataboxMap[$element->getElement()->getBaseId()]; + $recordId = $element->getElement()->getRecordId(); + + if (isset($orderableSubdefs[$databoxId][$recordId])) { + $element->setOrderableMediaSubdefs($orderableSubdefs[$databoxId][$recordId]); + } + } + } + } + + + /** + * @param OrderView[] $elements + * @return OrderElement[][] + */ + private function gatherElements(array $elements) + { + Assertion::allIsInstanceOf($elements, OrderView::class); + + $elements = []; + + foreach ($elements as $index => $model) { + $elements[$index] = $model->getOrder()->getElements()->toArray(); + } + + return $elements; + } + + /** + * @param OrderElement[] $elements + * @return array + */ + private function mapBaseIdToDataboxId(array $elements) + { + $baseIds = array_keys(array_reduce($elements, function (array &$baseIds, OrderElement $element) { + $baseIds[$element->getBaseId()] = true; + + return $baseIds; + }, [])); + + $collectionToDataboxMap = []; + + foreach ($this->application['repo.collection-references']->findMany($baseIds) as $collectionReference) { + $collectionToDataboxMap[$collectionReference->getBaseId()] = $collectionReference->getDataboxId(); + } + + return $collectionToDataboxMap; + } + + /** + * @param OrderView[] $orderViews + * @param OrderElement[][] $elements + * @param RecordReferenceInterface[]|RecordReferenceCollection $records + * @return void + */ + private function createOrderElementViews(array $orderViews, $elements, $records) + { + $user = $this->application->getAuthenticatedUser(); + + foreach ($orderViews as $index => $model) { + $models = []; + + /** @var OrderElement $element */ + foreach ($elements[$index] as $elementIndex => $element) { + if (isset($records[$element->getId()])) { + $models[$elementIndex] = new OrderElementView($element, $records[$element->getId()], $user); + } + } + + $model->setViewElements($models); + } + } +}