Показывать, редактировать и обновлять скрытые записи во FrontEnd (TYPO3)

Я создаю расширение (Доска объявлений). Пользователь FrontEnd имеет возможность сделать свое объявление скрытым, или объявление получит статус скрытого через некоторое время (срок действия объявления истек). Я столкнулся с двумя проблемами:

  1. если я попытаюсь вызвать его на showAction(), то TYPO3 вернет ошибку, говоря, что объект не был найден, что имеет смысл, поскольку существуют ограничения.
  2. В действии списка URL-адрес действия show не будет отображаться, поскольку аспект persistedAliasMapper отправляет запрос, включающий те же ограничения.

Как мне решить эти проблемы, чтобы пользователь мог редактировать свое объявление?

Окружающая обстановка:

  • TYPO3: 10
  • РЕЖИМ: композитор
  • PHP: 7,4

person Aristeidis Karavas    schedule 18.09.2020    source источник


Ответы (1)


Сначала нам нужно снять ограничение, чтобы можно было отобразить URL-адрес в listAction(). Это довольно просто, поскольку аспект использует функцию createQueryBuilder(), поэтому единственное, что здесь нужно сделать, - это просто переопределить функцию и удалить ограничение Скрытый. Для этого нам нужно расширить класс PersistedAliasMapper. Сначала мы должны объявить класс.

ваше_расширение / ext_localconf.php

$GLOBALS['TYPO3_CONF_VARS']['SYS']['routing']['aspects']['AdPersistedAliasMapper'] = \Vendor\YourExtension\Routing\AdPersistedAliasMapper::class;

Следующим шагом будет фактическое расширение класса. Мы не собираемся отменять ограничения каждый раз, но мы включаем еще одно поле в PersistedAliasMapper аргументы, чтобы мы могли использовать его в определенных конфигурациях.

your_extension / Classes / Routing / AdPersistedAliasMapper.php

<?php
namespace Vendor\YourExtension\Routing;

use InvalidArgumentException;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendGroupRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
use TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class AdPersistedAliasMapper extends PersistedAliasMapper
{
    /**
     * @var bool
     */
    protected $ignoreEnablefields;

    /**
     * @param array $settings
     * @throws InvalidArgumentException
     */
    public function __construct(array $settings)
    {
        $ignoreEnablefields = $settings['ignoreEnablefields'] ?? false;
        $this->ignoreEnablefields = $ignoreEnablefields;
        parent::__construct($settings);
    }

    protected function createQueryBuilder(): QueryBuilder
    {
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
            ->getQueryBuilderForTable($this->tableName)
            ->from($this->tableName);
        if ($this->ignoreEnablefields) {
            $queryBuilder
                ->getRestrictions()
                ->removeAll()
                ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
        }
        else {
            $queryBuilder->setRestrictions(
                GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context)
            );
        }
        $queryBuilder->getRestrictions()->removeByType(FrontendGroupRestriction::class);
        return $queryBuilder;
    }
}

Это позволяет оценить, определено ли поле ignoreEnablefields в config.yaml. Если да, то это

$queryBuilder
      ->getRestrictions()
      ->removeAll()
      ->add(GeneralUtility::makeInstance(DeletedRestriction::class));

снимет все ограничения и снова добавит DeletedRestriction. Вы можете сделать наоборот, если хотите, чтобы удаленные, а не скрытые. Или вы можете просто удалить все, и все URL-адреса объектов будут отображены.

Если ignoreEnablefields не установлен, TYPO3 продолжит нормальное поведение.

Теперь вы можете использовать следующую конфигурацию в своем config.yaml:

config / sites / yourIdentifier / config.yaml

Ad:
    type: Extbase
    extension: YourExtension
    plugin: Yourextension
    routes:
      - routePath: '/{ad}'
         _controller: 'Ad::show'
         _arguments:
            ad: ad
    aspects:
      ad:
        type: AdPersistedAliasMapper
        tableName: tx_yourextension_domain_model_ad
        routeFieldName: path_segment
        ignoreEnablefields: true

Теперь нам нужно снять ограничения на получение объекта и избежать ошибки Объект с UID x не найден. Мой detailAction выглядит так:

/**
 * action show
 *
 * @param Ad $ad
 * @return void
 */
public function showAction(Ad $ad): void
{ }

Обычно TYPO3 получает uid и отправляет запрос на сервер, чтобы получить объект. Отсюда и ошибка. Поскольку объект установлен как скрытый, ограничения по умолчанию ищут UID, hidden=0 и deleted=0. TYPO3 ничего не находит, поэтому ломается. Но этого можно избежать, получив объект до того, как он достигнет showAction. Для этого мы используем префикс метода initialize в TYPO3 по умолчанию. Таким образом, на вашем контроллере должно быть установлено следующее:

ваше_расширение / Классы / Контроллер / AdController.php

protected function initializeShowAction(): void
{
    $adUid = $this->request->getArguments()['ad'];
    $ad = $this->adRepository->findByUidAndHidden($adUid);
}

При этом скрытый объект присваивается переменной $ad, поэтому при вызове showAction() переменная $ad уже содержит объект, который действие ожидает в качестве параметра.

Теперь метод findByUidAndHidden() не является функцией TYPO3 по умолчанию, поэтому мы должны его создать.

ваше_расширение / Классы / Домен / Репозиторий / AdRepository.php

public function findByUidAndHidden($uid)
{
    $query = $this->createQuery();
    $query->getQuerySettings()->setIgnoreEnableFields(array('hidden'));
    $query->matching(
        $query->equals('uid', (int)$uid)
    );
    return $query->execute()[0];
}

Это создает запрос, который не учитывает скрытое поле. Это означает, что скрытый столбец не будет учитываться при отправке запроса. Вместо этого функция может использовать функцию findByIdentifier(). [0] просто возвращает первую запись ответа массива, поскольку всегда есть только 1 результат (если объект действительно существует).

То же самое вы можете использовать для функции редактирования или обновления.

С наилучшими пожеланиями

person Aristeidis Karavas    schedule 18.09.2020
comment
Как присвоение переменной $ ad в initializeShowAction переносит значение в showAction? Есть ли промежуточный шаг? - person Ceremony; 23.06.2021
comment
вы можете просто удалить параметр из showAction и использовать findByUidAndHidden внутри функции. - person Aristeidis Karavas; 23.06.2021
comment
Это означало бы, что мне пришлось бы вручную переназначать измененные значения, которые отправляются в updateAction. Не совсем хорошее решение ... - person Ceremony; 23.06.2021