From fe53ec5837807f873b1f16fc585fcf9a2e8fcaf3 Mon Sep 17 00:00:00 2001 From: Mario Basic Date: Mon, 3 Jul 2017 13:51:25 +0200 Subject: [PATCH] Major revamp. --- .gitignore | 4 +- .travis.yml | 5 +- LICENSE.md | 2 +- README.md | 41 +++---- spec/SitemapIndexSpec.php | 15 ++- spec/SitemapSpec.php | 12 +- spec/UrlSetSpec.php | 14 +-- spec/UrlSpec.php | 85 +++++--------- src/Exceptions/ValidationException.php | 7 -- src/Helpers/Matchers.php | 18 +-- src/Interfaces/Generatable.php | 8 +- src/Interfaces/Renderable.php | 10 +- src/Laravel/Sitemap.php | 95 ---------------- src/Laravel/SitemapInterface.php | 17 --- src/Sitemap.php | 14 +-- src/SitemapIndex.php | 19 ++-- src/Traits/Common.php | 36 +++--- src/Traits/Renderer.php | 15 ++- src/Url.php | 152 ++++++------------------- src/UrlSet.php | 24 ++-- 20 files changed, 177 insertions(+), 416 deletions(-) delete mode 100644 src/Exceptions/ValidationException.php delete mode 100644 src/Laravel/Sitemap.php delete mode 100644 src/Laravel/SitemapInterface.php diff --git a/.gitignore b/.gitignore index aa9d7b4..fd815ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ vendor/ - -.idea \ No newline at end of file +.php_cs.cache +.idea diff --git a/.travis.yml b/.travis.yml index 7f593d9..a9af33e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,8 @@ php: - 5.4 - 5.5 - 5.6 - - hhvm + - 7.0 + - 7.1 before_script: - composer self-update @@ -13,4 +14,4 @@ install: - composer install --prefer-source --no-interaction script: - - vendor/bin/phpspec run \ No newline at end of file + - vendor/bin/phpspec run diff --git a/LICENSE.md b/LICENSE.md index 102d9b8..df35219 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2015 Mario Basic +Copyright (c) 2015-2017 Mario Bašić Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c9bbae2..2529787 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,30 @@ # Bard -[![Build Status](https://travis-ci.org/laravelista/Bard.svg)](https://travis-ci.org/laravelista/Bard) [![Latest Stable Version](https://poser.pugx.org/laravelista/bard/v/stable.svg)](https://packagist.org/packages/laravelista/bard) [![Total Downloads](https://poser.pugx.org/laravelista/bard/downloads.svg)](https://packagist.org/packages/laravelista/bard) [![Latest Unstable Version](https://poser.pugx.org/laravelista/bard/v/unstable.svg)](https://packagist.org/packages/laravelista/bard) [![License](https://poser.pugx.org/laravelista/bard/license.svg)](https://packagist.org/packages/laravelista/bard) [![Join the chat at https://gitter.im/laravelista/Bard](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/laravelista/Bard?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Build Status](https://travis-ci.org/laravelista/Bard.svg)](https://travis-ci.org/laravelista/Bard) [![Latest Stable Version](https://poser.pugx.org/laravelista/bard/v/stable.svg)](https://packagist.org/packages/laravelista/bard) [![Total Downloads](https://poser.pugx.org/laravelista/bard/downloads.svg)](https://packagist.org/packages/laravelista/bard) [![Latest Unstable Version](https://poser.pugx.org/laravelista/bard/v/unstable.svg)](https://packagist.org/packages/laravelista/bard) [![License](https://poser.pugx.org/laravelista/bard/license.svg)](https://packagist.org/packages/laravelista/bard) [![Join the chat at https://gitter.im/laravelista/Bard](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/laravelista/Bard?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ![Bard](http://news.cdn.leagueoflegends.com/public/images/pages/2015/breveal/img/Promo_Bard_Reveal_BardFloating.png) Tired of unstable and bloated PHP sitemap packages? - -**Look no more!** - -Bard is the simplest PHP Sitemap package, just add some urls and you are ready to go. Did I mention that *it supports multilingual locations aka hreflangs*. - -**But wait, there is more.** - -If you are using Laravel you'll have access to some *extra awesomeness* with convenient boilerplate that makes creating sitemaps a breeze. - -## Features - -- Framework Agnostic Sitemap Package -- Laravel Friendly also other Frameworks friendly :) -- Common Sitemap Boilerplate for Laravel and other Frameworks -- Create Sitemaps -- Create Sitemap Index -- Return XML response -- Get XML string -- Input Validation - -**Everything is tested like crazy with PhpSpec** - + +**Look no more!** + +Bard is the simplest PHP Sitemap package, just add some URLs and you are ready to go. Did I mention that *it supports multilingual locations aka hreflangs*. + +## Syntax + +``` +$sitemap->addUrl('http://domain.com/contact') + ->setPriority(0.8) + ->setChangeFrequency('hourly') + ->setLastModification(Carbon::now()) + ->addTranslation('hr', 'http://domain.com/hr/contact'); +``` + ## List of all poems - [Install me gently](https://github.com/laravelista/Bard/wiki/Installation) - [Let me show you how to use me](https://github.com/laravelista/Bard/wiki/Usage) - [Learn the API](https://github.com/laravelista/Bard/wiki/Learn-the-API) - [Laravel + Bard](https://github.com/laravelista/Bard/wiki/Laravel-and-Bard) -- [Laravel Boilerplate](https://github.com/laravelista/Bard/wiki/Laravel-Boilerplate) - ![Bard](http://news.cdn.leagueoflegends.com/public/images/pages/2015/breveal/img/Promo_Bard_Reveal_Mask.png) diff --git a/spec/SitemapIndexSpec.php b/spec/SitemapIndexSpec.php index fbc6e66..24e6c76 100644 --- a/spec/SitemapIndexSpec.php +++ b/spec/SitemapIndexSpec.php @@ -6,33 +6,33 @@ use Prophecy\Argument; use Sabre\Xml\Writer; -class SitemapIndexSpec extends ObjectBehavior { - +class SitemapIndexSpec extends ObjectBehavior +{ use Matchers; - function let() + public function let() { $this->beConstructedWith(new Writer); } - function it_is_initializable() + public function it_is_initializable() { $this->shouldHaveType('Laravelista\Bard\SitemapIndex'); } - function it_adds_sitemap_to_sitemap_index() + public function it_adds_sitemap_to_sitemap_index() { $this->addSitemap('http://acme.me/sitemap.xml')->shouldHaveType('Laravelista\Bard\Sitemap'); } - function it_generates_sitemap_index_xml_string() + public function it_generates_sitemap_index_xml_string() { $this->addSitemap('http://acme.me/sitemap.xml', Carbon::now()); $this->generate()->shouldBeValidXml(); } - function it_renders_sitemap_index_in_xml_response() + public function it_renders_sitemap_index_in_xml_response() { $this->addSitemap('http://acme.me/sitemap.xml', Carbon::now()); @@ -40,5 +40,4 @@ function it_renders_sitemap_index_in_xml_response() $this->render()->shouldHaveType('Symfony\Component\HttpFoundation\Response'); } - } diff --git a/spec/SitemapSpec.php b/spec/SitemapSpec.php index 9a68c6c..cea7d9d 100644 --- a/spec/SitemapSpec.php +++ b/spec/SitemapSpec.php @@ -8,23 +8,23 @@ class SitemapSpec extends ObjectBehavior { - function let() + public function let() { $this->beConstructedWith('http://acme.me/sitemap.xml'); } - function it_is_initializable() + public function it_is_initializable() { $this->shouldHaveType('Laravelista\Bard\Sitemap'); } - function it_sets_location() + public function it_sets_location() { - $this->setLocation('http://acme.me/sitemap.xml')->shouldReturn(true); + $this->setLocation('http://acme.me/sitemap.xml')->shouldReturn($this); } - function it_sets_last_modification() + public function it_sets_last_modification() { - $this->setLastModification(new DateTime("2014-12-22"))->shouldReturn(true); + $this->setLastModification(new DateTime("2014-12-22"))->shouldReturn($this); } } diff --git a/spec/UrlSetSpec.php b/spec/UrlSetSpec.php index 1fa0eb1..14bb49e 100644 --- a/spec/UrlSetSpec.php +++ b/spec/UrlSetSpec.php @@ -5,33 +5,33 @@ use Prophecy\Argument; use Sabre\Xml\Writer; -class UrlSetSpec extends ObjectBehavior { - +class UrlSetSpec extends ObjectBehavior +{ use Matchers; - function let() + public function let() { $this->beConstructedWith(new Writer); } - function it_is_initializable() + public function it_is_initializable() { $this->shouldHaveType('Laravelista\Bard\UrlSet'); } - function it_adds_url_to_urlset() + public function it_adds_url_to_urlset() { $this->addUrl('http://acme.me')->shouldHaveType('Laravelista\Bard\Url'); } - function it_generates_sitemap_xml_string() + public function it_generates_sitemap_xml_string() { $this->addUrl('http://acme.me', 1.0, 'monthly', null, [['hreflang' => 'en', 'href' => "http://acme.me/en"]]); $this->generate()->shouldBeValidXml(); } - function it_renders_sitemap_in_xml_response() + public function it_renders_sitemap_in_xml_response() { $this->addUrl('http://acme.me', 1.0, 'monthly', null, [['hreflang' => 'en', 'href' => "http://acme.me/en"]]); diff --git a/spec/UrlSpec.php b/spec/UrlSpec.php index 13d936d..af78640 100644 --- a/spec/UrlSpec.php +++ b/spec/UrlSpec.php @@ -4,96 +4,63 @@ use PhpSpec\ObjectBehavior; use Prophecy\Argument; -class UrlSpec extends ObjectBehavior { - - function let() +class UrlSpec extends ObjectBehavior +{ + public function let() { $this->beConstructedWith('http://acme.me'); } - function it_is_initializable() + public function it_is_initializable() { $this->shouldHaveType('Laravelista\Bard\Url'); } - function it_sets_priority() + public function it_sets_priority() { // Test all from 0.0 to 1.0 - for ($i = 0.0; $i <= 1; $i += 0.1) - { - $this->setPriority($i)->shouldReturn(true); + for ($i = 0.0; $i <= 1; $i += 0.1) { + $this->setPriority($i)->shouldReturn($this); } } - function it_cannot_set_priority() + public function it_cannot_set_priority() { - $this->shouldThrow('Laravelista\Bard\Exceptions\ValidationException')->duringSetPriority(22); - $this->shouldThrow('Laravelista\Bard\Exceptions\ValidationException')->duringSetPriority(1.1); - $this->shouldThrow('Laravelista\Bard\Exceptions\ValidationException')->duringSetPriority(- 1); + $this->shouldThrow('Exception')->duringSetPriority(22); + $this->shouldThrow('Exception')->duringSetPriority(1.1); + $this->shouldThrow('Exception')->duringSetPriority(- 1); } - function it_sets_location() + public function it_sets_location() { - $this->setLocation('http://acme.me')->shouldReturn(true); + $this->setLocation('http://acme.me')->shouldReturn($this); } - function it_sets_change_frequency() + public function it_sets_change_frequency() { // Test all valid values for change frequency field - foreach ($this->getValidChangeFrequencyValues() as $changeFrequency) - { - $this->setChangeFrequency($changeFrequency)->shouldReturn(true); - } - } - - function it_cannot_set_change_frequency() - { - $this->shouldThrow('Laravelista\Bard\Exceptions\ValidationException')->duringSetChangeFrequency('from time to time'); - } - - function it_sets_last_modification() - { - $this->setLastModification(new DateTime("2014-12-22"))->shouldReturn(true); - } - - function it_sets_translations() - { - $translations = [ - [ - 'hreflang' => 'en', - 'href' => "http://acme.me/en" - ], - [ - 'hreflang' => 'de', - 'href' => "http://acme.me/de" - ] + $validChangeFrequencyValues = [ + "always", "hourly", "daily", "weekly", + "monthly", "yearly", "never" ]; - $this->setTranslations($translations)->shouldReturn(true); + foreach ($validChangeFrequencyValues as $changeFrequency) { + $this->setChangeFrequency($changeFrequency)->shouldReturn($this); + } } - function it_cannot_set_translations() + public function it_cannot_set_change_frequency() { - $this->shouldThrow('Laravelista\Bard\Exceptions\ValidationException')->duringSetTranslations(["bla"]); - $this->shouldThrow('Laravelista\Bard\Exceptions\ValidationException')->duringSetTranslations([['bla', 'bla']]); + $this->shouldThrow('Exception')->duringSetChangeFrequency('from time to time'); } - function it_adds_a_translation() + public function it_sets_last_modification() { - $this->addTranslation('de', "http://acme.me/de")->shouldReturn(true); - - $translation = [ - 'hreflang' => 'de', - 'href' => "http://acme.me/de" - ]; - - $this->addTranslation($translation)->shouldReturn(true); + $this->setLastModification(new DateTime("2014-12-22"))->shouldReturn($this); } - function it_cannot_add_a_translation() + public function it_adds_a_translation() { - $this->shouldThrow('Exception')->duringAddTranslation('de', "http://acme.me/de", "be"); - - $this->shouldThrow('Laravelista\Bard\Exceptions\ValidationException')->duringAddTranslation(["bla"]); + $this->addTranslation('de', "http://acme.me/de")->shouldReturn($this); } } diff --git a/src/Exceptions/ValidationException.php b/src/Exceptions/ValidationException.php deleted file mode 100644 index 0612b78..0000000 --- a/src/Exceptions/ValidationException.php +++ /dev/null @@ -1,7 +0,0 @@ - function ($result) - { - if ( ! simplexml_load_string($result)) return false; + 'beValidXml' => function ($result) { + if (! simplexml_load_string($result)) { + return false; + } return true; } ]; } - -} \ No newline at end of file +} diff --git a/src/Interfaces/Generatable.php b/src/Interfaces/Generatable.php index 95a57e2..347f30b 100644 --- a/src/Interfaces/Generatable.php +++ b/src/Interfaces/Generatable.php @@ -1,9 +1,11 @@ -addNamedRoute($routeName); - } - } - - /** - * Use $this->addUrl() to add named route to sitemap. - * You can also add translations and other properties - * with the object returned from addUrl() method. - * You will probably want to add translations also. - * - * @param $routeName - * @return mixed - */ - abstract public function addNamedRoute($routeName); - - /** - * Get array of translations for given route name. - * Don't forget to specify locales property. - * - * @param $routeName - * @return mixed - */ - public function getNamedRouteTranslations($routeName) - { - $translations = []; - - foreach ($this->locales as $locale) - { - array_push($translations, $this->getNamedRouteTranslation($routeName, $locale)); - } - - return $translations; - } - - /** - * Sets the locales. - * - * @param array $locales - */ - public function setLocales(array $locales) - { - $this->locales = $locales; - } - - /** - * This method returns array with keys href and hreflang. - * - * @param $routeName - * @param $locale - * @return mixed - */ - public function getNamedRouteTranslation($routeName, $locale) - { - return [ - 'href' => $this->getLocalizedUrlForRouteName($routeName, $locale), - 'hreflang' => $locale - ]; - } - - /** - * Implement your own way for getting localized route url. - * - * @param $routeName - * @param $locale - * @return mixed - */ - abstract public function getLocalizedUrlForRouteName($routeName, $locale); -} \ No newline at end of file diff --git a/src/Laravel/SitemapInterface.php b/src/Laravel/SitemapInterface.php deleted file mode 100644 index 426fd10..0000000 --- a/src/Laravel/SitemapInterface.php +++ /dev/null @@ -1,17 +0,0 @@ -setLocation($location); - if ( ! is_null($lastModification)) $this->setLastModification($lastModification); } /** * @param Writer $writer * @return void */ - function xmlSerialize(Writer $writer) + public function xmlSerialize(Writer $writer) { - // This is required $writer->write([ 'loc' => $this->location, ]); - // This is optional $this->add($writer, ['lastmod']); } } diff --git a/src/SitemapIndex.php b/src/SitemapIndex.php index f426d27..e3f0bcb 100644 --- a/src/SitemapIndex.php +++ b/src/SitemapIndex.php @@ -1,12 +1,14 @@ -writer = $writer; } @@ -36,8 +38,7 @@ public function generate() $this->writer->startElement('sitemapindex'); - foreach ($this->sitemaps as $sitemap) - { + foreach ($this->sitemaps as $sitemap) { $this->writer->write([ 'sitemap' => $sitemap ]); @@ -50,14 +51,12 @@ public function generate() /** * @param $location - * @param null $lastModification * @return Sitemap */ - public function addSitemap($location, $lastModification = null) + public function addSitemap($location) { - $this->sitemaps[] = $sitemap = new Sitemap($location, $lastModification); + $this->sitemaps[] = $sitemap = new Sitemap($location); return $sitemap; } - } diff --git a/src/Traits/Common.php b/src/Traits/Common.php index 11d404b..2915be0 100644 --- a/src/Traits/Common.php +++ b/src/Traits/Common.php @@ -1,20 +1,21 @@ -location = $url; - return true; + return $this; } /** * @param DateTime $lastModification - * @return bool */ public function setLastModification(DateTime $lastModification) { $this->lastmod = Carbon::instance($lastModification)->toW3cString(); - return true; + return $this; } /** @@ -45,10 +45,10 @@ public function setLastModification(DateTime $lastModification) */ private function add(Writer $writer, array $properties) { - foreach ($properties as $property) - { - if ( ! is_null($this->$property)) + foreach ($properties as $property) { + if (! is_null($this->$property)) { $writer->write([$property => $this->$property]); + } } } @@ -58,10 +58,8 @@ private function add(Writer $writer, array $properties) */ private function validateUrl($url) { - if ( ! filter_var($url, FILTER_VALIDATE_URL)) - { - throw new ValidationException('Not a valid URL'); + if (! filter_var($url, FILTER_VALIDATE_URL)) { + throw new Exception('Not a valid URL'); } } - -} \ No newline at end of file +} diff --git a/src/Traits/Renderer.php b/src/Traits/Renderer.php index b393c6b..1f066d2 100644 --- a/src/Traits/Renderer.php +++ b/src/Traits/Renderer.php @@ -1,15 +1,18 @@ -generate(), Response::HTTP_OK, ['Content-Type' => 'text/xml']); + return new Response($this->generate(), Response::HTTP_OK, [ + 'Content-Type' => 'text/xml' + ]); } - -} \ No newline at end of file +} diff --git a/src/Url.php b/src/Url.php index dcc17b1..22b9a6a 100644 --- a/src/Url.php +++ b/src/Url.php @@ -1,14 +1,14 @@ -setLocation($location); - if ( ! is_null($priority)) $this->setPriority($priority); - if ( ! is_null($changeFrequency)) $this->setChangeFrequency($changeFrequency); - if ( ! is_null($lastModification)) $this->setLastModification($lastModification); - if ( ! is_null($translations)) $this->setTranslations($translations); } /** @@ -48,26 +31,25 @@ function __construct($location, $priority = null, $changeFrequency = null, DateT * @param Writer $writer * @return void */ - function xmlSerialize(Writer $writer) + public function xmlSerialize(Writer $writer) { - // This is required $writer->write([ 'loc' => $this->location, ]); - // This is optional $this->add($writer, ['priority', 'changefreq', 'lastmod']); $this->addTranslations($writer); } /** + * Used for serialization. + * * @param Writer $writer */ private function addTranslations(Writer $writer) { - foreach ($this->translations as $translation) - { + foreach ($this->translations as $translation) { $writer->write([ [ 'name' => 'xhtml:link', @@ -80,126 +62,62 @@ private function addTranslations(Writer $writer) ] ]); } - - } - - /** - * @param array $translations - * @return bool - * @throws ValidationException - */ - public function setTranslations(array $translations) - { - foreach ($translations as $translation) - { - if ( ! is_array($translation)) - { - throw new ValidationException('Translation must be an array.'); - } - - $this->validateTranslation($translation); - } - - $this->translations = $translations; - - return true; } /** - * Adds a translation to property translations. - * @return bool - * @throws Exception - * @throws ValidationException + * It adds a translation + * + * addTranslation('hr', 'http://domain.com/hr/contact'); + * + * @param $locale + * @param $url */ - public function addTranslation() + public function addTranslation($locale, $url) { - $params = func_get_args(); - - if (is_array($params[0])) - { - $translation = $params[0]; - - $this->validateTranslation($translation); - - $this->translations[] = $translation; - - return true; - } - - if (count($params) != 2) - { - throw new Exception('You must pass array as first parameter or (hreflang and href)'); - } - - $hreflang = $params[0]; - $href = $params[1]; - - $this->validateUrl($href); + $this->validateUrl($url); $this->translations[] = [ - 'hreflang' => $hreflang, - 'href' => $href + 'hreflang' => $locale, + 'href' => $url ]; - return true; - } - - /** - * @param $translation - * @throws ValidationException - */ - private function validateTranslation(array $translation) - { - if ( ! array_key_exists('hreflang', $translation) || ! array_key_exists('href', $translation)) - { - throw new ValidationException('Translation must be an array with hreflang and href keys.'); - } - - $this->validateUrl($translation['href']); + return $this; } /** - * This is only used for testing with PHPSpec. + * It sets change frequency. * - * @return array - */ - public function getValidChangeFrequencyValues() - { - return $this->validChangeFrequencyValues; - } - - /** - * @param null $changeFrequency - * @return bool + * @param $changeFrequency * @throws ValidationException */ public function setChangeFrequency($changeFrequency) { - if ( ! in_array($changeFrequency, $this->getValidChangeFrequencyValues())) - { - throw new ValidationException('Change frequency supports only: always, hourly, daily, weekly, monthly, yearly and never values.'); + if (! in_array($changeFrequency, [ + "always", "hourly", "daily", "weekly", + "monthly", "yearly", "never" + ])) { + throw new Exception('Change frequency not supported!'); } $this->changefreq = $changeFrequency; - return true; + return $this; } /** - * @param null $priority - * @return bool + * It sets priority. + * + * @param $priority * @throws ValidationException */ public function setPriority($priority) { - if ( ! (is_float($priority) && $priority >= 0 && $priority <= 1)) - { - throw new ValidationException('Priority must be >=0.0 and <=1.0'); + if (! (is_float($priority) && $priority >= 0 && $priority <= 1)) { + throw new Exception('Priority must be >=0.0 and <=1.0'); } $this->priority = number_format($priority, 1); - return true; + return $this; } - } diff --git a/src/UrlSet.php b/src/UrlSet.php index 1b13e1e..a8f88e6 100644 --- a/src/UrlSet.php +++ b/src/UrlSet.php @@ -1,12 +1,14 @@ -writer = $writer; } @@ -37,8 +39,7 @@ public function generate() $this->writer->startElement('urlset'); - foreach ($this->urls as $url) - { + foreach ($this->urls as $url) { $this->writer->write([ 'url' => $url ]); @@ -50,18 +51,15 @@ public function generate() } /** + * It adds a URL. + * * @param $location - * @param null $priority - * @param null $changeFrequency - * @param null $lastModification - * @param array $translations * @return Url */ - public function addUrl($location, $priority = null, $changeFrequency = null, $lastModification = null, array $translations = []) + public function addUrl($location) { - $this->urls[] = $url = new Url($location, $priority, $changeFrequency, $lastModification, $translations); + $this->urls[] = $url = new Url($location); return $url; } - }