module/Application/src/Controller/Api/NewController.php
<?php
namespace Application\Controller\Api;
use Application\Hydrator\Api\AbstractRestHydrator;
use Application\Model\Item;
use Application\Model\Picture;
use Application\Model\PictureItem;
use Application\Module;
use Application\Service\DayPictures;
use ArrayAccess;
use Autowp\User\Controller\Plugin\User;
use Exception;
use Laminas\ApiTools\ApiProblem\ApiProblemResponse;
use Laminas\InputFilter\InputFilter;
use Laminas\InputFilter\InputFilterInterface;
use Laminas\Mvc\Controller\AbstractRestfulController;
use Laminas\Stdlib\ResponseInterface;
use Laminas\View\Model\JsonModel;
use Laminas\View\Model\ViewModel;
use Traversable;
use function count;
/**
* @method User user($user = null)
* @method ApiProblemResponse inputFilterResponse(InputFilterInterface $inputFilter)
* @method string language()
*/
class NewController extends AbstractRestfulController
{
private const PER_PAGE = 30;
private Picture $picture;
private InputFilter $inputFilter;
private PictureItem $pictureItem;
private AbstractRestHydrator $pictureHydrator;
private AbstractRestHydrator $pictureThumbnailHydrator;
private Item $itemModel;
private AbstractRestHydrator $itemHydrator;
public function __construct(
Picture $picture,
Item $itemModel,
PictureItem $pictureItem,
InputFilter $inputFilter,
AbstractRestHydrator $pictureHydrator,
AbstractRestHydrator $pictureThumbnailHydrator,
AbstractRestHydrator $itemHydrator
) {
$this->picture = $picture;
$this->inputFilter = $inputFilter;
$this->pictureItem = $pictureItem;
$this->pictureHydrator = $pictureHydrator;
$this->pictureThumbnailHydrator = $pictureThumbnailHydrator;
$this->itemModel = $itemModel;
$this->itemHydrator = $itemHydrator;
}
/**
* @return ViewModel|ResponseInterface|array
* @throws Exception
*/
public function indexAction()
{
$user = $this->user()->get();
$this->inputFilter->setData($this->params()->fromQuery());
if (! $this->inputFilter->isValid()) {
return $this->inputFilterResponse($this->inputFilter);
}
$values = $this->inputFilter->getValues();
$select = $this->picture->getTable()->getSql()->select()
->where(['pictures.status' => Picture::STATUS_ACCEPTED]);
$service = new DayPictures([
'picture' => $this->picture,
'timezone' => $this->user()->timezone(),
'dbTimezone' => Module::MYSQL_TIMEZONE,
'select' => $select,
'orderColumn' => 'accept_datetime',
'currentDate' => $values['date'],
]);
if (! $service->haveCurrentDate() || ! $service->haveCurrentDayPictures()) {
$lastDate = $service->getLastDateStr();
if (! $lastDate) {
return $this->notFoundAction();
}
$service->setCurrentDate($lastDate);
}
$paginator = $service->getPaginator()
->setItemCountPerPage(self::PER_PAGE)
->setCurrentPageNumber($values['page']);
$prevDate = $service->getPrevDate();
$currentDate = $service->getCurrentDate();
$nextDate = $service->getNextDate();
$groupsData = $this->splitPictures($paginator->getCurrentItems());
$this->pictureHydrator->setOptions([
'language' => $this->language(),
'user_id' => $user ? $user['id'] : null,
'fields' => $values['fields']['pictures'] ?? [],
]);
$this->pictureThumbnailHydrator->setOptions([
'language' => $this->language(),
'user_id' => $user ? $user['id'] : null,
'fields' => $values['fields']['item_pictures'] ?? [],
]);
$this->itemHydrator->setOptions([
'language' => $this->language(),
'user_id' => $user ? $user['id'] : null,
'fields' => $values['fields']['item'] ?? [],
]);
$groups = [];
foreach ($groupsData as $groupData) {
$group = [
'type' => $groupData['type'],
];
if ($groupData['type'] === 'item') {
$itemRow = $this->itemModel->getRow(['id' => $groupData['item_id']]);
$group['item'] = $this->itemHydrator->extract($itemRow);
$ids = [];
foreach ($groupData['pictures'] as $picture) {
$ids[] = $picture['id'];
}
$pictureRows = $this->picture->getRows([
'id' => $ids,
'item' => [
'id' => $groupData['item_id'],
],
'limit' => 6,
'order' => 'accept_datetime_desc',
]);
$group['pictures'] = [];
foreach ($pictureRows as $row) {
$group['pictures'][] = $this->pictureThumbnailHydrator->extract($row);
}
$group['total_pictures'] = $this->picture->getCount([
'status' => Picture::STATUS_ACCEPTED,
'item' => [
'id' => $groupData['item_id'],
],
'accept_date' => $values['date'],
'timezone' => $this->user()->timezone(),
]);
} else {
$group['pictures'] = [];
foreach ($groupData['pictures'] as $row) {
$group['pictures'][] = $this->pictureHydrator->extract($row);
}
}
$groups[] = $group;
}
return new JsonModel([
'groups' => $groups,
'paginator' => $paginator->getPages(),
'prev' => [
'date' => $prevDate ? $prevDate->format('Y-m-d') : null,
'count' => $service->getPrevDateCount(),
],
'current' => [
'date' => $currentDate ? $currentDate->format('Y-m-d') : null,
'count' => $service->getCurrentDateCount(),
],
'next' => [
'date' => $nextDate ? $nextDate->format('Y-m-d') : null,
'count' => $service->getNextDateCount(),
],
]);
}
private function expandSmallItems(array $items): array
{
$result = [];
foreach ($items as $item) {
if ($item['type'] !== 'item') {
$result[] = $item;
continue;
}
if (count($item['pictures']) <= 2) {
foreach ($item['pictures'] as $picture) {
$result[] = [
'type' => 'picture',
'picture' => $picture,
];
}
} else {
$result[] = $item;
}
}
return $result;
}
private function mergeSiblings(array $items): array
{
$result = [];
$picturesBuffer = [];
foreach ($items as $itemId => $item) {
if ($item['type'] === 'item') {
if (count($picturesBuffer) > 0) {
$result[] = [
'type' => 'pictures',
'pictures' => $picturesBuffer,
];
$picturesBuffer = [];
}
$result[$itemId] = $item;
} else {
$picturesBuffer[] = $item['picture'];
}
}
if (count($picturesBuffer) > 0) {
$result[] = [
'type' => 'pictures',
'pictures' => $picturesBuffer,
];
}
return $result;
}
/**
* @param array|ArrayAccess|Traversable $pictures
*/
private function splitPictures($pictures): array
{
$items = [];
foreach ($pictures as $pictureRow) {
$itemIds = $this->pictureItem->getPictureItems($pictureRow['id'], PictureItem::PICTURE_CONTENT);
if (count($itemIds) !== 1) {
$items[] = [
'type' => 'picture',
'picture' => $pictureRow,
];
} else {
$itemId = $itemIds[0];
$found = false;
foreach ($items as &$item) {
if ($item['type'] === 'item' && (int) $item['item_id'] === $itemId) {
$item['pictures'][] = $pictureRow;
$found = true;
break;
}
}
unset($item);
if (! $found) {
$items[] = [
'item_id' => $itemId,
'type' => 'item',
'pictures' => [$pictureRow],
];
}
}
}
// convert single picture items to picture record
// merge sibling single items
return $this->mergeSiblings($this->expandSmallItems($items));
}
}