Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sitemap support #152

Merged
merged 4 commits into from
Jun 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ $ bin/console doctrine:schema:update --force
$ bin/console assets:install
```

### Optional, Sitemap integration
This plugin has a ready to go integration with [Sylius Sitemap Plugin](https://github.com/stefandoorn/sitemap-plugin).

To enable the integration you need to add the following to your `app/config/config.yml` file:
```yaml
# app/config/config.yml
imports:
...
- { resource: "@BitBagSyliusCmsPlugin/Resources/config/services/sitemap_provider.yml" }
```

## Usage

### Blocks
Expand Down
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"license": "MIT",
"require": {
"php": "^7.1",

"sylius/sylius": "^1.1"
},
"require-dev": {
Expand All @@ -19,15 +18,20 @@
"friends-of-behat/service-container-extension": "^1.0",
"friends-of-behat/symfony-extension": "^1.0",
"friends-of-behat/variadic-extension": "^1.0",
"lakion/api-test-case": "^1.1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I upgraded it to ^2.0|^3.1.0 last week, which went fairly easy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surely we would need to upgrade to PHPUnit ^6.0 at least for the whole plugin then? Feels like that belongs to a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True :)

"lakion/mink-debug-extension": "^1.2.3",
"phpspec/phpspec": "^3.2",
"phpstan/phpstan-shim": "^0.9.2",
"phpunit/phpunit": "^5.6",
"se/selenium-server-standalone": "^2.52",
"stefandoorn/sitemap-plugin": "^1.0.8",
"symplify/easy-coding-standard": "^2.4",
"sylius-labs/coding-standard": "^1.0",
"matthiasnoback/symfony-config-test": "^2.1.0"
},
"suggest": {
"stefandoorn/sitemap-plugin": "If you want SEO friendly sitemaps generated for your CMS pages"
},
"prefer-stable": true,
"minimum-stability": "alpha",
"autoload": {
Expand Down
3 changes: 2 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
bootstrap="vendor/autoload.php">
<testsuites>
<testsuite name="BitBagSyliusCmsPlugin Test Suite">

<directory>tests</directory>
</testsuite>
</testsuites>

<php>
<server name="KERNEL_CLASS_PATH" value="/tests/Application/AppKernel.php"/>
<server name="KERNEL_DIR" value="tests/Application/app/" />
<server name="IS_DOCTRINE_ORM_SUPPORTED" value="true"/>
<server name="EXPECTED_RESPONSE_DIR" value="../../Responses/Expected"/>
</php>
</phpunit>
2 changes: 1 addition & 1 deletion src/Fixture/Factory/PageFixtureFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ private function createPage(string $code, array $pageData, bool $generateSlug =
if ($translation['image_path']) {
$image = new PageImage();
$path = $translation['image_path'];
$uploadedImage = new UploadedFile($path, md5($path).'.jpg');
$uploadedImage = new UploadedFile($path, md5($path) . '.jpg');

$image->setFile($uploadedImage);
$pageTranslation->setImage($image);
Expand Down
15 changes: 15 additions & 0 deletions src/Repository/PageRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ public function createListQueryBuilder(string $locale): QueryBuilder
;
}

/**
* {@inheritdoc}
*/
public function findByEnabled(bool $enabled): array
{
return $this->createQueryBuilder('o')
->addSelect('translation')
->innerJoin('o.translations', 'translation')
->andWhere('o.enabled = :enabled')
->setParameter('enabled', $enabled)
->getQuery()
->getResult()
;
}

/**
* {@inheritdoc}
*/
Expand Down
7 changes: 7 additions & 0 deletions src/Repository/PageRepositoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ interface PageRepositoryInterface extends RepositoryInterface
*/
public function createListQueryBuilder(string $locale): QueryBuilder;

/**
* @param bool $enabled
*
* @return array|PageInterface[]
*/
public function findByEnabled(bool $enabled): array;

/**
* @param string $code
* @param string|null $localeCode
Expand Down
2 changes: 1 addition & 1 deletion src/Repository/ProductRepositoryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface ProductRepositoryInterface extends BaseProductRepositoryInterface
{
/**
* @param string $phrase
* @param null|string $locale
* @param string|null $locale
*
* @return array|ProductInterface[]
*/
Expand Down
11 changes: 11 additions & 0 deletions src/Resources/config/services/sitemap_provider.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
bitbag_sylius_cms_plugin.sitemap_provider.page:
class: BitBag\SyliusCmsPlugin\Sitemap\Provider\PageUrlProvider
arguments:
- "@bitbag_sylius_cms_plugin.repository.page"
- "@router"
- "@sylius.sitemap_url_factory"
- "@sylius.context.locale"
- "@sylius.context.channel"
tags:
- "sylius.sitemap_provider"
184 changes: 184 additions & 0 deletions src/Sitemap/Provider/PageUrlProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<?php

declare(strict_types=1);

namespace BitBag\SyliusCmsPlugin\Sitemap\Provider;

use BitBag\SyliusCmsPlugin\Entity\PageInterface;
use BitBag\SyliusCmsPlugin\Entity\PageTranslationInterface;
use BitBag\SyliusCmsPlugin\Repository\PageRepositoryInterface;
use Doctrine\Common\Collections\Collection;
use SitemapPlugin\Factory\SitemapUrlFactoryInterface;
use SitemapPlugin\Model\ChangeFrequency;
use SitemapPlugin\Model\SitemapUrlInterface;
use SitemapPlugin\Provider\UrlProviderInterface;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Locale\Context\LocaleContextInterface;
use Sylius\Component\Locale\Model\LocaleInterface;
use Sylius\Component\Resource\Model\TranslationInterface;
use Symfony\Component\Routing\RouterInterface;

class PageUrlProvider implements UrlProviderInterface
{
/**
* @var PageRepositoryInterface|EntityRepository
*/
private $pageRepository;

/**
* @var RouterInterface
*/
private $router;

/**
* @var SitemapUrlFactoryInterface
*/
private $sitemapUrlFactory;

/**
* @var LocaleContextInterface
*/
private $localeContext;

/**
* @var ChannelContextInterface
*/
private $channelContext;

/**
* @var array
*/
private $urls = [];

/**
* @var array
*/
private $channelLocaleCodes;

/**
* @param PageRepositoryInterface $pageRepository
* @param RouterInterface $router
* @param SitemapUrlFactoryInterface $sitemapUrlFactory
* @param LocaleContextInterface $localeContext
* @param ChannelContextInterface $channelContext
*/
public function __construct(
PageRepositoryInterface $pageRepository,
RouterInterface $router,
SitemapUrlFactoryInterface $sitemapUrlFactory,
LocaleContextInterface $localeContext,
ChannelContextInterface $channelContext
) {
$this->pageRepository = $pageRepository;
$this->router = $router;
$this->sitemapUrlFactory = $sitemapUrlFactory;
$this->localeContext = $localeContext;
$this->channelContext = $channelContext;
}

/**
* @return string
*/
public function getName(): string
{
return 'cms_pages';
}

/**
* {@inheritdoc}
*/
public function generate(): iterable
{
foreach ($this->getPages() as $product) {
$this->urls[] = $this->createPageUrl($product);
}

return $this->urls;
}

/**
* @param PageInterface $page
*
* @return Collection|PageTranslationInterface[]
*/
private function getTranslations(PageInterface $page): Collection
{
return $page->getTranslations()->filter(function (TranslationInterface $translation) {
return $this->localeInLocaleCodes($translation);
});
}

/**
* @param TranslationInterface $translation
*
* @return bool
*/
private function localeInLocaleCodes(TranslationInterface $translation): bool
{
return in_array($translation->getLocale(), $this->getLocaleCodes());
}

/**
* @return array|PageInterface[]
*/
private function getPages(): iterable
{
return $this->pageRepository->findByEnabled(true);
}

/**
* @return array
*/
private function getLocaleCodes(): array
{
if (null === $this->channelLocaleCodes) {
/** @var ChannelInterface $channel */
$channel = $this->channelContext->getChannel();
$this->channelLocaleCodes = $channel->getLocales()->map(function (LocaleInterface $locale) {
return $locale->getCode();
})->toArray();
}

return $this->channelLocaleCodes;
}

/**
* @param PageInterface $page
*
* @return SitemapUrlInterface
*/
private function createPageUrl(PageInterface $page): SitemapUrlInterface
{
$pageUrl = $this->sitemapUrlFactory->createNew();
$pageUrl->setChangeFrequency(ChangeFrequency::daily());
$pageUrl->setPriority(0.7);
if ($page->getUpdatedAt()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't $page always have an updated at? Else fall back to created at maybe?

$pageUrl->setLastModification($page->getUpdatedAt() ?? $page->getCreatedAt());

$pageUrl->setLastModification($page->getUpdatedAt());
} elseif ($page->getCreatedAt()) {
$pageUrl->setLastModification($page->getCreatedAt());
}
/** @var PageTranslationInterface $translation */
foreach ($this->getTranslations($page) as $translation) {
if (!$translation->getLocale()) {
continue;
}
if (!$this->localeInLocaleCodes($translation)) {
continue;
}
$location = $this->router->generate('bitbag_sylius_cms_plugin_shop_page_show', [
'slug' => $translation->getSlug(),
'_locale' => $translation->getLocale(),
]);
if ($translation->getLocale() === $this->localeContext->getLocaleCode()) {
$pageUrl->setLocalization($location);

continue;
}
$pageUrl->addAlternative($location, $translation->getLocale());
}

return $pageUrl;
}
}
72 changes: 72 additions & 0 deletions tests/Api/Sitemap/Provider/AbstractTestController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace Tests\BitBag\SyliusCmsPlugin\Api\Sitemap\Provider;

use Lakion\ApiTestCase\XmlApiTestCase;
use Sylius\Component\Core\Model\Channel;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Currency\Model\Currency;
use Sylius\Component\Currency\Model\CurrencyInterface;
use Sylius\Component\Locale\Model\Locale;
use Sylius\Component\Locale\Model\LocaleInterface;

abstract class AbstractTestController extends XmlApiTestCase
{

/**
* @var ChannelInterface
*/
protected $channel;

/**
* @var LocaleInterface
*/
protected $locale;

/**
* @var LocaleInterface
*/
protected $secondLocale;

/**
* @var CurrencyInterface
*/
protected $currency;

/**
* @before
*/
public function setupDatabase()
{
parent::setUpDatabase();

$this->locale = new Locale();
$this->locale->setCode('en_US');

$this->getEntityManager()->persist($this->locale);

$this->secondLocale = new Locale();
$this->secondLocale->setCode('nl_NL');

$this->getEntityManager()->persist($this->secondLocale);

$this->currency = new Currency();
$this->currency->setCode('USD');

$this->getEntityManager()->persist($this->currency);

$this->channel = new Channel();
$this->channel->setCode('US_WEB');
$this->channel->setName('US Web Store');
$this->channel->setDefaultLocale($this->locale);
$this->channel->setBaseCurrency($this->currency);
$this->channel->setTaxCalculationStrategy('order_items_based');

$this->channel->addLocale($this->locale);
$this->channel->addLocale($this->secondLocale);

$this->getEntityManager()->persist($this->channel);
$this->getEntityManager()->flush();
}

}
Loading