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

#object #routes #typo3 #hidden #restriction

#объект #маршруты #typo3 #скрытый #ограничение

Вопрос:

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

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

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

Окружающая среда:

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

Ответ №1:

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

your_extension/ext_localconf.php

 $GLOBALS['TYPO3_CONF_VARS']['SYS']['routing']['aspects']['AdPersistedAliasMapper'] = VendorYourExtensionRoutingAdPersistedAliasMapper::class;
  

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

your_extension/Classes/Routing/AdPersistedAliasMapper.php

 <?php
namespace VendorYourExtensionRouting;

use InvalidArgumentException;
use TYPO3CMSCoreDatabaseConnectionPool;
use TYPO3CMSCoreDatabaseQueryQueryBuilder;
use TYPO3CMSCoreDatabaseQueryRestrictionDeletedRestriction;
use TYPO3CMSCoreDatabaseQueryRestrictionFrontendGroupRestriction;
use TYPO3CMSCoreDatabaseQueryRestrictionFrontendRestrictionContainer;
use TYPO3CMSCoreRoutingAspectPersistedAliasMapper;
use TYPO3CMSCoreUtilityGeneralUtility;

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 и отправляет запрос на сервер для извлечения объекта. Вот откуда возникает ошибка. Поскольку для объекта установлено значение hidden, ограничения по умолчанию ищут UID и hidden=0 и deleted=0 . TYPO3 ничего не находит, поэтому он ломается. Но мы можем избежать этого, получив объект до того, как он достигнет showAction . Для этого мы используем префикс initialize метода TYPO3 по умолчанию. Итак, на вашем контроллере должно быть установлено следующее:

your_extension/Classes/Controller/AdController.php

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

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

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

your_extension/Classes/Domain/Repository/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 результат (если объект действительно существует).

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

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

Комментарии:

1. Как присвоение переменной $ad в initializeShowAction переносит значение в showAction? Разве между ними не хватает шага?

2. вы могли бы просто удалить параметр из showAction и использовать findByUidAndHidden внутри функции.

3. Это означало бы, что мне пришлось бы вручную переназначать измененные значения, которые отправляются в updateAction. Не очень хорошее решение…

4. @Ceremony Я застрял именно на этом этапе. Вы нашли решение?