From f02f3c85a5f27b3aa10e3fe233ac4c0619932b4d Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 14 Jun 2024 16:19:57 +0200 Subject: [PATCH] + Compatible with Sulu 2.6 and Symfony 6.4 + Add phpstan --- changelog.md | 4 + composer.json | 14 +-- phpstan.neon | 12 +++ readme.md | 109 ++++++++++++++++++++- src/Content/NewsDataProvider.php | 27 +++-- src/Content/Type/NewsSelection.php | 2 +- src/Controller/Admin/NewsController.php | 2 +- src/Controller/Admin/SettingController.php | 3 + src/Controller/Website/NewsController.php | 74 +++++--------- src/Domain/Event/NewsCreatedEvent.php | 6 ++ src/Domain/Event/NewsModifiedEvent.php | 6 ++ src/Domain/Event/NewsRestoredEvent.php | 6 ++ src/Entity/News.php | 26 ++++- src/Entity/NewsTranslation.php | 23 ++++- src/Entity/Setting.php | 3 - src/Link/NewsLinkProvider.php | 3 +- src/Preview/NewsObjectProvider.php | 21 +++- src/Repository/NewsRepository.php | 29 +++++- src/Resources/config/services.xml | 2 +- src/Resources/config/services.yaml | 2 + src/Resources/translations/admin.en.json | 25 +++++ src/Resources/translations/messages.en.yml | 5 + src/Routing/NewsRouteDefaultsProvider.php | 2 +- src/Sitemap/NewsSitemapProvider.php | 8 +- src/Trash/NewsTrashItemHandler.php | 6 +- src/Twig/NewsExtension.php | 23 +++-- src/Twig/SettingsExtension.php | 6 +- 27 files changed, 341 insertions(+), 108 deletions(-) create mode 100644 phpstan.neon create mode 100644 src/Resources/translations/admin.en.json create mode 100644 src/Resources/translations/messages.en.yml diff --git a/changelog.md b/changelog.md index bba8920..a72badb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # Changelog +## 2.6.0 (14/06/2024) + ++ Compatible with Sulu 2.6 and Symfony 6.4 + ## 2.4.15 (10/02/2023) - fix pagination diff --git a/composer.json b/composer.json index 2217f3d..dc20ebc 100644 --- a/composer.json +++ b/composer.json @@ -14,14 +14,14 @@ } ], "require": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "sulu/sulu": "^2.4", - "symfony/config": "^4.4 || ^5.0", - "pixelopen/sulu-blockbundle": "^2.4 || ^2.5", - "symfony/dependency-injection": "^4.4 || ^5.0", - "symfony/framework-bundle": "^4.4 || ^5.0", - "symfony/http-foundation": "^4.4 || ^5.0", - "symfony/http-kernel": "^4.4 || ^5.0" + "symfony/config": "^5.0 || ^6.0", + "pixelopen/sulu-blockbundle": "^2.5 || ^2.6", + "symfony/dependency-injection": "^5.0 || ^6.0", + "symfony/framework-bundle": "^5.0 || ^6.0", + "symfony/http-foundation": "^5.0 || ^6.0", + "symfony/http-kernel": "^5.0 || ^6.0" }, "require-dev": { "dantleech/phpcr-migrations-bundle": "^1.3", diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..730fb11 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,12 @@ +parameters: + level: 6 + + checkGenericClassInNonGenericObjectType: false + treatPhpDocTypesAsCertain: false + + paths: + - src + + ignoreErrors: + - '#Negated boolean expression is always false#' + - '#Unable to resolve the template type T in call#' \ No newline at end of file diff --git a/readme.md b/readme.md index 4949df1..d691196 100644 --- a/readme.md +++ b/readme.md @@ -1,11 +1,17 @@ # Sulu news bundle +![GitHub release (with filter)](https://img.shields.io/github/v/release/Pixel-Developpement/sulu-news-bundle?style=for-the-badge) +[![Dependency](https://img.shields.io/badge/sulu-2.5-cca000.svg?style=for-the-badge)](https://sulu.io/) + +## Presentation +A Sulu bundle to manage the news of your website. ## Requirements * PHP >= 7.4 * Sulu >= 2.4.* * Symfony >= 5.4 +* Composer ## Features * List view of News (smart content) @@ -19,7 +25,6 @@ * Automation * SEO - ## Installation ### Install the bundle @@ -28,9 +33,7 @@ Execute the following [composer](https://getcomposer.org/) command to add the bu project: ```bash - composer require pixeldev/sulu-newsbundle --with-all-dependencies - ``` ### Enable the bundle @@ -60,3 +63,103 @@ news.news_api: name_prefix: news. ``` +## Use +### Add/Edit a news +Go to the "News" section in the administration interface. Then, click on "Add". +Fill the fields that are needed for your use. + +Here is the list of the fields: +* Title (mandatory) +* URL (mandatory and filled automatically according to the title) +* Published at (manually filled) +* Cover +* Category (mandatory) +* Content + +The "Content" field is a block content type. The different type of block come from the [Sulu Block Bundle](https://github.com/Pixel-Developpement/sulu-block-bundle) + +Once you finished, click on "Save" + +Your news is not visible on the website yet. In order to do that, click on "Publish?". It should be now visible for visitors. + +To edit a news, simply click on the pencil at the left of the news you wish to edit. + +### Categories +As you may have seen in the previous section, a news needs a category. These categories need to be created in a very specific way: +* You **must** create a root category which **must** have its key named "news" +* Then, under this root category, you create all the news categories you need + +### Remove/Restore a gallery + +There are two ways to remove a news: +* Check every news you want to remove and then click on "Delete" +* Go to the detail of a news (see the "Add/Edit a news" section) and click on "Delete". + +In both cases, the news will be put in the trash. + +To access the trash, go to the "Settings" and click on "Trash". +To restore a news, click on the clock at the left. Confirm the restore. You will be redirected to the detail of the news you restored. + +To remove permanently a news, check all the news you want to remove and click on "Delete". + +## Settings + +This bundle comes with settings. There is only one setting, it's the configuration of a default image. +To access the bundle settings, go to "Settings > News management". + +## Twig extension +There are several twig functions in order to help you use the news and settings on your website: + +**get_latest_news(limit, local)**: returns the latest news. It takes two parameters: +* limit: represents the number of the latest news to display. If no limit is provided, the default value is 3 +* locale: the locale in which the news should be retrieved. If no local is provided, the default value is 'fr' + +Example of use: +```twig +
+ {% set news = get_latest_news(4, app.request.locale) %} + {% for new in news %} + + {% endfor %} +
+``` + +**get_latest_news_html(limit, locale)**: same as get_latest_news but it renders a view instead. It takes two parameters: +* limit: represents the number of the latest news to display. If no limit is provided, the default value is 3 +* locale: the locale in which the news should be retrieved. If no local is provided, the default value is 'fr' + +Example of use: +```twig +
+ {{ get_latest_news_html(4, app.request.locale) }} +
+``` + +**news_settings()**: returns the settings of the bundle. No parameters are required. + +Example of use: + +```twig +{% set newsSettings = news_settings() %} +{% if news.cover is not empty %} + {% set cover = sulu_resolve_media(news.cover.id, 'en' %} + {{ news.name }} +{% else %} + {% set default = sulu_resolve_media(newsSettings.defaultImage.id, 'en' %} + Default news image +{% endif %} +``` + +## Contributing +You can contribute to this bundle. The only thing you must do is respect the coding standard we implement. +You can find them in the `ecs.php` file. diff --git a/src/Content/NewsDataProvider.php b/src/Content/NewsDataProvider.php index 5180ba7..2702bfd 100644 --- a/src/Content/NewsDataProvider.php +++ b/src/Content/NewsDataProvider.php @@ -4,8 +4,8 @@ namespace Pixel\NewsBundle\Content; -use Doctrine\ORM\EntityManagerInterface; -use Pixel\NewsBundle\Entity\News; +use Pixel\NewsBundle\Repository\NewsRepository; +use Sulu\Component\Content\Compat\PropertyParameter; use Sulu\Component\Serializer\ArraySerializerInterface; use Sulu\Component\SmartContent\DataProviderResult; use Sulu\Component\SmartContent\ItemInterface; @@ -17,12 +17,12 @@ class NewsDataProvider extends BaseDataProvider { private RequestStack $requestStack; - private EntityManagerInterface $entityManager; + private NewsRepository $newsRepository; - public function __construct(DataProviderRepositoryInterface $repository, ArraySerializerInterface $serializer, RequestStack $requestStack, EntityManagerInterface $entityManager) + public function __construct(DataProviderRepositoryInterface $repository, ArraySerializerInterface $serializer, RequestStack $requestStack, NewsRepository $newsRepository) { parent::__construct($repository, $serializer); - $this->entityManager = $entityManager; + $this->newsRepository = $newsRepository; $this->requestStack = $requestStack; } @@ -50,6 +50,15 @@ public function getConfiguration() return $this->configuration; } + /** + * @param array $filters + * @param array $propertyParameter + * @param array $options + * @param int $limit + * @param int $page + * @param int $pageSize + * @return DataProviderResult + */ public function resolveResourceItems( array $filters, array $propertyParameter, @@ -61,12 +70,13 @@ public function resolveResourceItems( $locale = $options['locale']; $request = $this->requestStack->getCurrentRequest(); $options['page'] = $request->get('p'); - $news = $this->entityManager->getRepository(News::class)->findByFilters($filters, $page, $pageSize, $limit, $locale, $options); - return new DataProviderResult($news, $this->entityManager->getRepository(News::class)->hasNextPage($filters, $page, $pageSize, $limit, $locale, $options)); + $news = $this->newsRepository->findByFilters($filters, $page, $pageSize, $limit, $locale, $options); + return new DataProviderResult($news, $this->newsRepository->hasNextPage($filters, $page, $pageSize, $limit, $locale, $options)); } /** * Decorates result as data item. + * @param array $data * * @return ItemInterface[] */ @@ -84,8 +94,9 @@ function ($item) { * Returns additional options for query creation. * * @param PropertyParameter[] $propertyParameter + * @param array $options * - * @return array + * @return array */ protected function getOptions(array $propertyParameter, array $options = []) { diff --git a/src/Content/Type/NewsSelection.php b/src/Content/Type/NewsSelection.php index 14266ec..594eb70 100644 --- a/src/Content/Type/NewsSelection.php +++ b/src/Content/Type/NewsSelection.php @@ -5,7 +5,7 @@ namespace Pixel\NewsBundle\Content\Type; use Doctrine\ORM\EntityManagerInterface; -use Pixel\newsBundle\Entity\News; +use Pixel\NewsBundle\Entity\News; use Sulu\Component\Content\Compat\PropertyInterface; use Sulu\Component\Content\SimpleContentType; diff --git a/src/Controller/Admin/NewsController.php b/src/Controller/Admin/NewsController.php index 1fecf66..90e922f 100644 --- a/src/Controller/Admin/NewsController.php +++ b/src/Controller/Admin/NewsController.php @@ -122,7 +122,7 @@ public function getAction(int $id, Request $request): Response return $this->handleView($this->view($item)); } - protected function load(int $id, Request $request, $defaultLocal = null): ?News + protected function load(int $id, Request $request, string $defaultLocal = null): ?News { return $this->repository->findById($id, ($defaultLocal) ? $defaultLocal : (string) $this->getLocale($request)); } diff --git a/src/Controller/Admin/SettingController.php b/src/Controller/Admin/SettingController.php index 4f1892c..b928898 100644 --- a/src/Controller/Admin/SettingController.php +++ b/src/Controller/Admin/SettingController.php @@ -54,6 +54,9 @@ public function putAction(Request $request): Response return $this->handleView($this->view($applicationSetting)); } + /** + * @param array $data + */ public function mapDataToEntity(array $data, Setting $entity): void { $defaultImageId = $data['defaultImage']['id'] ?? null; diff --git a/src/Controller/Website/NewsController.php b/src/Controller/Website/NewsController.php index faca5cb..2f2a37e 100644 --- a/src/Controller/Website/NewsController.php +++ b/src/Controller/Website/NewsController.php @@ -11,24 +11,31 @@ use Sulu\Component\Webspace\Manager\WebspaceManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; +use Twig\Environment; class NewsController extends AbstractController { - /** - * @return string[] - */ - public static function getSubscribedServices() - { - $subscribedServices = parent::getSubscribedServices(); + private TemplateAttributeResolverInterface $templateAttributeResolver; + + private RouteRepositoryInterface $routeRepository; + + private WebspaceManagerInterface $webspaceManager; - $subscribedServices['sulu_core.webspace.webspace_manager'] = WebspaceManagerInterface::class; - $subscribedServices['sulu.repository.route'] = RouteRepositoryInterface::class; - $subscribedServices['sulu_website.resolver.template_attribute'] = TemplateAttributeResolverInterface::class; + private Environment $twig; - return $subscribedServices; + public function __construct(TemplateAttributeResolverInterface $templateAttributeResolver, RouteRepositoryInterface $routeRepository, WebspaceManagerInterface $webspaceManager, Environment $twig) + { + $this->templateAttributeResolver = $templateAttributeResolver; + $this->routeRepository = $routeRepository; + $this->webspaceManager = $webspaceManager; + $this->twig = $twig; } - public function indexAction(News $news, $attributes = [], $preview = false, $partial = false): Response + /** + * @param array $attributes + * @throws \Exception + */ + public function indexAction(News $news, array $attributes = [], bool $preview = false, bool $partial = false): Response { if (!$news->getSeo() || (isset($news->getSeo()['title']) && !$news->getSeo()['title'])) { $seo = [ @@ -37,19 +44,19 @@ public function indexAction(News $news, $attributes = [], $preview = false, $par $news->setSeo($seo); } - $parameters = $this->get('sulu_website.resolver.template_attribute')->resolve([ + $parameters = $this->templateAttributeResolver->resolve([ 'news' => $news, 'localizations' => $this->getLocalizationsArrayForEntity($news), ]); if ($partial) { - $content = $this->renderBlock( + return $this->renderBlock( '@News/news.html.twig', 'content', $parameters ); } elseif ($preview) { - $content = $this->renderPreview( + $content = $this->renderPreview( '@News/news.html.twig', $parameters ); @@ -61,21 +68,22 @@ public function indexAction(News $news, $attributes = [], $preview = false, $par '@News/news.html.twig', $parameters ); + } - return new Response($content); + return new Response((string) $content); } /** - * @return array + * @return array> */ protected function getLocalizationsArrayForEntity(News $entity): array { - $routes = $this->get('sulu.repository.route')->findAllByEntity(News::class, (string) $entity->getId()); + $routes = $this->routeRepository->findAllByEntity(News::class, (string) $entity->getId()); $localizations = []; foreach ($routes as $route) { - $url = $this->get('sulu_core.webspace.webspace_manager')->findUrlByResourceLocator( + $url = $this->webspaceManager->findUrlByResourceLocator( $route->getPath(), null, $route->getLocale() @@ -91,36 +99,8 @@ protected function getLocalizationsArrayForEntity(News $entity): array } /** - * Returns rendered part of template specified by block. - * - * @param mixed $template - * @param mixed $block - * @param mixed $attributes + * @param array $parameters */ - protected function renderBlock($template, $block, $attributes = []) - { - $twig = $this->get('twig'); - $attributes = $twig->mergeGlobals($attributes); - - $template = $twig->load($template); - - $level = ob_get_level(); - ob_start(); - - try { - $rendered = $template->renderBlock($block, $attributes); - ob_end_clean(); - - return $rendered; - } catch (\Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; - } - } - protected function renderPreview(string $view, array $parameters = []): string { $parameters['previewParentTemplate'] = $view; diff --git a/src/Domain/Event/NewsCreatedEvent.php b/src/Domain/Event/NewsCreatedEvent.php index 70cc63a..e132929 100644 --- a/src/Domain/Event/NewsCreatedEvent.php +++ b/src/Domain/Event/NewsCreatedEvent.php @@ -11,8 +11,14 @@ class NewsCreatedEvent extends DomainEvent { private News $news; + /** + * @var array + */ private array $payload; + /** + * @param array $payload + */ public function __construct(News $news, array $payload) { parent::__construct(); diff --git a/src/Domain/Event/NewsModifiedEvent.php b/src/Domain/Event/NewsModifiedEvent.php index cc5eca1..28714e4 100644 --- a/src/Domain/Event/NewsModifiedEvent.php +++ b/src/Domain/Event/NewsModifiedEvent.php @@ -11,8 +11,14 @@ class NewsModifiedEvent extends DomainEvent { private News $news; + /** + * @var array + */ private array $payload; + /** + * @param array $payload + */ public function __construct(News $news, array $payload) { parent::__construct(); diff --git a/src/Domain/Event/NewsRestoredEvent.php b/src/Domain/Event/NewsRestoredEvent.php index f62d96d..d34b2e7 100644 --- a/src/Domain/Event/NewsRestoredEvent.php +++ b/src/Domain/Event/NewsRestoredEvent.php @@ -11,8 +11,14 @@ class NewsRestoredEvent extends DomainEvent { private News $news; + /** + * @var array + */ private array $payload; + /** + * @param array $payload + */ public function __construct(News $news, array $payload) { parent::__construct(); diff --git a/src/Entity/News.php b/src/Entity/News.php index d1fa2ce..5ef5926 100644 --- a/src/Entity/News.php +++ b/src/Entity/News.php @@ -39,7 +39,7 @@ class News * @ORM\JoinColumn(nullable=false) * @Serializer\Expose() */ - private Category $category; + private CategoryInterface $category; /** * @ORM\ManyToOne(targetEntity=MediaInterface::class) @@ -156,6 +156,7 @@ public function setIsPublished(?bool $isPublished): self /** * @Serializer\VirtualProperty(name="seo") + * @return array|null */ public function getSeo(): ?array { @@ -168,6 +169,7 @@ public function getSeo(): ?array /** * @Serializer\VirtualProperty(name="ext") + * @return array|null */ public function getExt(): ?array { @@ -185,6 +187,10 @@ public function getExt(): ?array ]; } + /** + * @param array|null $seo + * @return $this + */ public function setSeo(?array $seo): self { $translation = $this->getTranslation($this->locale); @@ -197,6 +203,7 @@ public function setSeo(?array $seo): self /** * @Serializer\VirtualProperty(name="content") + * @return array|null */ public function getContent(): ?array { @@ -207,14 +214,11 @@ public function getContent(): ?array return $translation->getContent(); } - public function getCategory(): Category + public function getCategory(): CategoryInterface { return $this->category; } - /** - * @param Category $category - */ public function setCategory(CategoryInterface $category): void { $this->category = $category; @@ -230,6 +234,10 @@ public function setCover(?MediaInterface $cover): void $this->cover = $cover; } + /** + * @param array $content + * @return $this + */ public function setContent(array $content): self { $translation = $this->getTranslation($this->locale); @@ -264,6 +272,7 @@ public function setPublishedAt(?\DateTimeImmutable $date): self /** * @Serializer\VirtualProperty(name="excerpt") + * @return array|null */ public function getExcerpt(): ?array { @@ -274,6 +283,10 @@ public function getExcerpt(): ?array return $translation->getExcerpt(); } + /** + * @param array|null $excerpt + * @return $this + */ public function setExcerpt(?array $excerpt): self { $translation = $this->getTranslation($this->locale); @@ -284,6 +297,9 @@ public function setExcerpt(?array $excerpt): self return $this; } + /** + * @return array + */ public function getTranslations(): array { return $this->translations->toArray(); diff --git a/src/Entity/NewsTranslation.php b/src/Entity/NewsTranslation.php index 97fb967..1080b80 100644 --- a/src/Entity/NewsTranslation.php +++ b/src/Entity/NewsTranslation.php @@ -63,18 +63,21 @@ class NewsTranslation implements AuditableInterface /** * @ORM\Column(type="json", nullable=true) * @Serializer\Expose() + * @var array|null */ private ?array $seo = null; /** * @ORM\Column(type="json") * @Serializer\Expose() + * @var array */ private array $content; /** * @ORM\Column(type="json", nullable=true) * @Serializer\Expose() + * @var array|null */ private ?array $excerpt = null; @@ -125,9 +128,6 @@ public function getRoutePath(): string return $this->routePath ?? ''; } - /** - * @return self - */ public function setRoutePath(string $routePath): void { $this->routePath = $routePath; @@ -161,34 +161,49 @@ public function setPublishedAt(?\DateTimeImmutable $publishedAt): void $this->publishedAt = $publishedAt; } + /** + * @return mixed[]|null + */ public function getSeo(): ?array { return $this->seo; } + /** + * @param array|null $seo + */ public function setSeo(?array $seo): void { $this->seo = $seo; } /** - * @return array + * @return array|null */ public function getContent(): ?array { return $this->content ?? []; } + /** + * @param array $content + */ public function setContent(array $content): void { $this->content = $content; } + /** + * @return array|null + */ public function getExcerpt(): ?array { return $this->excerpt; } + /** + * @param array|null $excerpt + */ public function setExcerpt(?array $excerpt): void { $this->excerpt = $excerpt; diff --git a/src/Entity/Setting.php b/src/Entity/Setting.php index eb4ed77..1725dca 100644 --- a/src/Entity/Setting.php +++ b/src/Entity/Setting.php @@ -43,9 +43,6 @@ public function getId(): ?int return $this->id; } - /** - * @return array|null - */ public function getDefaultImage(): ?MediaInterface { return $this->defaultImage; diff --git a/src/Link/NewsLinkProvider.php b/src/Link/NewsLinkProvider.php index 2dd962a..0eca936 100644 --- a/src/Link/NewsLinkProvider.php +++ b/src/Link/NewsLinkProvider.php @@ -38,8 +38,9 @@ public function getConfiguration() public function preload(array $hrefs, $locale, $published = true): array { + $result = []; if (0 === count($hrefs)) { - return []; + return $result; } $items = $this->newsRepository->findBy([ diff --git a/src/Preview/NewsObjectProvider.php b/src/Preview/NewsObjectProvider.php index 7143c76..f8d7302 100644 --- a/src/Preview/NewsObjectProvider.php +++ b/src/Preview/NewsObjectProvider.php @@ -33,15 +33,20 @@ public function getObject($id, $locale): News return $this->newsRepository->find((int) $id); } - public function getId($object): int + /** + * @param News $object + */ + public function getId($object): string { - return $object->getId(); + return (string) $object->getId(); } /** * @param News $object + * @param string $locale + * @param array $data */ - public function setValues($object, $locale, array $data) + public function setValues($object, $locale, array $data): void { $coverId = $data['cover']['id'] ?? null; $categoryId = (isset($data['category']['id'])) ? $data['category']['id'] : $data['category']; @@ -57,6 +62,12 @@ public function setValues($object, $locale, array $data) $object->setSeo($seo); } + /** + * @param object $object + * @param string $locale + * @param array $context + * @return mixed + */ public function setContext($object, $locale, array $context) { if (\array_key_exists('template', $context)) { @@ -79,6 +90,9 @@ public function serialize($object) return serialize($object); } + /** + * @return mixed + */ public function deserialize($serializedObject, $objectClass) { return unserialize($serializedObject); @@ -86,5 +100,6 @@ public function deserialize($serializedObject, $objectClass) public function getSecurityContext($id, $locale): ?string { + return News::SECURITY_CONTEXT; } } diff --git a/src/Repository/NewsRepository.php b/src/Repository/NewsRepository.php index fd45a99..03663bd 100644 --- a/src/Repository/NewsRepository.php +++ b/src/Repository/NewsRepository.php @@ -44,6 +44,9 @@ public function findById(int $id, string $locale): ?News return $news; } + /** + * @return array + */ public function findAllForSitemap(int $page, int $limit): array { $query = $this->createQueryBuilder('n') @@ -52,17 +55,26 @@ public function findAllForSitemap(int $page, int $limit): array return $query->getQuery()->getResult(); } - public function countForSitemap() + public function countForSitemap(): int { $query = $this->createQueryBuilder('n') ->select('count(n)'); return $query->getQuery()->getSingleScalarResult(); } - public function appendJoins(QueryBuilder $queryBuilder, $alias, $locale) + /** + * @param string $alias + * @param string $locale + */ + public function appendJoins(QueryBuilder $queryBuilder, $alias, $locale): void { } + /** + * @param array $filters + * @param array $options + * @return array|object[] + */ public function findByFilters($filters, $page, $pageSize, $limit, $locale, $options = []): array { $entities = $this->getPublishedNews($filters, $locale, $page, $pageSize, $limit, $options); @@ -75,6 +87,12 @@ function (News $entity) use ($locale) { ); } + /** + * @param array $filters + * @param array $options + * @throws \Doctrine\ORM\NoResultException + * @throws \Doctrine\ORM\NonUniqueResultException + */ public function hasNextPage(array $filters, ?int $page, ?int $pageSize, ?int $limit, string $locale, array $options = []): bool { $pageCurrent = (key_exists('page', $options)) ? (int) $options['page'] : 0; @@ -93,7 +111,12 @@ public function hasNextPage(array $filters, ?int $page, ?int $pageSize, ?int $li } } - public function getPublishedNews(array $filters, string $locale, ?int $page, $pageSize, ?int $limit, array $options): array + /** + * @param array $filters + * @param array $options + * @return array + */ + public function getPublishedNews(array $filters, string $locale, ?int $page, ?int $pageSize, ?int $limit, array $options): array { $pageCurrent = (key_exists('page', $options)) ? (int) $options['page'] : 0; diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 76ab432..a5378db 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -82,7 +82,7 @@ - + diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index f69a668..12f7542 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -14,5 +14,7 @@ services: Pixel\NewsBundle\Twig\NewsExtension: public: false autowire: true + arguments: + $newsRepository: "@news.news_repository" tags: - {name: twig.extension} \ No newline at end of file diff --git a/src/Resources/translations/admin.en.json b/src/Resources/translations/admin.en.json new file mode 100644 index 0000000..07c370a --- /dev/null +++ b/src/Resources/translations/admin.en.json @@ -0,0 +1,25 @@ +{ + "news": "News", + "news.title": "Title", + "news.isPublished": "Publish?", + "news.category": "Category", + "news.cover": "Cover", + "news.content": "Content", + "news.contentDetails": "Content details", + "news.text": "Text", + "news.quote": "Quote", + "news.reference": "Reference to the person quoted", + "news.searchName": "News", + "news.newsList": "News list", + "news.emptyNews": "Select a news item", + "news.settings": "News management", + "news_settings.defaultImage": "Default image", + "sulu_activity.resource.news": "News", + "sulu_activity.description.news.created": "{userFullName} created the news \"{resourceTitle}\"", + "sulu_activity.description.news.modified": "{userFullName} edited the news \"{resourceTitle}\"", + "sulu_activity.description.news.removed": "{userFullName} removed the news \"{resourceTitle}\"", + "sulu_activity.description.news.restored": "{userFullName} restored the news \"{resourceTitle}\"", + "news.publish": "Publish", + "news.unpublish": "Unpublish", + "news.publishedAt": "Published at" +} \ No newline at end of file diff --git a/src/Resources/translations/messages.en.yml b/src/Resources/translations/messages.en.yml new file mode 100644 index 0000000..806f1ed --- /dev/null +++ b/src/Resources/translations/messages.en.yml @@ -0,0 +1,5 @@ +alert.message: /!\The page is not visible on the wesite/!\ +news.unpublish: Unpublish +news.publish: Publish +news: News +news.emptyNews: Select a news item diff --git a/src/Routing/NewsRouteDefaultsProvider.php b/src/Routing/NewsRouteDefaultsProvider.php index 8c5e062..e40c359 100644 --- a/src/Routing/NewsRouteDefaultsProvider.php +++ b/src/Routing/NewsRouteDefaultsProvider.php @@ -23,7 +23,7 @@ public function getByEntity($entityClass, $id, $locale, $object = null) { return [ '_controller' => NewsController::class . '::indexAction', - 'news' => $object ?: $this->newsRepository->findById($id, $locale), + 'news' => $object ?: $this->newsRepository->findById((int) $id, $locale), ]; } diff --git a/src/Sitemap/NewsSitemapProvider.php b/src/Sitemap/NewsSitemapProvider.php index 246c38d..9d36170 100644 --- a/src/Sitemap/NewsSitemapProvider.php +++ b/src/Sitemap/NewsSitemapProvider.php @@ -16,6 +16,9 @@ class NewsSitemapProvider implements SitemapProviderInterface private WebspaceManagerInterface $webspaceManager; + /** + * @var array + */ private array $locales = []; public function __construct(NewsRepository $newsRepository, WebspaceManagerInterface $webspaceManager) @@ -41,7 +44,7 @@ public function build($page, $scheme, $host): array return $result; } - private function getLocaleByHost($host) + private function getLocaleByHost(string $host): ?string { if (!\array_key_exists($host, $this->locales)) { $portalInformation = $this->webspaceManager->getPortalInformations(); @@ -54,6 +57,7 @@ private function getLocaleByHost($host) if (isset($this->locales[$host])) { return $this->locales[$host]; } + return null; } public function createSitemap($scheme, $host): Sitemap @@ -68,6 +72,6 @@ public function getAlias(): string public function getMaxPage($scheme, $host) { - return ceil($this->newsRepository->countForSitemap() / self::PAGE_SIZE); + return (int) ceil($this->newsRepository->countForSitemap() / self::PAGE_SIZE); } } diff --git a/src/Trash/NewsTrashItemHandler.php b/src/Trash/NewsTrashItemHandler.php index 4c455c2..9bc0d3a 100644 --- a/src/Trash/NewsTrashItemHandler.php +++ b/src/Trash/NewsTrashItemHandler.php @@ -102,14 +102,14 @@ public function restore(TrashItemInterface $trashItem, array $restoreFormData = return $actu; } - private function createRoute(EntityManagerInterface $manager, int $id, string $slug, string $class) + private function createRoute(EntityManagerInterface $manager, int $id, string $slug, string $class): void { $route = new Route(); $route->setPath($slug); $route->setLocale('fr'); $route->setEntityClass($class); - $route->setEntityId($id); - $route->setHistory(0); + $route->setEntityId((string) $id); + $route->setHistory(false); $route->setCreated(new \DateTime()); $route->setChanged(new \DateTime()); $manager->persist($route); diff --git a/src/Twig/NewsExtension.php b/src/Twig/NewsExtension.php index 9c1591a..4150440 100644 --- a/src/Twig/NewsExtension.php +++ b/src/Twig/NewsExtension.php @@ -2,26 +2,22 @@ namespace Pixel\NewsBundle\Twig; -use Doctrine\ORM\EntityManagerInterface; use Pixel\NewsBundle\Entity\News; -use Symfony\Component\HttpFoundation\RequestStack; +use Pixel\NewsBundle\Repository\NewsRepository; use Twig\Environment; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; class NewsExtension extends AbstractExtension { - private EntityManagerInterface $entityManager; + private NewsRepository $newsRepository; private Environment $environment; - private RequestStack $request; - - public function __construct(EntityManagerInterface $entityManager, Environment $environment, RequestStack $request) + public function __construct(NewsRepository $newsRepository, Environment $environment) { - $this->entityManager = $entityManager; + $this->newsRepository = $newsRepository; $this->environment = $environment; - $this->request = $request; } public function getFunctions() @@ -34,17 +30,20 @@ public function getFunctions() ]; } - public function getLatestNewsHtml(int $limit = 3, $locale = 'fr') + public function getLatestNewsHtml(int $limit = 3, string $locale = 'fr'): string { - $news = $this->entityManager->getRepository(News::class)->findByFilters([], 0, $limit, $limit, $locale); + $news = $this->newsRepository->findByFilters([], 0, $limit, $limit, $locale); ; return $this->environment->render("@News/twig/news.html.twig", [ "news" => $news, ]); } - public function getLatestNews(int $limit = 3, $locale = 'fr') + /** + * @return array + */ + public function getLatestNews(int $limit = 3, string $locale = 'fr'): array { - return $this->entityManager->getRepository(News::class)->findByFilters([], 0, $limit, $limit, $locale); + return $this->newsRepository->findByFilters([], 0, $limit, $limit, $locale); } } diff --git a/src/Twig/SettingsExtension.php b/src/Twig/SettingsExtension.php index 859465a..1002ee4 100644 --- a/src/Twig/SettingsExtension.php +++ b/src/Twig/SettingsExtension.php @@ -3,13 +3,13 @@ namespace Pixel\NewsBundle\Twig; use Doctrine\ORM\EntityManagerInterface; -use Pixel\GalleryBundle\Entity\Setting; +use Pixel\NewsBundle\Entity\Setting; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; class SettingsExtension extends AbstractExtension { - private $entityManager; + private EntityManagerInterface $entityManager; public function __construct(EntityManagerInterface $entityManager) { @@ -23,7 +23,7 @@ public function getFunctions(): array ]; } - public function newsSettings() + public function newsSettings(): Setting { return $this->entityManager->getRepository(Setting::class)->findOneBy([]); }