Refactor to use views

This commit is contained in:
Benoît Burnichon
2016-04-11 21:20:17 +02:00
parent 1274e0f7b3
commit ae32c3e964
8 changed files with 416 additions and 102 deletions

View File

@@ -90,7 +90,7 @@ class MediaSubdefService
foreach ($records->groupPerDataboxId() as $databoxId => $indexes) { foreach ($records->groupPerDataboxId() as $databoxId => $indexes) {
$subdefs = $this->getRepositoryForDatabox($databoxId)->findByRecordIdsAndNames(array_keys($indexes)); $subdefs = $this->getRepositoryForDatabox($databoxId)->findByRecordIdsAndNames(array_keys($indexes));
$carry = $process($carry, $subdefs, $indexes); $carry = $process($carry, $subdefs, $indexes, $databoxId);
} }
return $carry; return $carry;

View File

@@ -18,9 +18,13 @@ use Alchemy\Phrasea\Core\PhraseaEvents;
use Alchemy\Phrasea\Model\Entities\BasketElement; use Alchemy\Phrasea\Model\Entities\BasketElement;
use Alchemy\Phrasea\Model\Entities\Order; use Alchemy\Phrasea\Model\Entities\Order;
use Alchemy\Phrasea\Model\Entities\OrderElement; use Alchemy\Phrasea\Model\Entities\OrderElement;
use Alchemy\Phrasea\Model\RecordReferenceInterface;
use Alchemy\Phrasea\Order\OrderElementTransformer; use Alchemy\Phrasea\Order\OrderElementTransformer;
use Alchemy\Phrasea\Order\OrderElementViewModel;
use Alchemy\Phrasea\Order\OrderFiller; use Alchemy\Phrasea\Order\OrderFiller;
use Alchemy\Phrasea\Order\OrderTransformer; use Alchemy\Phrasea\Order\OrderTransformer;
use Alchemy\Phrasea\Order\OrderViewModel;
use Alchemy\Phrasea\Order\SubdefViewModel;
use Alchemy\Phrasea\Record\RecordReference; use Alchemy\Phrasea\Record\RecordReference;
use Alchemy\Phrasea\Record\RecordReferenceCollection; use Alchemy\Phrasea\Record\RecordReferenceCollection;
use Assert\Assertion; use Assert\Assertion;
@@ -92,11 +96,8 @@ class ApiOrderController extends BaseOrderController
; ;
} }
$collection = $builder->getQuery()->getResult(); $collection = $this->buildOrderViewModels($builder->getQuery()->getResult());
$this->fillViewModels($collection, $fractal->getRequestedIncludes());
if (in_array('elements.resource_links', $fractal->getRequestedIncludes(), false)) {
$this->fetchResourceLinksData($collection);
}
$resource = new Collection($collection, $this->getOrderTransformer()); $resource = new Collection($collection, $this->getOrderTransformer());
@@ -118,15 +119,21 @@ class ApiOrderController extends BaseOrderController
{ {
$order = $this->findOr404($orderId); $order = $this->findOr404($orderId);
$includes = $request->get('includes', []); $fractal = $this->parseIncludes($request->get('includes', []));
if ($order->getUser()->getId() !== $this->getAuthenticatedUser()->getId()) { if ($order->getUser()->getId() !== $this->getAuthenticatedUser()->getId()) {
throw new AccessDeniedHttpException(sprintf('Cannot access order "%d"', $order->getId())); throw new AccessDeniedHttpException(sprintf('Cannot access order "%d"', $order->getId()));
} }
$resource = new Item($order, $this->getOrderTransformer()); $model = $this->buildOrderViewModel($order);
return $this->returnResourceResponse($request, $includes, $resource); $resource = new Item($model, $this->getOrderTransformer());
if (in_array('elements.resource_links', $fractal->getRequestedIncludes(), false)) {
$this->fillViewModels([$resource]);
}
return $this->returnResourceResponse($request, $fractal, $resource);
} }
public function acceptElementsAction(Request $request, $orderId) public function acceptElementsAction(Request $request, $orderId)
@@ -199,7 +206,7 @@ class ApiOrderController extends BaseOrderController
*/ */
private function getOrderTransformer() private function getOrderTransformer()
{ {
return new OrderTransformer(new OrderElementTransformer($this->app)); return new OrderTransformer(new OrderElementTransformer($this->app['media_accessor.subdef_url_generator']));
} }
/** /**
@@ -246,26 +253,34 @@ class ApiOrderController extends BaseOrderController
} }
/** /**
* @param Order[] $orders * @param OrderViewModel[] $models
* @param array $includes
* @return void
*/ */
private function fetchResourceLinksData(array $orders) private function fillViewModels(array $models, array $includes)
{ {
$elements = $this->gatherElements($orders); if (!in_array('elements', $includes, true)) {
return;
$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();
} }
$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
);
if (!$allElements) {
return;
}
$collectionToDataboxMap = $this->mapBaseIdToDataboxId($allElements);
$records = RecordReferenceCollection::fromListExtractor( $records = RecordReferenceCollection::fromListExtractor(
$elements, $allElements,
function (OrderElement $element) use ($collectionToDataboxMap) { function (OrderElement $element) use ($collectionToDataboxMap) {
return isset($collectionToDataboxMap[$element->getBaseId()]) return isset($collectionToDataboxMap[$element->getBaseId()])
? [$collectionToDataboxMap[$element->getBaseId()], $element->getRecordId()] ? [$collectionToDataboxMap[$element->getBaseId()], $element->getRecordId()]
@@ -278,30 +293,129 @@ class ApiOrderController extends BaseOrderController
} }
); );
$this->createOrderElementViewModels($models, $elements, $records);
if (!in_array('elements.resource_links', $includes, true)) {
return;
}
// Load all records // Load all records
$records->toRecords($this->getApplicationBox()); $records->toRecords($this->getApplicationBox());
// Load all subdefs // Load all subdefs
$subdefs = $this->app['service.media_subdef']->findSubdefsFromRecordReferenceCollection($records); $subdefs = $this->app['service.media_subdef']->findSubdefsFromRecordReferenceCollection($records);
\media_Permalink_Adapter::getMany($this->app, $subdefs); $links = \media_Permalink_Adapter::getMany($this->app, $subdefs);
$orderableViews = [];
$views = array_map(null, $subdefs, $links);
foreach ($views as $view) {
/**
* @var \media_subdef $subdef
* @var \media_Permalink_Adapter $link
*/
list ($subdef, $link) = $view;
$databoxId = $subdef->get_sbas_id();
$recordId = $subdef->get_record_id();
if (!isset($orderableViews[$databoxId][$recordId])) {
$orderableViews[$databoxId][$recordId] = [];
}
$orderableViews[$databoxId][$recordId][] = new SubdefViewModel($subdef, $link);
}
foreach ($models as $model) {
foreach ($model->getElements() as $element) {
$databoxId = $collectionToDataboxMap[$element->getElement()->getBaseId()];
$recordId = $element->getElement()->getRecordId();
if (isset($orderableViews[$databoxId][$recordId])) {
$element->setOrderableMediaSubdefs($orderableViews[$databoxId][$recordId]);
}
}
}
} }
/** /**
* @param Order[] $orders * @param Order[] $orders
* @return OrderElement[] * @return OrderViewModel[]
*/ */
private function gatherElements(array $orders) private function buildOrderViewModels(array $orders)
{ {
Assertion::allIsInstanceOf($orders, Order::class); 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 = []; $elements = [];
foreach ($orders as $order) { foreach ($models as $index => $model) {
foreach ($order->getElements() as $element) { $elements[$index] = $model->getOrder()->getElements()->toArray();
$elements[] = $element;
}
} }
return $elements; 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);
}
}
} }

View File

@@ -11,9 +11,7 @@
namespace Alchemy\Phrasea\Order; namespace Alchemy\Phrasea\Order;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Databox\Subdef\MediaSubdefRepository;
use Alchemy\Phrasea\Media\MediaSubDefinitionUrlGenerator; use Alchemy\Phrasea\Media\MediaSubDefinitionUrlGenerator;
use Alchemy\Phrasea\Model\Entities\OrderElement;
use League\Fractal\ParamBag; use League\Fractal\ParamBag;
use League\Fractal\TransformerAbstract; use League\Fractal\TransformerAbstract;
@@ -24,22 +22,25 @@ class OrderElementTransformer extends TransformerAbstract
private $validParams = ['ttl']; private $validParams = ['ttl'];
/** /**
* @var Application * @var MediaSubDefinitionUrlGenerator
*/ */
private $app; private $urlGenerator;
public function __construct(Application $app) public function __construct(MediaSubDefinitionUrlGenerator $urlGenerator)
{ {
$this->app = $app; $this->urlGenerator = $urlGenerator;
} }
public function transform(OrderElement $element) public function transform(OrderElementViewModel $model)
{ {
$element = $model->getElement();
$record = $model->getRecordReference();
$data = [ $data = [
'id' => $element->getId(), 'id' => $element->getId(),
'record' => [ 'record' => [
'databox_id' => $element->getSbasId($this->app), 'databox_id' => $record->getDataboxId(),
'record_id' => $element->getRecordId(), 'record_id' => $record->getRecordId(),
], ],
]; ];
@@ -53,7 +54,7 @@ class OrderElementTransformer extends TransformerAbstract
return $data; return $data;
} }
public function includeResourceLinks(OrderElement $element, ParamBag $params = null) public function includeResourceLinks(OrderElementViewModel $model, ParamBag $params = null)
{ {
$ttl = null; $ttl = null;
@@ -71,13 +72,11 @@ class OrderElementTransformer extends TransformerAbstract
list ($ttl) = $params->get('ttl'); list ($ttl) = $params->get('ttl');
} }
$generator = $this->getSubdefUrlGenerator();
if (null === $ttl) { if (null === $ttl) {
$ttl = $generator->getDefaultTTL(); $ttl = $this->urlGenerator->getDefaultTTL();
} }
$urls = $generator->generateMany($this->app->getAuthenticatedUser(), $this->findOrderableMediaSubdef($element), $ttl); $urls = $this->urlGenerator->generateMany($model->getAuthenticatedUser(), $model->getOrderableMediaSubdefs(), $ttl);
$urls = array_map(null, array_keys($urls), array_values($urls)); $urls = array_map(null, array_keys($urls), array_values($urls));
return $this->collection($urls, function (array $data) use ($ttl) { return $this->collection($urls, function (array $data) use ($ttl) {
@@ -88,45 +87,4 @@ class OrderElementTransformer extends TransformerAbstract
]; ];
}); });
} }
/**
* @param OrderElement $element
* @return \media_subdef[]
*/
private function findOrderableMediaSubdef(OrderElement $element)
{
if (false !== $element->getDeny()) {
return [];
}
$databox = $this->app->findDataboxById($element->getSbasId($this->app));
$record = $databox->get_record($element->getRecordId());
$subdefNames = [];
foreach ($databox->get_subdef_structure()->getSubdefGroup($record->getType()) as $databoxSubdef) {
if ($databoxSubdef->isOrderable()) {
$subdefNames[] = $databoxSubdef->get_name();
}
}
return $this->getMediaSubDefRepository($databox->get_sbas_id())
->findByRecordIdsAndNames([$element->getRecordId()], $subdefNames);
}
/**
* @return MediaSubDefinitionUrlGenerator
*/
private function getSubdefUrlGenerator()
{
return $this->app['media_accessor.subdef_url_generator'];
}
/**
* @return MediaSubdefRepository
*/
private function getMediaSubDefRepository($databoxId)
{
return $this->app['provider.repo.media_subdef']->getRepositoryForDatabox($databoxId);
}
} }

View File

@@ -0,0 +1,82 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* 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\Model\Entities\OrderElement;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Model\RecordReferenceInterface;
use Assert\Assertion;
class OrderElementViewModel
{
/**
* @var OrderElement
*/
private $element;
/**
* @var RecordReferenceInterface
*/
private $record;
/**
* @var User
*/
private $user;
/**
* @var \media_subdef[]
*/
private $subdefs = [];
/**
* OrderElementViewModel constructor.
* @param OrderElement $element
* @param RecordReferenceInterface $record
* @param User $user
*/
public function __construct(OrderElement $element, RecordReferenceInterface $record, User $user)
{
$this->element = $element;
$this->record = $record;
$this->user = $user;
}
public function getElement()
{
return $this->element;
}
public function getRecordReference()
{
return $this->record;
}
public function getAuthenticatedUser()
{
return $this->user;
}
/**
* @param SubdefViewModel[] $subdefs
*/
public function setOrderableMediaSubdefs($subdefs)
{
Assertion::allIsInstanceOf($subdefs, SubdefViewModel::class);
$this->subdefs = $subdefs instanceof \Traversable ? iterator_to_array($subdefs) : $subdefs;
}
public function getOrderableMediaSubdefs()
{
return $this->subdefs;
}
}

View File

@@ -10,7 +10,6 @@
namespace Alchemy\Phrasea\Order; namespace Alchemy\Phrasea\Order;
use Alchemy\Phrasea\Model\Entities\Order;
use League\Fractal\TransformerAbstract; use League\Fractal\TransformerAbstract;
class OrderTransformer extends TransformerAbstract class OrderTransformer extends TransformerAbstract
@@ -29,8 +28,10 @@ class OrderTransformer extends TransformerAbstract
$this->elementTransformer = $elementTransformer; $this->elementTransformer = $elementTransformer;
} }
public function transform(Order $order) public function transform(OrderViewModel $view)
{ {
$order = $view->getOrder();
$data = [ $data = [
'id' => (int)$order->getId(), 'id' => (int)$order->getId(),
'owner_id' => (int)$order->getUser()->getId(), 'owner_id' => (int)$order->getUser()->getId(),
@@ -46,7 +47,7 @@ class OrderTransformer extends TransformerAbstract
return $data; return $data;
} }
public function includeElements(Order $order) public function includeElements(OrderViewModel $order)
{ {
$elements = $order->getElements(); $elements = $order->getElements();

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* 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\Model\Entities\Order;
use Assert\Assertion;
class OrderViewModel
{
/**
* @var Order
*/
private $order;
/**
* @var OrderElementViewModel[]
*/
private $viewElements = [];
/**
* @param Order $order
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* @param $viewElements
*/
public function setViewElements($viewElements)
{
Assertion::allIsInstanceOf($viewElements, OrderElementViewModel::class);
$this->viewElements = $viewElements instanceof \Traversable ? iterator_to_array($viewElements) : $viewElements;
}
/**
* @return Order
*/
public function getOrder()
{
return $this->order;
}
/**
* @return OrderElementViewModel[]
*/
public function getElements()
{
return $this->viewElements;
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Order;
class SubdefViewModel
{
/**
* @var \media_subdef
*/
private $subdef;
/**
* @var \media_Permalink_Adapter
*/
private $link;
public function __construct(\media_subdef $subdef, \media_Permalink_Adapter $link)
{
$this->subdef = $subdef;
$this->link = $link;
}
/**
* @return \media_subdef
*/
public function getSubdef()
{
return $this->subdef;
}
/**
* @return \media_Permalink_Adapter
*/
public function getLink()
{
return $this->link;
}
}

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Record;
use Alchemy\Phrasea\Model\RecordReferenceInterface; use Alchemy\Phrasea\Model\RecordReferenceInterface;
use Assert\Assertion; use Assert\Assertion;
class RecordReferenceCollection implements \IteratorAggregate class RecordReferenceCollection implements \IteratorAggregate, \ArrayAccess
{ {
/** /**
* @param array<int|string,array> $records * @param array<int|string,array> $records
@@ -25,11 +25,11 @@ class RecordReferenceCollection implements \IteratorAggregate
$references = []; $references = [];
foreach ($records as $record) { foreach ($records as $index => $record) {
if (isset($record['id'])) { if (isset($record['id'])) {
$references[] = RecordReference::createFromRecordReference($record['id']); $references[$index] = RecordReference::createFromRecordReference($record['id']);
} elseif (isset($record['databox_id'], $record['record_id'])) { } elseif (isset($record['databox_id'], $record['record_id'])) {
$references[] = RecordReference::createFromDataboxIdAndRecordId($record['databox_id'], $record['record_id']); $references[$index] = RecordReference::createFromDataboxIdAndRecordId($record['databox_id'], $record['record_id']);
} }
} }
@@ -56,7 +56,7 @@ class RecordReferenceCollection implements \IteratorAggregate
}; };
} }
foreach ($list as $item) { foreach ($list as $index => $item) {
$data = $extractor($item); $data = $extractor($item);
if (null === $data) { if (null === $data) {
@@ -66,7 +66,7 @@ class RecordReferenceCollection implements \IteratorAggregate
$reference = $creator($data); $reference = $creator($data);
if ($reference instanceof RecordReferenceInterface) { if ($reference instanceof RecordReferenceInterface) {
$references[] = $reference; $references[$index] = $reference;
} }
} }
@@ -90,22 +90,35 @@ class RecordReferenceCollection implements \IteratorAggregate
{ {
Assertion::allIsInstanceOf($references, RecordReferenceInterface::class); Assertion::allIsInstanceOf($references, RecordReferenceInterface::class);
$this->references = $references instanceof \Traversable ? iterator_to_array($references, false) : array_values($references); $this->references = $references instanceof \Traversable ? iterator_to_array($references, true) : $references;
} }
public function add(RecordReferenceInterface $reference) /**
* @param RecordReferenceInterface $reference
* @param null|string|int $index
*/
public function add(RecordReferenceInterface $reference, $index = null)
{ {
$this->references[] = $reference;
$this->groups = null; $this->groups = null;
if (null === $index) {
$this->references[] = $reference;
return;
}
$this->references[$index] = $reference;
} }
/** /**
* @param int $databoxId * @param int $databoxId
* @param int $recordId * @param int $recordId
* @param null|string|int $index
* @return void
*/ */
public function addRecordReference($databoxId, $recordId) public function addRecordReference($databoxId, $recordId, $index = null)
{ {
$this->add(RecordReference::createFromDataboxIdAndRecordId($databoxId, $recordId)); $this->add(RecordReference::createFromDataboxIdAndRecordId($databoxId, $recordId), $index);
} }
public function getIterator() public function getIterator()
@@ -161,8 +174,48 @@ class RecordReferenceCollection implements \IteratorAggregate
} }
} }
ksort($records); $indexes = array_flip(array_keys($this->references));
uksort($records, function ($keyA, $keyB) use ($indexes) {
$indexA = $indexes[$keyA];
$indexB = $indexes[$keyB];
if ($indexA < $indexB) {
return -1;
} elseif ($indexA > $indexB) {
return 1;
}
return 0;
});
return $records; return $records;
} }
public function offsetExists($offset)
{
return isset($this->references[$offset]);
}
/**
* @param mixed $offset
* @return RecordReferenceInterface
*/
public function offsetGet($offset)
{
return $this->references[$offset];
}
public function offsetSet($offset, $value)
{
Assertion::isInstanceOf($value, RecordReferenceInterface::class);
$this->add($value, $offset);
}
public function offsetUnset($offset)
{
unset($this->references[$offset]);
$this->groups = null;
}
} }