autowp/autowp

View on GitHub
module/Application/src/Controller/Api/GalleryController.php

Summary

Maintainability
D
2 days
Test Coverage
F
0%
<?php

namespace Application\Controller\Api;

use Application\Comments;
use Application\ItemNameFormatter;
use Application\Model\Item;
use Application\Model\Picture;
use Application\Model\PictureItem;
use Application\PictureNameFormatter;
use Autowp\Comments\CommentsService;
use Autowp\Image\Storage;
use Autowp\User\Controller\Plugin\User;
use Exception;
use ImagickException;
use Laminas\Mvc\Controller\AbstractRestfulController;
use Laminas\View\Model\JsonModel;
use Laminas\View\Model\ViewModel;

use function explode;
use function floor;

/**
 * @method User user($user = null)
 * @method string language()
 * @method ViewModel forbiddenAction()
 */
class GalleryController extends AbstractRestfulController
{
    private Picture $picture;

    private CommentsService $comments;

    private PictureNameFormatter $pictureNameFormatter;

    private ItemNameFormatter $itemNameFormatter;

    private PictureItem $pictureItem;

    private Item $itemModel;

    private int $itemsPerPage = 10;

    private Storage $imageStorage;

    public function __construct(
        Picture $picture,
        PictureItem $pictureItem,
        Item $itemModel,
        CommentsService $comments,
        PictureNameFormatter $pictureNameFormatter,
        ItemNameFormatter $itemNameFormatter,
        Storage $imageStorage
    ) {
        $this->picture              = $picture;
        $this->pictureItem          = $pictureItem;
        $this->itemModel            = $itemModel;
        $this->comments             = $comments;
        $this->pictureNameFormatter = $pictureNameFormatter;
        $this->itemNameFormatter    = $itemNameFormatter;
        $this->imageStorage         = $imageStorage;
    }

    /**
     * @throws Exception
     */
    private function getPicturePage(array $filter, string $identity): int
    {
        unset($filter['identity']);
        $filter['columns'] = ['identity'];
        $rows              = $this->picture->getRows($filter);
        foreach ($rows as $index => $row) {
            if ($row['identity'] === $identity) {
                return (int) floor($index / $this->itemsPerPage) + 1;
            }
        }

        return 1;
    }

    /**
     * @return array|ViewModel
     * @throws Storage\Exception
     * @throws ImagickException
     * @throws Exception
     */
    public function galleryAction()
    {
        $itemId = (int) $this->params()->fromQuery('item_id');

        $filter = [
            'order'  => 'resolution_desc',
            'status' => Picture::STATUS_ACCEPTED,
        ];

        $exact = (bool) $this->params()->fromQuery('exact');

        if ($itemId) {
            if ($exact) {
                $filter['item']['id'] = $itemId;
            } else {
                $filter['item']['ancestor_or_self'] = $itemId;
            }
        }

        $exactItemId = (int) $this->params()->fromQuery('exact_item_id');
        if ($exactItemId) {
            $filter['item']['id'] = $exactItemId;
        }

        if ($itemId || $exactItemId) {
            $filter['order'] = 'perspectives';

            $perspectiveId = (int) $this->params()->fromQuery('perspective_id');
            if ($perspectiveId) {
                $filter['item']['perspective'] = $perspectiveId;
            }

            $perspectiveExcludeId = $this->params()->fromQuery('perspective_exclude');
            if ($perspectiveExcludeId) {
                $parts = explode(',', $perspectiveExcludeId);
                $value = [];
                foreach ($parts as $part) {
                    $part = (int) $part;
                    if ($part) {
                        $value[] = $part;
                    }
                }

                $filter['item']['perspective_exclude'] = $value;
            }
        }

        $exactItemLinkType = (int) $this->params()->fromQuery('exact_item_link_type');
        if ($exactItemLinkType) {
            $filter['item']['link_type'] = $exactItemLinkType;
        }

        $page            = $this->params()->fromQuery('page');
        $pictureIdentity = $this->params()->fromQuery('picture_identity');

        if (! $itemId && ! $pictureIdentity && ! $exactItemId) {
            return $this->forbiddenAction();
        }

        switch ($this->params()->fromQuery('status')) {
            case Picture::STATUS_INBOX:
                $filter['status'] = Picture::STATUS_INBOX;
                break;
            case Picture::STATUS_REMOVING:
                $filter['status'] = Picture::STATUS_REMOVING;
                break;
            case Picture::STATUS_ACCEPTED:
            default:
                $filter['status'] = Picture::STATUS_ACCEPTED;
                break;
        }

        $language = $this->language();

        if ($pictureIdentity) {
            if (! $itemId && ! $exactItemId) {
                $filter['identity'] = $pictureIdentity;
            }

            // look for page of that picture
            $filterCopy = $filter;
            unset($filterCopy['status']);
            $filterCopy['columns']  = ['status'];
            $filterCopy['identity'] = $pictureIdentity;

            $row = $this->picture->getRow($filterCopy);

            if (! $row) {
                return $this->notFoundAction();
            }

            $filter['status'] = $row['status'];
            $page             = 0;
            if ($itemId || $exactItemId) {
                $page = $this->getPicturePage($filter, $pictureIdentity);
            }
        }

        $filter['columns'] = [
            'id',
            'identity',
            'name',
            'width',
            'height',
            'image_id',
            'filesize',
            'messages',
        ];

        $paginator = $this->picture->getPaginator($filter);

        $paginator
            ->setItemCountPerPage($this->itemsPerPage)
            ->setCurrentPageNumber($page);

        $rows = $paginator->getCurrentItems();

        // prefetch
        $ids          = [];
        $fullRequests = [];
        $cropRequests = [];
        $crops        = [];
        $imageIds     = [];
        foreach ($rows as $idx => $picture) {
            $imageId            = (int) $picture['image_id'];
            $fullRequests[$idx] = $imageId;

            $crop = $this->imageStorage->getImageCrop($imageId);

            if ($crop) {
                $cropRequests[$idx] = $imageId;
                $crops[$idx]        = $crop;
            }
            $ids[]      = (int) $picture['id'];
            $imageIds[] = $imageId;
        }

        // images
        $images         = $this->imageStorage->getImages($imageIds);
        $fullImagesInfo = $this->imageStorage->getFormatedImages($fullRequests, 'picture-gallery-full');
        $cropImagesInfo = $this->imageStorage->getFormatedImages($cropRequests, 'picture-gallery');

        // names
        $names = $this->picture->getNameData($rows, [
            'language' => $language,
        ]);

        // comments
        $user        = $this->user()->get();
        $userId      = $user ? $user['id'] : null;
        $newMessages = [];
        if ($userId) {
            $newMessages = $this->comments->getNewMessages(
                Comments::PICTURES_TYPE_ID,
                $ids,
                $userId
            );
        }

        $gallery = [];
        foreach ($rows as $idx => $row) {
            $imageId = (int) $row['image_id'];

            if (! $imageId) {
                continue;
            }

            $image = $images[$imageId] ?? null;
            if (! $image) {
                continue;
            }

            $itemId = (int) $row['id'];

            $sUrl = $image->getSrc();

            $crop = null;
            if (isset($cropImagesInfo[$idx]) && isset($crops[$idx])) {
                $crop = $cropImagesInfo[$idx]->toArray();

                $cropInfo = $crops[$idx];

                $crop['crop'] = [
                    'left'   => $cropInfo['left'] / $image->getWidth(),
                    'top'    => $cropInfo['top'] / $image->getHeight(),
                    'width'  => $cropInfo['width'] / $image->getWidth(),
                    'height' => $cropInfo['height'] / $image->getHeight(),
                ];
            }

            $full = isset($fullImagesInfo[$idx]) ? $fullImagesInfo[$idx]->toArray() : null;

            $msgCount    = $row['messages'];
            $newMsgCount = 0;
            if ($userId) {
                $newMsgCount = $newMessages[$itemId] ?? $msgCount;
            }

            $name = $names[$itemId] ?? null;
            $name = $this->pictureNameFormatter->format($name, $language);

            $itemsData = $this->pictureItem->getData([
                'picture'      => $row['id'],
                'onlyWithArea' => true,
            ]);

            $areas = [];
            foreach ($itemsData as $pictureItem) {
                $item = $this->itemModel->getRow(['id' => $pictureItem['item_id']]);
                $area = null;
                if ($pictureItem['area']) {
                    $area = [
                        'left'   => $pictureItem['area'][0] / $image->getWidth(),
                        'top'    => $pictureItem['area'][1] / $image->getHeight(),
                        'width'  => $pictureItem['area'][2] / $image->getWidth(),
                        'height' => $pictureItem['area'][3] / $image->getHeight(),
                    ];
                }
                $areas[] = [
                    'area' => $area,
                    'name' => $this->itemNameFormatter->formatHtml(
                        $this->itemModel->getNameData($item, $language),
                        $language
                    ),
                ];
            }

            $gallery[] = [
                'id'          => $itemId,
                'identity'    => $row['identity'],
                'sourceUrl'   => $sUrl,
                'crop'        => $crop,
                'full'        => $full,
                'messages'    => $msgCount,
                'newMessages' => $newMsgCount,
                'name'        => $name,
                'filesize'    => (int) $row['filesize'],
                'areas'       => $areas,
            ];
        }

        return new JsonModel([
            'page'   => $paginator->getCurrentPageNumber(),
            'pages'  => $paginator->count(),
            'count'  => $paginator->getTotalItemCount(),
            'items'  => $gallery,
            'status' => $filter['status'],
        ]);
    }
}