custom/plugins/SasBlogModule/src/SasBlogModule.php line 28

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Sas\BlogModule;
  3. use Doctrine\DBAL\Connection;
  4. use Sas\BlogModule\Content\Blog\BlogEntriesDefinition;
  5. use Sas\BlogModule\Content\Blog\BlogSeoUrlRoute;
  6. use Sas\BlogModule\Content\Blog\Events\BlogIndexerEvent;
  7. use Sas\BlogModule\Util\Lifecycle;
  8. use Sas\BlogModule\Util\Update;
  9. use Shopware\Core\Content\Media\Aggregate\MediaThumbnailSize\MediaThumbnailSizeEntity;
  10. use Shopware\Core\Content\Seo\SeoUrlTemplate\SeoUrlTemplateCollection;
  11. use Shopware\Core\Content\Seo\SeoUrlTemplate\SeoUrlTemplateEntity;
  12. use Shopware\Core\Defaults;
  13. use Shopware\Core\Framework\Context;
  14. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  16. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter;
  17. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\NotFilter;
  19. use Shopware\Core\Framework\Plugin;
  20. use Shopware\Core\Framework\Plugin\Context\InstallContext;
  21. use Shopware\Core\Framework\Plugin\Context\UninstallContext;
  22. use Shopware\Core\Framework\Plugin\Context\UpdateContext;
  23. use Shopware\Core\Framework\Uuid\Uuid;
  24. use Shopware\Core\System\SystemConfig\SystemConfigService;
  25. class SasBlogModule extends Plugin
  26. {
  27.     public const ANONYMOUS_AUTHOR_ID '64f4c60194634128b9b85d9299797c45';
  28.     public function install(InstallContext $installContext): void
  29.     {
  30.         parent::install($installContext);
  31.         $this->createBlogMediaFolder($installContext->getContext());
  32.         $this->getLifeCycle()->install($installContext->getContext());
  33.     }
  34.     public function uninstall(UninstallContext $context): void
  35.     {
  36.         parent::uninstall($context);
  37.         if ($context->keepUserData()) {
  38.             return;
  39.         }
  40.         /*
  41.          * We need to uninstall our default media folder,
  42.          * the media folder and the thumbnail sizes.
  43.          * However, we have to clean this up within a next update :)
  44.          */
  45.         $this->deleteMediaFolder($context->getContext());
  46.         $this->deleteDefaultMediaFolder($context->getContext());
  47.         $this->deleteSeoUrlTemplate($context->getContext());
  48.         /**
  49.          * And of course we need to drop our tables
  50.          */
  51.         $connection $this->container->get(Connection::class);
  52.         $connection->executeStatement('SET FOREIGN_KEY_CHECKS=0;');
  53.         $connection->executeStatement('DROP TABLE IF EXISTS `sas_blog_entries`');
  54.         $connection->executeStatement('DROP TABLE IF EXISTS `sas_blog_entries_translation`');
  55.         $connection->executeStatement('DROP TABLE IF EXISTS `sas_blog_blog_category`');
  56.         $connection->executeStatement('DROP TABLE IF EXISTS `sas_blog_category_translation`');
  57.         $connection->executeStatement('DROP TABLE IF EXISTS `sas_blog_category`');
  58.         $connection->executeStatement('DROP TABLE IF EXISTS `sas_blog_author_translation`');
  59.         $connection->executeStatement('DROP TABLE IF EXISTS `sas_blog_author`');
  60.         /** @var EntityRepositoryInterface $cmsBlockRepo */
  61.         $cmsBlockRepo $this->container->get('cms_block.repository');
  62.         $context Context::createDefaultContext();
  63.         $criteria = new Criteria();
  64.         $criteria->addFilter(new EqualsAnyFilter('type', ['blog-detail''blog-listing']));
  65.         $cmsBlocks $cmsBlockRepo->searchIds($criteria$context);
  66.         $cmsBlockRepo->delete(array_values($cmsBlocks->getData()), $context);
  67.         $connection->executeQuery('SET FOREIGN_KEY_CHECKS=1;');
  68.     }
  69.     public function update(UpdateContext $updateContext): void
  70.     {
  71.         parent::update($updateContext);
  72.         (new Update())->update($this->container$updateContext);
  73.         if (version_compare($updateContext->getCurrentPluginVersion(), '1.1.0''<')) {
  74.             $this->createBlogMediaFolder($updateContext->getContext());
  75.         }
  76.         if (version_compare($updateContext->getCurrentPluginVersion(), '1.5.10''<')) {
  77.             $this->fixSeoUrlTemplate($updateContext->getContext());
  78.             $this->updateSeoUrls($updateContext->getContext());
  79.         }
  80.     }
  81.     /**
  82.      * We need to create a folder for the blog media with it's,
  83.      * own configuration to generate thumbnails for the teaser image.
  84.      */
  85.     public function createBlogMediaFolder(Context $context): void
  86.     {
  87.         $this->deleteDefaultMediaFolder($context);
  88.         $thumbnailSizes $this->getThumbnailSizes($context);
  89.         /** @var EntityRepositoryInterface $mediaFolderRepository */
  90.         $mediaFolderRepository $this->container->get('media_default_folder.repository');
  91.         $data = [
  92.             [
  93.                 'entity' => BlogEntriesDefinition::ENTITY_NAME,
  94.                 'associationFields' => ['media'],
  95.                 'folder' => [
  96.                     'name' => 'Blog Images',
  97.                     'useParentConfiguration' => false,
  98.                     'configuration' => [
  99.                         'createThumbnails' => true,
  100.                         'keepAspectRatio' => true,
  101.                         'thumbnailQuality' => 90,
  102.                         'mediaThumbnailSizes' => $thumbnailSizes,
  103.                     ],
  104.                 ],
  105.             ],
  106.         ];
  107.         $mediaFolderRepository->create($data$context);
  108.     }
  109.     private function deleteDefaultMediaFolder(Context $context): void
  110.     {
  111.         $criteria = new Criteria();
  112.         $criteria->addFilter(
  113.             new EqualsAnyFilter('entity', [
  114.                 BlogEntriesDefinition::ENTITY_NAME,
  115.             ])
  116.         );
  117.         /** @var EntityRepositoryInterface $mediaFolderRepository */
  118.         $mediaFolderRepository $this->container->get('media_default_folder.repository');
  119.         $mediaFolderIds $mediaFolderRepository->searchIds($criteria$context)->getIds();
  120.         if (!empty($mediaFolderIds)) {
  121.             $ids array_map(static function ($id) {
  122.                 return ['id' => $id];
  123.             }, $mediaFolderIds);
  124.             $mediaFolderRepository->delete($ids$context);
  125.         }
  126.     }
  127.     private function deleteMediaFolder(Context $context): void
  128.     {
  129.         $criteria = new Criteria();
  130.         $criteria->addFilter(
  131.             new EqualsFilter('name''Blog Images')
  132.         );
  133.         /** @var EntityRepositoryInterface $mediaFolderRepository */
  134.         $mediaFolderRepository $this->container->get('media_folder.repository');
  135.         $mediaFolderRepository->search($criteria$context);
  136.         $mediaFolderIds $mediaFolderRepository->searchIds($criteria$context)->getIds();
  137.         if (!empty($mediaFolderIds)) {
  138.             $ids array_map(static function ($id) {
  139.                 return ['id' => $id];
  140.             }, $mediaFolderIds);
  141.             $mediaFolderRepository->delete($ids$context);
  142.         }
  143.     }
  144.     private function deleteSeoUrlTemplate(Context $context): void
  145.     {
  146.         $criteria = new Criteria();
  147.         $criteria->addFilter(
  148.             new EqualsFilter('entityName''sas_blog_entries')
  149.         );
  150.         /** @var EntityRepositoryInterface $seoUrlTemplateRepository */
  151.         $seoUrlTemplateRepository $this->container->get('seo_url_template.repository');
  152.         $seoUrlTemplateRepository->search($criteria$context);
  153.         $seoUrlTemplateIds $seoUrlTemplateRepository->searchIds($criteria$context)->getIds();
  154.         if (!empty($seoUrlTemplateIds)) {
  155.             $ids array_map(static function ($id) {
  156.                 return ['id' => $id];
  157.             }, $seoUrlTemplateIds);
  158.             $seoUrlTemplateRepository->delete($ids$context);
  159.         }
  160.     }
  161.     private function getThumbnailSizes(Context $context): array
  162.     {
  163.         $mediaThumbnailSizes = [
  164.             "330x185" => [
  165.                 "width" => 330,
  166.                 "height" => 185,
  167.             ],
  168.             "650x365" => [
  169.                 "width" => 650,
  170.                 "height" => 365,
  171.             ],
  172.             "900x506" => [
  173.                 "width" => 900,
  174.                 "height" => 506,
  175.             ],
  176.             "1280x720" => [
  177.                 "width" => 1280,
  178.                 "height" => 720,
  179.             ],
  180.         ];
  181.         $criteria = new Criteria();
  182.         /** @var EntityRepositoryInterface $thumbnailSizeRepository */
  183.         $thumbnailSizeRepository $this->container->get('media_thumbnail_size.repository');
  184.         $thumbnailSizes $thumbnailSizeRepository->search($criteria$context)->getEntities();
  185.         $mediaThumbnailSizesAddedIds = [];
  186.         /** @var MediaThumbnailSizeEntity $thumbnailSize */
  187.         foreach ($thumbnailSizes as $thumbnailSize) {
  188.             $key $thumbnailSize->getWidth() . 'x' .$thumbnailSize->getHeight();
  189.             if (array_key_exists($key$mediaThumbnailSizes)) {
  190.                 $mediaThumbnailSize $mediaThumbnailSizes[$key];
  191.                 $mediaThumbnailSizesAddedIds[$key] = array_merge(
  192.                     ["id" => $thumbnailSize->getId()],
  193.                     $mediaThumbnailSize,
  194.                 );
  195.                 unset($mediaThumbnailSizes[$key]);
  196.             }
  197.         }
  198.         $mediaThumbnailSizesCreateData = [];
  199.         foreach ($mediaThumbnailSizes as $key => $mediaThumbnailSize) {
  200.             $data array_merge(
  201.                 ["id" => Uuid::randomHex()],
  202.                 $mediaThumbnailSize,
  203.             );
  204.             $mediaThumbnailSizesCreateData[$key] = $data;
  205.             $mediaThumbnailSizesAddedIds[$key] = $data;
  206.         }
  207.         if (count($mediaThumbnailSizesCreateData) > 0) {
  208.             $thumbnailSizeRepository->create(array_values($mediaThumbnailSizesCreateData), $context);
  209.         }
  210.         return array_values($mediaThumbnailSizesAddedIds);
  211.     }
  212.     private function getLifeCycle(): Lifecycle
  213.     {
  214.         /** @var SystemConfigService $systemConfig */
  215.         $systemConfig $this->container->get(SystemConfigService::class);
  216.         /** @var EntityRepositoryInterface $cmsPageRepository */
  217.         $cmsPageRepository $this->container->get('cms_page.repository');
  218.         return new Lifecycle(
  219.             $systemConfig,
  220.             $cmsPageRepository
  221.         );
  222.     }
  223.     private function fixSeoUrlTemplate(Context $context): void
  224.     {
  225.         $criteria = new Criteria();
  226.         $criteria->addFilter(new EqualsFilter('routeName'BlogSeoUrlRoute::ROUTE_NAME));
  227.         $criteria->addFilter(new EqualsFilter('entityName'BlogEntriesDefinition::ENTITY_NAME));
  228.         $criteria->addFilter(new NotFilter(
  229.             NotFilter::CONNECTION_AND,
  230.             [new EqualsFilter('template'null)]
  231.         ));
  232.         /** @var EntityRepositoryInterface $seoUrlTemplateRepository */
  233.         $seoUrlTemplateRepository $this->container->get('seo_url_template.repository');
  234.         /** @var SeoUrlTemplateCollection $seoUrlTemplates */
  235.         $seoUrlTemplates $seoUrlTemplateRepository->search($criteria$context)->getEntities();
  236.         $update = [];
  237.         /** @var SeoUrlTemplateEntity $seoUrlTemplate */
  238.         foreach ($seoUrlTemplates as $seoUrlTemplate) {
  239.             // If the clients fixed it in SEO template we don't have to do again
  240.             if (strpos($seoUrlTemplate->getTemplate(), 'entry.translated')) {
  241.                 continue;
  242.             }
  243.             // We found the issue
  244.             if (!strpos($seoUrlTemplate->getTemplate(), 'entry.title')) {
  245.                 continue;
  246.             }
  247.             $templateReplaced str_replace('entry.title''entry.translated.title'$seoUrlTemplate->getTemplate());
  248.             if (!\is_string($templateReplaced)) {
  249.                 continue;
  250.             }
  251.             $update[] = [
  252.                 'id' => $seoUrlTemplate->getId(),
  253.                 'template' => $templateReplaced
  254.             ];
  255.         }
  256.         if (count($update) === 0) {
  257.             return;
  258.         }
  259.         $seoUrlTemplateRepository->update($update$context);
  260.     }
  261.     private function updateSeoUrls(Context $context): void
  262.     {
  263.         $blogArticlesIds $this->getBlogArticlesIds();
  264.         if (count($blogArticlesIds) === 0) {
  265.             return;
  266.         }
  267.         $eventDispatcher $this->container->get('event_dispatcher');
  268.         $eventDispatcher->dispatch(new BlogIndexerEvent($blogArticlesIds$context));
  269.     }
  270.     private function getBlogArticlesIds(): array
  271.     {
  272.         /** @var Connection $connection */
  273.         $connection $this->container->get(Connection::class);
  274.         if (!$connection->getSchemaManager()->tablesExist([BlogEntriesDefinition::ENTITY_NAME])) {
  275.             return [];
  276.         }
  277.         $now = (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT);
  278.         $query $connection->createQueryBuilder();
  279.         $query->select([
  280.             'LOWER(HEX(id)) as id',
  281.         ]);
  282.         $query->where('active = true')->andWhere('published_at <= :now');
  283.         $query->setParameter('now'$now);
  284.         $query->from(BlogEntriesDefinition::ENTITY_NAME);
  285.         $results $query->execute()->fetchAllAssociative();
  286.         if (empty($results)) {
  287.             return [];
  288.         }
  289.         return array_column($results'id');
  290.     }
  291. }