From bb6419f9cb1936404b85c585d9a196f6cb6965d2 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 14 May 2018 02:46:54 +0300 Subject: [PATCH 1/7] Refactored library to be more flexible --- .gitignore | 2 +- README.md | 73 +- Sitemap.php | 494 ------ composer.json | 12 +- composer.lock | 1475 +++++++++++++++++ src/Extension/AlternateLink.php | 89 + src/Extension/ExtensionInterface.php | 27 + src/Extension/Image.php | 165 ++ src/Extension/Video.php | 67 + src/Frequency.php | 33 + Index.php => src/Index.php | 20 +- src/Sitemap.php | 377 +++++ src/Url.php | 167 ++ .../Writer/DeflateWriter.php | 10 +- .../Writer/PlainFileWriter.php | 10 +- .../Writer/TempFileGZIPWriter.php | 12 +- .../Writer/WriterInterface.php | 7 +- tests/IndexTest.php | 42 +- tests/SitemapTest.php | 321 ++-- tests/TestCase.php | 42 + tests/runtime/.gitignore | 2 + tests/{siteindex.xsd => xsd/index.xsd} | 0 tests/{ => xsd}/sitemap.xsd | 0 tests/{ => xsd}/sitemap_xhtml.xsd | 0 tests/{ => xsd}/xhtml1-strict.xsd | 0 25 files changed, 2663 insertions(+), 784 deletions(-) delete mode 100644 Sitemap.php create mode 100644 composer.lock create mode 100644 src/Extension/AlternateLink.php create mode 100644 src/Extension/ExtensionInterface.php create mode 100644 src/Extension/Image.php create mode 100644 src/Extension/Video.php create mode 100644 src/Frequency.php rename Index.php => src/Index.php (82%) create mode 100644 src/Sitemap.php create mode 100644 src/Url.php rename DeflateWriter.php => src/Writer/DeflateWriter.php (85%) rename PlainFileWriter.php => src/Writer/PlainFileWriter.php (74%) rename TempFileGZIPWriter.php => src/Writer/TempFileGZIPWriter.php (79%) rename WriterInterface.php => src/Writer/WriterInterface.php (79%) create mode 100644 tests/TestCase.php create mode 100644 tests/runtime/.gitignore rename tests/{siteindex.xsd => xsd/index.xsd} (100%) rename tests/{ => xsd}/sitemap.xsd (100%) rename tests/{ => xsd}/sitemap_xhtml.xsd (100%) rename tests/{ => xsd}/xhtml1-strict.xsd (100%) diff --git a/.gitignore b/.gitignore index 5657f6e..22d0d82 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -vendor \ No newline at end of file +vendor diff --git a/README.md b/README.md index c64916b..a2fff7c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Features -------- - Create sitemap files: either regular or gzipped. -- Create multi-language sitemap files. +- Sitemap extensions support. Included extensions are multi-language sitemaps, video sitemaps, image siteamaps. - Create sitemap index files. - Automatically creates new file if either URL limit or file size limit is reached. - Fast and memory efficient. @@ -30,17 +30,29 @@ How to use it ------------- ```php -use samdark\sitemap\Sitemap; -use samdark\sitemap\Index; +use SamDark\Sitemap\Sitemap; +use SamDark\Sitemap\Index; // create sitemap $sitemap = new Sitemap(__DIR__ . '/sitemap.xml'); // add some URLs -$sitemap->addItem('http://example.com/mylink1'); -$sitemap->addItem('http://example.com/mylink2', time()); -$sitemap->addItem('http://example.com/mylink3', time(), Sitemap::HOURLY); -$sitemap->addItem('http://example.com/mylink4', time(), Sitemap::DAILY, 0.3); +$sitemap->addUrl(new Url('http://example.com/mylink1')); +$sitemap->addUrl( + (new Url('http://example.com/mylink2')) + ->setLastModified(new \DateTime()) +); +$sitemap->addUrl( + (new Url('http://example.com/mylink3')) + ->setLastModified(new \DateTime()) + ->setChangeFrequency(Frequency::HOURLY) +); +$sitemap->addUrl( + (new Url('http://example.com/mylink4')) + ->setChangeFrequency(Frequency::DAILY) + ->setLastModified(new \DateTime()) + ->setPriority(0.3) +); // write it $sitemap->write(); @@ -52,9 +64,9 @@ $sitemapFileUrls = $sitemap->getSitemapUrls('http://example.com/'); $staticSitemap = new Sitemap(__DIR__ . '/sitemap_static.xml'); // add some URLs -$staticSitemap->addItem('http://example.com/about'); -$staticSitemap->addItem('http://example.com/tos'); -$staticSitemap->addItem('http://example.com/jobs'); +$staticSitemap->addUrl(new Url('http://example.com/about')); +$staticSitemap->addUrl(new Url('http://example.com/tos')); +$staticSitemap->addUrl(new Url('http://example.com/jobs')); // write it $staticSitemap->write(); @@ -83,36 +95,31 @@ Multi-language sitemap ---------------------- ```php -use samdark\sitemap\Sitemap; +use SamDark\Sitemap\Sitemap; -// create sitemap -// be sure to pass `true` as second parameter to specify XHTML namespace -$sitemap = new Sitemap(__DIR__ . '/sitemap_multi_language.xml', true); - -// Set URL limit to fit in default limit of 50000 (default limit / number of languages) -$sitemap->setMaxUrls(25000); +// create sitemap declaring you need alternate links support +$sitemap = new Sitemap(__DIR__ . '/sitemap_multi_language.xml', [AlternateLink::class]); // add some URLs -$sitemap->addItem('http://example.com/mylink1'); - -$sitemap->addItem([ - 'ru' => 'http://example.com/ru/mylink2', - 'en' => 'http://example.com/en/mylink2', -], time()); -$sitemap->addItem([ - 'ru' => 'http://example.com/ru/mylink3', - 'en' => 'http://example.com/en/mylink3', -], time(), Sitemap::HOURLY); - -$sitemap->addItem([ - 'ru' => 'http://example.com/ru/mylink4', - 'en' => 'http://example.com/en/mylink4', -], time(), Sitemap::DAILY, 0.3); +$sitemap->addUrl( + (new Url('http://example.com/en/mylink2')) + ->setLastModified(new \DateTime()) + ->setChangeFrequency(Frequency::HOURLY) + ->add(new AlternateLink('en', 'http://example.com/en/mylink1')) + ->add(new AlternateLink('ru', 'http://example.com/ru/mylink1')) +); + +$sitemap->addUrl( + (new Url('http://example.com/en/mylink2')) + ->setLastModified(new \DateTime()) + ->setChangeFrequency(Frequency::HOURLY) + ->add(new AlternateLink('en', 'http://example.com/en/mylink2')) + ->add(new AlternateLink('ru', 'http://example.com/ru/mylink2')) +); // write it $sitemap->write(); - ``` Options diff --git a/Sitemap.php b/Sitemap.php deleted file mode 100644 index dc20fd7..0000000 --- a/Sitemap.php +++ /dev/null @@ -1,494 +0,0 @@ - - */ -class Sitemap -{ - const ALWAYS = 'always'; - const HOURLY = 'hourly'; - const DAILY = 'daily'; - const WEEKLY = 'weekly'; - const MONTHLY = 'monthly'; - const YEARLY = 'yearly'; - const NEVER = 'never'; - - /** - * @var integer Maximum allowed number of URLs in a single file. - */ - private $maxUrls = 50000; - - /** - * @var integer number of URLs added - */ - private $urlsCount = 0; - - /** - * @var integer Maximum allowed number of bytes in a single file. - */ - private $maxBytes = 10485760; - - /** - * @var integer number of bytes already written to the current file, before compression - */ - private $byteCount = 0; - - /** - * @var string path to the file to be written - */ - private $filePath; - - /** - * @var integer number of files written - */ - private $fileCount = 0; - - /** - * @var array path of files written - */ - private $writtenFilePaths = array(); - - /** - * @var integer number of URLs to be kept in memory before writing it to file - */ - private $bufferSize = 10; - - /** - * @var bool if XML should be indented - */ - private $useIndent = true; - - /** - * @var bool if should XHTML namespace be specified - * Useful for multi-language sitemap to point crawler to alternate language page via xhtml:link tag. - * @see https://support.google.com/webmasters/answer/2620865?hl=en - */ - private $useXhtml = false; - - /** - * @var array valid values for frequency parameter - */ - private $validFrequencies = array( - self::ALWAYS, - self::HOURLY, - self::DAILY, - self::WEEKLY, - self::MONTHLY, - self::YEARLY, - self::NEVER - ); - - /** - * @var bool whether to gzip the resulting files or not - */ - private $useGzip = false; - - /** - * @var WriterInterface that does the actual writing - */ - private $writerBackend; - - /** - * @var XMLWriter - */ - private $writer; - - /** - * @param string $filePath path of the file to write to - * @param bool $useXhtml is XHTML namespace should be specified - * - * @throws \InvalidArgumentException - */ - public function __construct($filePath, $useXhtml = false) - { - $dir = dirname($filePath); - if (!is_dir($dir)) { - throw new \InvalidArgumentException( - "Please specify valid file path. Directory not exists. You have specified: {$dir}." - ); - } - - $this->filePath = $filePath; - $this->useXhtml = $useXhtml; - } - - /** - * Get array of generated files - * @return array - */ - public function getWrittenFilePath() - { - return $this->writtenFilePaths; - } - - /** - * Creates new file - * @throws \RuntimeException if file is not writeable - */ - private function createNewFile() - { - $this->fileCount++; - $filePath = $this->getCurrentFilePath(); - $this->writtenFilePaths[] = $filePath; - - if (file_exists($filePath)) { - $filePath = realpath($filePath); - if (is_writable($filePath)) { - unlink($filePath); - } else { - throw new \RuntimeException("File \"$filePath\" is not writable."); - } - } - - if ($this->useGzip) { - if (function_exists('deflate_init') && function_exists('deflate_add')) { - $this->writerBackend = new DeflateWriter($filePath); - } else { - $this->writerBackend = new TempFileGZIPWriter($filePath); - } - } else { - $this->writerBackend = new PlainFileWriter($filePath); - } - - $this->writer = new XMLWriter(); - $this->writer->openMemory(); - $this->writer->startDocument('1.0', 'UTF-8'); - $this->writer->setIndent($this->useIndent); - $this->writer->startElement('urlset'); - $this->writer->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9'); - if ($this->useXhtml) { - $this->writer->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); - } - - /* - * XMLWriter does not give us much options, so we must make sure, that - * the header was written correctly and we can simply reuse any - * elements that did not fit into the previous file. (See self::flush) - */ - $this->writer->text(PHP_EOL); - $this->flush(true); - } - - /** - * Writes closing tags to current file - */ - private function finishFile() - { - if ($this->writer !== null) { - $this->writer->endElement(); - $this->writer->endDocument(); - - /* To prevent infinite recursion through flush */ - $this->urlsCount = 0; - - $this->flush(0); - $this->writerBackend->finish(); - $this->writerBackend = null; - - $this->byteCount = 0; - } - } - - /** - * Finishes writing - */ - public function write() - { - $this->finishFile(); - } - - /** - * Flushes buffer into file - * - * @param int $footSize Size of the remaining closing tags - * @throws \OverflowException - */ - private function flush($footSize = 10) - { - $data = $this->writer->flush(true); - $dataSize = mb_strlen($data, '8bit'); - - /* - * Limit the file size of each single site map - * - * We use a heuristic of 10 Bytes for the remainder of the file, - * i.e. plus a new line. - */ - if ($this->byteCount + $dataSize + $footSize > $this->maxBytes) { - if ($this->urlsCount <= 1) { - throw new \OverflowException('The buffer size is too big for the defined file size limit'); - } - $this->finishFile(); - $this->createNewFile(); - } - - $this->writerBackend->append($data); - $this->byteCount += $dataSize; - } - - /** - * Takes a string and validates, if the string - * is a valid url - * - * @param string $location - * @throws \InvalidArgumentException - */ - protected function validateLocation($location) { - if (false === filter_var($location, FILTER_VALIDATE_URL)) { - throw new \InvalidArgumentException( - "The location must be a valid URL. You have specified: {$location}." - ); - } - } - - /** - * Adds a new item to sitemap - * - * @param string|array $location location item URL - * @param integer $lastModified last modification timestamp - * @param string $changeFrequency change frequency. Use one of self:: constants here - * @param string $priority item's priority (0.0-1.0). Default null is equal to 0.5 - * - * @throws \InvalidArgumentException - */ - public function addItem($location, $lastModified = null, $changeFrequency = null, $priority = null) - { - if ($this->urlsCount >= $this->maxUrls) { - $this->finishFile(); - } - - if ($this->writerBackend === null) { - $this->createNewFile(); - } - - if (is_array($location)) { - $this->addMultiLanguageItem($location, $lastModified, $changeFrequency, $priority); - } else { - $this->addSingleLanguageItem($location, $lastModified, $changeFrequency, $priority); - } - - $this->urlsCount++; - - if ($this->urlsCount % $this->bufferSize === 0) { - $this->flush(); - } - } - - - /** - * Adds a new single item to sitemap - * - * @param string $location location item URL - * @param integer $lastModified last modification timestamp - * @param float $changeFrequency change frequency. Use one of self:: constants here - * @param string $priority item's priority (0.0-1.0). Default null is equal to 0.5 - * - * @throws \InvalidArgumentException - * - * @see addItem - */ - private function addSingleLanguageItem($location, $lastModified, $changeFrequency, $priority) - { - $this->validateLocation($location); - - - $this->writer->startElement('url'); - - $this->writer->writeElement('loc', $location); - - if ($lastModified !== null) { - $this->writer->writeElement('lastmod', date('c', $lastModified)); - } - - if ($changeFrequency !== null) { - if (!in_array($changeFrequency, $this->validFrequencies, true)) { - throw new \InvalidArgumentException( - 'Please specify valid changeFrequency. Valid values are: ' - . implode(', ', $this->validFrequencies) - . "You have specified: {$changeFrequency}." - ); - } - - $this->writer->writeElement('changefreq', $changeFrequency); - } - - if ($priority !== null) { - if (!is_numeric($priority) || $priority < 0 || $priority > 1) { - throw new \InvalidArgumentException( - "Please specify valid priority. Valid values range from 0.0 to 1.0. You have specified: {$priority}." - ); - } - $this->writer->writeElement('priority', number_format($priority, 1, '.', ',')); - } - - $this->writer->endElement(); - } - - /** - * Adds a multi-language item, based on multiple locations with alternate hrefs to sitemap - * - * @param array $locations array of language => link pairs - * @param integer $lastModified last modification timestamp - * @param float $changeFrequency change frequency. Use one of self:: constants here - * @param string $priority item's priority (0.0-1.0). Default null is equal to 0.5 - * - * @throws \InvalidArgumentException - * - * @see addItem - */ - private function addMultiLanguageItem($locations, $lastModified, $changeFrequency, $priority) - { - foreach ($locations as $language => $url) { - $this->validateLocation($url); - - $this->writer->startElement('url'); - - $this->writer->writeElement('loc', $url); - - if ($lastModified !== null) { - $this->writer->writeElement('lastmod', date('c', $lastModified)); - } - - if ($changeFrequency !== null) { - if (!in_array($changeFrequency, $this->validFrequencies, true)) { - throw new \InvalidArgumentException( - 'Please specify valid changeFrequency. Valid values are: ' - . implode(', ', $this->validFrequencies) - . "You have specified: {$changeFrequency}." - ); - } - - $this->writer->writeElement('changefreq', $changeFrequency); - } - - if ($priority !== null) { - if (!is_numeric($priority) || $priority < 0 || $priority > 1) { - throw new \InvalidArgumentException( - "Please specify valid priority. Valid values range from 0.0 to 1.0. You have specified: {$priority}." - ); - } - $this->writer->writeElement('priority', number_format($priority, 1, '.', ',')); - } - - foreach ($locations as $hreflang => $href) { - - $this->writer->startElement('xhtml:link'); - $this->writer->startAttribute('rel'); - $this->writer->text('alternate'); - $this->writer->endAttribute(); - - $this->writer->startAttribute('hreflang'); - $this->writer->text($hreflang); - $this->writer->endAttribute(); - - $this->writer->startAttribute('href'); - $this->writer->text($href); - $this->writer->endAttribute(); - $this->writer->endElement(); - } - - $this->writer->endElement(); - } - } - - - /** - * @return string path of currently opened file - */ - private function getCurrentFilePath() - { - if ($this->fileCount < 2) { - return $this->filePath; - } - - $parts = pathinfo($this->filePath); - if ($parts['extension'] === 'gz') { - $filenameParts = pathinfo($parts['filename']); - if (!empty($filenameParts['extension'])) { - $parts['filename'] = $filenameParts['filename']; - $parts['extension'] = $filenameParts['extension'] . '.gz'; - } - } - return $parts['dirname'] . DIRECTORY_SEPARATOR . $parts['filename'] . '_' . $this->fileCount . '.' . $parts['extension']; - } - - /** - * Returns an array of URLs written - * - * @param string $baseUrl base URL of all the sitemaps written - * @return array URLs of sitemaps written - */ - public function getSitemapUrls($baseUrl) - { - $urls = array(); - foreach ($this->writtenFilePaths as $file) { - $urls[] = $baseUrl . pathinfo($file, PATHINFO_BASENAME); - } - return $urls; - } - - /** - * Sets maximum number of URLs to write in a single file. - * Default is 50000. - * @param integer $number - */ - public function setMaxUrls($number) - { - $this->maxUrls = (int)$number; - } - - /** - * Sets maximum number of bytes to write in a single file. - * Default is 10485760 or 10 MiB. - * @param integer $number - */ - public function setMaxBytes($number) - { - $this->maxBytes = (int)$number; - } - - /** - * Sets number of URLs to be kept in memory before writing it to file. - * Default is 10. - * - * @param integer $number - */ - public function setBufferSize($number) - { - $this->bufferSize = (int)$number; - } - - - /** - * Sets if XML should be indented. - * Default is true. - * - * @param bool $value - */ - public function setUseIndent($value) - { - $this->useIndent = (bool)$value; - } - - /** - * Sets whether the resulting files will be gzipped or not. - * @param bool $value - * @throws \RuntimeException when trying to enable gzip while zlib is not available or when trying to change - * setting when some items are already written - */ - public function setUseGzip($value) - { - if ($value && !extension_loaded('zlib')) { - throw new \RuntimeException('Zlib extension must be enabled to gzip the sitemap.'); - } - if ($this->writerBackend !== null && $value != $this->useGzip) { - throw new \RuntimeException('Cannot change the gzip value once items have been added to the sitemap.'); - } - $this->useGzip = $value; - } -} diff --git a/composer.json b/composer.json index fdf7d7c..7c4d2bb 100644 --- a/composer.json +++ b/composer.json @@ -1,4 +1,3 @@ - { "name": "samdark/sitemap", "description": "Sitemap and sitemap index builder", @@ -19,15 +18,20 @@ "source": "https://github.com/samdark/sitemap" }, "require": { - "php": ">=5.3.0", + "php": ">=7.1.0", "ext-xmlwriter": "*" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "~7.1.5" }, "autoload": { "psr-4": { - "samdark\\sitemap\\": "" + "SamDark\\Sitemap\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "SamDark\\Sitemap\\tests\\": "tests" } } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..6c624e5 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1475 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "7df6b111745c1e2ac134452e19aed1c9", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2017-07-22T11:58:36+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-10-19T19:58:43+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2017-03-05T17:38:23+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "~1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2017-11-30T07:14:17+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.7.6", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2018-04-18T13:57:24+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "6.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "52187754b0eed0b8159f62a6fa30073327e8c2ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/52187754b0eed0b8159f62a6fa30073327e8c2ca", + "reference": "52187754b0eed0b8159f62a6fa30073327e8c2ca", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.1", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.1", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-xdebug": "^2.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2018-04-29T14:59:09+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2018-02-01T13:07:23+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2018-02-01T13:16:43+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "7.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "ca64dba53b88aba6af32aebc6b388068db95c435" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ca64dba53b88aba6af32aebc6b388068db95c435", + "reference": "ca64dba53b88aba6af32aebc6b388068db95c435", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0.1", + "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.0", + "phpunit/phpunit-mock-objects": "^6.1.1", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2018-04-29T15:09:19+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "6.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/70c740bde8fd9ea9ea295be1cd875dd7b267e157", + "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.5", + "php": "^7.1", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2018-04-11T04:50:36+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ed5fd2281113729f1ebcc64d101ad66028aeb3d5", + "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5", + "shasum": "" + }, + "require": { + "php": "^7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2018-04-18T13:33:00+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8", + "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "time": "2018-02-01T13:45:15+00:00" + }, + { + "name": "sebastian/environment", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2017-07-01T08:51:00+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2017-04-03T13:19:02+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2018-01-29T19:49:41+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.0", + "ext-xmlwriter": "*" + }, + "platform-dev": [] +} diff --git a/src/Extension/AlternateLink.php b/src/Extension/AlternateLink.php new file mode 100644 index 0000000..04a972a --- /dev/null +++ b/src/Extension/AlternateLink.php @@ -0,0 +1,89 @@ +language = $language; + $this->location = $location; + } + + /** + * Get language of the page + * @return string + */ + public function getLanguage(): string + { + return $this->language; + } + + /** + * Get URL of the page + * @return string + */ + public function getLocation(): string + { + return $this->location; + } + + /** + * @inheritdoc + */ + public static function getLimit(): ?int + { + return null; + } + + /** + * @inheritdoc + */ + public static function writeXmlNamepsace(\XMLWriter $writer): void + { + $writer->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); + } + + /** + * @inheritdoc + */ + public function write(\XMLWriter $writer): void + { + $writer->startElement('xhtml:link'); + $writer->startAttribute('rel'); + $writer->text('alternate'); + $writer->endAttribute(); + + $writer->startAttribute('hreflang'); + $writer->text($this->language); + $writer->endAttribute(); + + $writer->startAttribute('href'); + $writer->text($this->location); + $writer->endAttribute(); + $writer->endElement(); + } +} diff --git a/src/Extension/ExtensionInterface.php b/src/Extension/ExtensionInterface.php new file mode 100644 index 0000000..ae03a7a --- /dev/null +++ b/src/Extension/ExtensionInterface.php @@ -0,0 +1,27 @@ +location = $location; + } + + /** + * @return string + */ + public function getCaption(): string + { + return $this->caption; + } + + /** + * @param string $caption + */ + public function setCaption(string $caption): void + { + $this->caption = $caption; + } + + /** + * @return string + */ + public function getGeoLocation(): string + { + return $this->geoLocation; + } + + /** + * @param string $geoLocation + */ + public function setGeoLocation(string $geoLocation): void + { + $this->geoLocation = $geoLocation; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle($title): void + { + $this->title = $title; + } + + /** + * @return string + */ + public function getLicense(): string + { + return $this->license; + } + + /** + * @param string $license + */ + public function setLicense(string $license): void + { + $this->license = $license; + } + + /** + * @return string + */ + public function getLocation(): string + { + return $this->location; + } + + /** + * @inheritdoc + */ + public static function getLimit(): ?int + { + return self::LIMIT; + } + + /** + * @inheritdoc + */ + public function write(\XMLWriter $writer): void + { + $writer->startElement('image:image'); + + if (!empty($image['loc'])) { + $writer->writeElement('image:loc', $image['loc']); + } + if (!empty($image['caption'])) { + $writer->writeElement('image:caption', $image['caption']); + } + if (!empty($image['geo_location'])) { + $writer->writeElement('image:geo_location', $image['geo_location']); + } + if (!empty($image['title'])) { + $writer->writeElement('image:title', $image['title']); + } + if (!empty($image['license'])) { + $writer->writeElement('image:license', $image['license']); + } + + $writer->endElement(); + } + + /** + * Writes XML namespace attribute + * @param \XMLWriter $writer + */ + public static function writeXmlNamepsace(\XMLWriter $writer): void + { + // TODO: Implement writeXmlNamepsace() method. + } +} \ No newline at end of file diff --git a/src/Extension/Video.php b/src/Extension/Video.php new file mode 100644 index 0000000..eef1516 --- /dev/null +++ b/src/Extension/Video.php @@ -0,0 +1,67 @@ +thumbnailLocation = $thumbnailLocation; + $this->title = $title; + $this->description = $description; + } + + + public function getLimit(): ?int + { + // TODO: Implement getLimit() method. + } + + public function getNamespace(): string + { + return 'video'; + } + + public function getUrl(): string + { + return 'http://www.google.com/schemas/sitemap-video/1.1'; + } + + public function write(\XMLWriter $writer) + { + // TODO: Implement write() method. + } + + public function writeXmlNamepsace(\XMLWriter $writer) + { + // TODO: Implement writeXmlNamepsace() method. + } +} \ No newline at end of file diff --git a/src/Frequency.php b/src/Frequency.php new file mode 100644 index 0000000..eb6cb15 --- /dev/null +++ b/src/Frequency.php @@ -0,0 +1,33 @@ +writer = new XMLWriter(); $this->writer->openMemory(); @@ -53,14 +53,8 @@ private function createNewFile() * @param integer $lastModified unix timestamp of sitemap modification time * @throws \InvalidArgumentException */ - public function addSitemap($location, $lastModified = null) + public function addSitemap($location, $lastModified = null): void { - if (false === filter_var($location, FILTER_VALIDATE_URL)) { - throw new \InvalidArgumentException( - "The location must be a valid URL. You have specified: {$location}." - ); - } - if ($this->writer === null) { $this->createNewFile(); } @@ -77,7 +71,7 @@ public function addSitemap($location, $lastModified = null) /** * @return string index file path */ - public function getFilePath() + public function getFilePath(): string { return $this->filePath; } @@ -85,7 +79,7 @@ public function getFilePath() /** * Finishes writing */ - public function write() + public function write(): void { if ($this->writer instanceof XMLWriter) { $this->writer->endElement(); @@ -103,9 +97,9 @@ public function write() * @param bool $value * @throws \RuntimeException when trying to enable gzip while zlib is not available */ - public function setUseGzip($value) + public function setUseGzip($value): void { - if ($value && !extension_loaded('zlib')) { + if ($value && !\extension_loaded('zlib')) { throw new \RuntimeException('Zlib extension must be installed to gzip the sitemap.'); } $this->useGzip = $value; diff --git a/src/Sitemap.php b/src/Sitemap.php new file mode 100644 index 0000000..cbbc6c0 --- /dev/null +++ b/src/Sitemap.php @@ -0,0 +1,377 @@ + + */ +class Sitemap +{ + /** + * @var integer Maximum allowed number of URLs in a single file. + */ + protected $maxUrls = 50000; + + /** + * @var integer number of URLs added + */ + protected $urlsCount = 0; + + /** + * @var integer Maximum allowed number of bytes in a single file. + */ + private $maxBytes = 10485760; + + /** + * @var integer number of bytes already written to the current file, before compression + */ + private $byteCount = 0; + + /** + * @var string path to the file to be written + */ + private $filePath; + + /** + * @var integer number of files written + */ + protected $fileCount = 0; + + /** + * @var array path of files written + */ + protected $writtenFilePaths = []; + + /** + * @var integer number of URLs to be kept in memory before writing it to file + */ + protected $bufferSize = 10; + + /** + * @var bool if XML should be indented + */ + protected $useIndent = true; + + /** + * @var bool whether to gzip the resulting files or not + */ + protected $useGzip = false; + + /** + * @var WriterInterface that does the actual writing + */ + protected $writerBackend; + + /** + * @var XMLWriter + */ + protected $writer; + + private $extensionClasses; + + /** + * @param string $filePath path of the file to write to + * @param array $extensionClasses + * + * @throws \InvalidArgumentException + */ + public function __construct($filePath, array $extensionClasses = []) + { + $dir = \dirname($filePath); + if (!is_dir($dir)) { + throw new \InvalidArgumentException( + "Please specify valid file path. Directory not exists. You have specified: {$dir}." + ); + } + + $this->filePath = $filePath; + $this->extensionClasses = $extensionClasses; + } + + /** + * Get array of generated files + * @return array + */ + public function getWrittenFilePaths(): array + { + return $this->writtenFilePaths; + } + + /** + * Creates new file + * @throws \RuntimeException if file is not writeable + */ + protected function createNewFile(): void + { + $this->fileCount++; + $filePath = $this->getCurrentFilePath(); + $this->writtenFilePaths[] = $filePath; + + if (file_exists($filePath)) { + $filePath = realpath($filePath); + if (is_writable($filePath)) { + unlink($filePath); + } else { + throw new \RuntimeException("File \"$filePath\" is not writable."); + } + } + + if ($this->useGzip) { + if (\function_exists('deflate_init') && \function_exists('deflate_add')) { + $this->writerBackend = new DeflateWriter($filePath); + } else { + $this->writerBackend = new TempFileGZIPWriter($filePath); + } + } else { + $this->writerBackend = new PlainFileWriter($filePath); + } + + $this->writer = new XMLWriter(); + $this->writer->openMemory(); + $this->addHeader(); + + /* + * XMLWriter does not give us much options, so we must make sure, that + * the header was written correctly and we can simply reuse any + * elements that did not fit into the previous file. (See self::flush) + */ + $this->writer->text(PHP_EOL); + $this->flush(true); + } + + /** + * Writes closing tags to current file + * @throws \RuntimeException + * @throws \OverflowException + */ + protected function finishFile(): void + { + if ($this->writer !== null) { + $this->writer->endElement(); + $this->writer->endDocument(); + + /* To prevent infinite recursion through flush */ + $this->urlsCount = 0; + + $this->flush(0); + $this->writerBackend->finish(); + $this->writerBackend = null; + + $this->byteCount = 0; + } + } + + /** + * Finishes writing + * @throws \RuntimeException + * @throws \OverflowException + */ + public function write(): void + { + $this->finishFile(); + } + + /** + * Flushes buffer into file + * + * @param int $footSize Size of the remaining closing tags + * @throws \RuntimeException + * @throws \OverflowException + */ + protected function flush($footSize = 10): void + { + $data = $this->writer->flush(); + $dataSize = mb_strlen($data, '8bit'); + + /* + * Limit the file size of each single site map + * + * We use a heuristic of 10 Bytes for the remainder of the file, + * i.e. plus a new line. + */ + if ($this->byteCount + $dataSize + $footSize > $this->maxBytes) { + if ($this->urlsCount <= 1) { + throw new \OverflowException('The buffer size is too big for the defined file size limit'); + } + $this->finishFile(); + $this->createNewFile(); + } + + $this->writerBackend->append($data); + $this->byteCount += $dataSize; + } + + /** + * Adds a new URL to sitemap + * + * @param Url $url + * @throws \OverflowException + * @throws \LogicException + * @throws \RuntimeException + */ + public function addUrl(Url $url): void + { + if ($this->urlsCount >= $this->maxUrls) { + $this->finishFile(); + } + + if ($this->writerBackend === null) { + $this->createNewFile(); + } + + $this->writeUrl($url); + + $this->urlsCount++; + + if ($this->urlsCount % $this->bufferSize === 0) { + $this->flush(); + } + } + + /** + * Writes XML for Url passed + * @param Url $url + * @throws \LogicException + */ + protected function writeUrl(Url $url): void + { + $this->writer->startElement('url'); + $this->writer->writeElement('loc', $url->getLocation()); + + if ($url->getLastModified() !== null) { + $this->writer->writeElement('lastmod', $url->getLastModified()->format('c')); + } + + if ($url->getChangeFrequency() !== null) { + $this->writer->writeElement('changefreq', $url->getChangeFrequency()); + } + + $this->writer->writeElement('priority', number_format($url->getPriority(), 1)); + + foreach ($url->getExtensionItems() as $item) { + $extensionClass = \get_class($item); + if (!\in_array($extensionClass, $this->extensionClasses, true)) { + throw new \LogicException("$extensionClass is missing from an array of extension class names passed as second Sitemap constructor argument."); + } + $item->write($this->writer); + } + + $this->writer->endElement(); + } + + /** + * @return string path of currently opened file + */ + protected function getCurrentFilePath(): string + { + if ($this->fileCount < 2) { + return $this->filePath; + } + + $parts = pathinfo($this->filePath); + if ($parts['extension'] === 'gz') { + $filenameParts = pathinfo($parts['filename']); + if (!empty($filenameParts['extension'])) { + $parts['filename'] = $filenameParts['filename']; + $parts['extension'] = $filenameParts['extension'] . '.gz'; + } + } + return $parts['dirname'] . DIRECTORY_SEPARATOR . $parts['filename'] . '_' . $this->fileCount . '.' . $parts['extension']; + } + + /** + * Returns an array of URLs written + * + * @param string $baseUrl base URL of all the sitemaps written + * @return array URLs of sitemaps written + */ + public function getSitemapUrls($baseUrl): array + { + $urls = []; + foreach ($this->writtenFilePaths as $file) { + $urls[] = $baseUrl . pathinfo($file, PATHINFO_BASENAME); + } + return $urls; + } + + /** + * Sets maximum number of URLs to write in a single file. + * Default is 50000. + * @param integer $number + */ + public function setMaxUrls($number): void + { + $this->maxUrls = (int)$number; + } + + /** + * Sets maximum number of bytes to write in a single file. + * Default is 10485760 or 10 MiB. + * @param integer $number + */ + public function setMaxBytes($number): void + { + $this->maxBytes = (int)$number; + } + + /** + * Sets number of URLs to be kept in memory before writing it to file. + * Default is 10. + * + * @param integer $number + */ + public function setBufferSize($number): void + { + $this->bufferSize = (int)$number; + } + + /** + * Sets if XML should be indented. + * Default is true. + * + * @param bool $value + */ + public function setUseIndent($value): void + { + $this->useIndent = (bool)$value; + } + + /** + * Sets whether the resulting files will be gzipped or not. + * @param bool $value + * @throws \RuntimeException when trying to enable gzip while zlib is not available or when trying to change + * setting when some items are already written + */ + public function setUseGzip($value): void + { + if ($value && !\extension_loaded('zlib')) { + throw new \RuntimeException('Zlib extension must be enabled to gzip the sitemap.'); + } + if ($this->writerBackend !== null && $value !== $this->useGzip) { + throw new \RuntimeException('Cannot change the gzip value once items have been added to the sitemap.'); + } + $this->useGzip = $value; + } + + /** + * Adds a document header + */ + protected function addHeader(): void + { + $this->writer->startDocument('1.0', 'UTF-8'); + $this->writer->setIndent($this->useIndent); + $this->writer->startElement('urlset'); + $this->writer->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9'); + + foreach ($this->extensionClasses as $extensionClass) { + $extensionClass::writeXmlNamepsace($this->writer); + } + } +} diff --git a/src/Url.php b/src/Url.php new file mode 100644 index 0000000..7d2e3ae --- /dev/null +++ b/src/Url.php @@ -0,0 +1,167 @@ +location = $location; + } + + /** + * @return string + */ + public function getLocation(): string + { + return $this->location; + } + + /** + * @param string $location + * @return Url + */ + public function setLocation(string $location): Url + { + $this->location = $location; + return $this; + } + + /** + * @return \DateTimeInterface + */ + public function getLastModified(): ?\DateTimeInterface + { + return $this->lastModified; + } + + /** + * @param \DateTimeInterface $lastModified + * @return Url + */ + public function setLastModified(\DateTimeInterface $lastModified): Url + { + $this->lastModified = $lastModified; + return $this; + } + + /** + * @return string + */ + public function getChangeFrequency(): ?string + { + return $this->changeFrequency; + } + + /** + * @param string $changeFrequency + * @return Url + * @throws \InvalidArgumentException + */ + public function setChangeFrequency(string $changeFrequency): Url + { + if (!\in_array($changeFrequency, Frequency::all(), true)) { + throw new \InvalidArgumentException( + 'Please specify valid changeFrequency. Valid values are: ' + . implode(', ', Frequency::all()) + . "You have specified: {$changeFrequency}." + ); + } + + $this->changeFrequency = $changeFrequency; + return $this; + } + + /** + * @return float + */ + public function getPriority(): float + { + return $this->priority; + } + + /** + * @param float $priority + * @return Url + * @throws \InvalidArgumentException + */ + public function setPriority(float $priority): Url + { + if ($priority < 0 || $priority > 1) { + throw new \InvalidArgumentException( + "Please specify valid priority. Valid values range from 0.0 to 1.0. You have specified: {$priority}." + ); + } + + $this->priority = $priority; + return $this; + } + + /** + * @param ExtensionInterface $item + * @return Url + * @throws \LogicException + */ + public function add(ExtensionInterface $item): Url + { + $itemClass = \get_class($item); + + $currentValue = $this->itemCounters[$itemClass] ?? 0; + $limit = $item->getLimit(); + if ($limit !== null && $currentValue === $limit) { + throw new \LogicException("You can not add more than $limit of $itemClass"); + } + + $this->extensionItems[] = $item; + $this->itemCounters[$itemClass] = ++$currentValue; + + return $this; + } + + /** + * @return ExtensionInterface[] + */ + public function getExtensionItems(): array + { + return $this->extensionItems; + } +} \ No newline at end of file diff --git a/DeflateWriter.php b/src/Writer/DeflateWriter.php similarity index 85% rename from DeflateWriter.php rename to src/Writer/DeflateWriter.php index 863b0e1..410677e 100644 --- a/DeflateWriter.php +++ b/src/Writer/DeflateWriter.php @@ -1,6 +1,6 @@ file !== null); + \assert($this->file !== null); $compressedChunk = deflate_add($this->deflateContext, $data, $flushMode); fwrite($this->file, $compressedChunk); @@ -45,7 +45,7 @@ private function write($data, $flushMode) * * @param string $data */ - public function append($data) + public function append($data): void { $this->write($data, ZLIB_NO_FLUSH); } @@ -53,7 +53,7 @@ public function append($data) /** * Make sure all data was written */ - public function finish() + public function finish(): void { $this->write('', ZLIB_FINISH); diff --git a/PlainFileWriter.php b/src/Writer/PlainFileWriter.php similarity index 74% rename from PlainFileWriter.php rename to src/Writer/PlainFileWriter.php index 3ea6d3a..fb4f900 100644 --- a/PlainFileWriter.php +++ b/src/Writer/PlainFileWriter.php @@ -1,6 +1,6 @@ file !== null); + \assert($this->file !== null); fwrite($this->file, $data); } @@ -33,9 +33,9 @@ public function append($data) /** * @inheritdoc */ - public function finish() + public function finish(): void { - assert($this->file !== null); + \assert($this->file !== null); fclose($this->file); $this->file = null; diff --git a/TempFileGZIPWriter.php b/src/Writer/TempFileGZIPWriter.php similarity index 79% rename from TempFileGZIPWriter.php rename to src/Writer/TempFileGZIPWriter.php index 1859f9c..5c68b16 100644 --- a/TempFileGZIPWriter.php +++ b/src/Writer/TempFileGZIPWriter.php @@ -1,6 +1,6 @@ tempFile !== null); + \assert($this->tempFile !== null); fwrite($this->tempFile, $data); } @@ -41,9 +41,9 @@ public function append($data) /** * Deflate buffered data */ - public function finish() + public function finish(): void { - assert($this->tempFile !== null); + \assert($this->tempFile !== null); $file = fopen('compress.zlib://' . $this->filename, 'wb'); rewind($this->tempFile); diff --git a/WriterInterface.php b/src/Writer/WriterInterface.php similarity index 79% rename from WriterInterface.php rename to src/Writer/WriterInterface.php index 887a98d..2bfe1f6 100644 --- a/WriterInterface.php +++ b/src/Writer/WriterInterface.php @@ -1,5 +1,6 @@ load($fileName); - $this->assertTrue($xml->schemaValidate(__DIR__ . '/siteindex.xsd')); - } +use SamDark\Sitemap\Index; +/** + * IndexTest tests Sitemap index generator + */ +class IndexTest extends TestCase +{ public function testWritingFile() { - $fileName = __DIR__ . '/sitemap_index.xml'; + $fileName = $this->getTempPath('sitemap_index.xml'); $index = new Index($fileName); $index->addSitemap('http://example.com/sitemap.xml'); $index->addSitemap('http://example.com/sitemap_2.xml', time()); $index->write(); - $this->assertTrue(file_exists($fileName)); - $this->assertIsValidIndex($fileName); - unlink($fileName); - } - - public function testLocationValidation() - { - $this->setExpectedException('InvalidArgumentException'); - - $fileName = __DIR__ . '/sitemap.xml'; - $index = new Index($fileName); - $index->addSitemap('noturl'); - - unlink($fileName); + $this->assertFileExists($fileName); + $this->assertValidXml($fileName, 'index'); } public function testWritingFileGzipped() { - $fileName = __DIR__ . '/sitemap_index.xml.gz'; + $fileName = $this->getTempPath('sitemap_index.xml.gz'); $index = new Index($fileName); $index->setUseGzip(true); $index->addSitemap('http://example.com/sitemap.xml'); $index->addSitemap('http://example.com/sitemap_2.xml', time()); $index->write(); - $this->assertTrue(file_exists($fileName)); + $this->assertFileExists($fileName); $finfo = new \finfo(FILEINFO_MIME_TYPE); $this->assertEquals('application/x-gzip', $finfo->file($fileName)); - $this->assertIsValidIndex('compress.zlib://' . $fileName); - unlink($fileName); + $this->assertValidXml('compress.zlib://' . $fileName, 'index'); } } diff --git a/tests/SitemapTest.php b/tests/SitemapTest.php index c1c4a14..2d99fbb 100644 --- a/tests/SitemapTest.php +++ b/tests/SitemapTest.php @@ -1,27 +1,22 @@ load($fileName); - $this->assertTrue($xml->schemaValidate(__DIR__ . '/' . $xsdFileName)); - } - - protected function assertIsOneMemberGzipFile($fileName) + protected function assertIsOneMemberGzipFile(string $fileName) { $gzipMemberStartSequence = pack('H*', '1f8b08'); $content = file_get_contents($fileName); @@ -31,293 +26,237 @@ protected function assertIsOneMemberGzipFile($fileName) public function testWritingFile() { - $fileName = __DIR__ . '/sitemap_regular.xml'; + $fileName = $this->getTempPath('testWritingFile.xml'); + $sitemap = new Sitemap($fileName); - $sitemap->addItem('http://example.com/mylink1'); - $sitemap->addItem('http://example.com/mylink2', time()); - $sitemap->addItem('http://example.com/mylink3', time(), Sitemap::HOURLY); - $sitemap->addItem('http://example.com/mylink4', time(), Sitemap::DAILY, 0.3); + $sitemap->addUrl(new Url('http://example.com/mylink1')); + $sitemap->addUrl( + (new Url('http://example.com/mylink2')) + ->setLastModified(new \DateTime()) + ); + $sitemap->addUrl( + (new Url('http://example.com/mylink3')) + ->setLastModified(new \DateTime()) + ->setChangeFrequency(Frequency::HOURLY) + ); + $sitemap->addUrl( + (new Url('http://example.com/mylink4')) + ->setChangeFrequency(Frequency::DAILY) + ->setLastModified(new \DateTime()) + ->setPriority(0.3) + ); $sitemap->write(); - $this->assertTrue(file_exists($fileName)); - $this->assertIsValidSitemap($fileName); - - unlink($fileName); + $this->assertFileExists($fileName); + $this->assertValidXml($fileName, 'sitemap'); } public function testMultipleFiles() { - $sitemap = new Sitemap(__DIR__ . '/sitemap_multi.xml'); + $sitemap = new Sitemap($this->getTempPath('/testMultipleFiles.xml')); $sitemap->setMaxUrls(2); for ($i = 0; $i < 20; $i++) { - $sitemap->addItem('http://example.com/mylink' . $i, time()); + $sitemap->addUrl( + (new Url('http://example.com/mylink' . $i)) + ->setLastModified(new \DateTime()) + ); } $sitemap->write(); - $expectedFiles = array( - __DIR__ . '/' .'sitemap_multi.xml', - __DIR__ . '/' .'sitemap_multi_2.xml', - __DIR__ . '/' .'sitemap_multi_3.xml', - __DIR__ . '/' .'sitemap_multi_4.xml', - __DIR__ . '/' .'sitemap_multi_5.xml', - __DIR__ . '/' .'sitemap_multi_6.xml', - __DIR__ . '/' .'sitemap_multi_7.xml', - __DIR__ . '/' .'sitemap_multi_8.xml', - __DIR__ . '/' .'sitemap_multi_9.xml', - __DIR__ . '/' .'sitemap_multi_10.xml', - ); + $expectedFiles = [ + $this->getTempPath('testMultipleFiles.xml'), + $this->getTempPath('testMultipleFiles_2.xml'), + $this->getTempPath('testMultipleFiles_3.xml'), + $this->getTempPath('testMultipleFiles_4.xml'), + $this->getTempPath('testMultipleFiles_5.xml'), + $this->getTempPath('testMultipleFiles_6.xml'), + $this->getTempPath('testMultipleFiles_7.xml'), + $this->getTempPath('testMultipleFiles_8.xml'), + $this->getTempPath('testMultipleFiles_9.xml'), + $this->getTempPath('testMultipleFiles_10.xml'), + ]; foreach ($expectedFiles as $expectedFile) { - $this->assertTrue(file_exists($expectedFile), "$expectedFile does not exist!"); - $this->assertIsValidSitemap($expectedFile); - unlink($expectedFile); + $this->assertFileExists($expectedFile, "$expectedFile does not exist!"); + $this->assertValidXml($expectedFile, 'sitemap'); } $urls = $sitemap->getSitemapUrls('http://example.com/'); - $this->assertEquals(10, count($urls), print_r($urls, true)); - $this->assertContains('http://example.com/sitemap_multi.xml', $urls); - $this->assertContains('http://example.com/sitemap_multi_10.xml', $urls); + $this->assertCount(10, $urls, print_r($urls, true)); + $this->assertContains('http://example.com/testMultipleFiles.xml', $urls); + $this->assertContains('http://example.com/testMultipleFiles_10.xml', $urls); } public function testMultiLanguageSitemap() { - $fileName = __DIR__ . '/sitemap_multi_language.xml'; - $sitemap = new Sitemap($fileName, true); - $sitemap->addItem('http://example.com/mylink1'); - - $sitemap->addItem(array( - 'ru' => 'http://example.com/ru/mylink2', - 'en' => 'http://example.com/en/mylink2', - ), time()); - - $sitemap->addItem(array( - 'ru' => 'http://example.com/ru/mylink3', - 'en' => 'http://example.com/en/mylink3', - ), time(), Sitemap::HOURLY); - - $sitemap->addItem(array( - 'ru' => 'http://example.com/ru/mylink4', - 'en' => 'http://example.com/en/mylink4', - ), time(), Sitemap::DAILY, 0.3); + $fileName = $this->getTempPath('testMultiLanguageSitemap.xml'); + $sitemap = new Sitemap($fileName, [AlternateLink::class]); + $sitemap->addUrl( + (new Url('http://example.com/en/mylink2')) + ->setLastModified(new \DateTime()) + ->setChangeFrequency(Frequency::HOURLY) + ->add(new AlternateLink('en', 'http://example.com/en/mylink2')) + ->add(new AlternateLink('ru', 'http://example.com/ru/mylink2')) + ); $sitemap->write(); - $this->assertTrue(file_exists($fileName)); - $this->assertIsValidSitemap($fileName, true); - - unlink($fileName); + $this->assertFileExists($fileName); + $this->assertValidXml($fileName, 'sitemap_xhtml'); } public function testFrequencyValidation() { - $this->setExpectedException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); - $fileName = __DIR__ . '/sitemap.xml'; + $fileName = $this->getTempPath('testFrequencyValidation.xml'); $sitemap = new Sitemap($fileName); - $sitemap->addItem('http://example.com/mylink1'); - $sitemap->addItem('http://example.com/mylink2', time(), 'invalid'); - - unlink($fileName); + $sitemap->addUrl( + (new Url('http://example.com/mylink2')) + ->setChangeFrequency('invalid') + ); } public function testPriorityValidation() { - $fileName = __DIR__ . '/sitemap.xml'; - $sitemap = new Sitemap($fileName); - - $exceptionCaught = false; - try { - $sitemap->addItem('http://example.com/mylink1'); - $sitemap->addItem('http://example.com/mylink2', time(), 'always', 2.0); - } catch (\InvalidArgumentException $e) { - $exceptionCaught = true; - } - - unlink($fileName); - - $this->assertTrue($exceptionCaught, 'Expected InvalidArgumentException wasn\'t thrown.'); - } - - public function testLocationValidation() - { - $fileName = __DIR__ . '/sitemap.xml'; + $fileName = $this->getTempPath('testPriorityValidation.xml'); $sitemap = new Sitemap($fileName); - $exceptionCaught = false; - try { - $sitemap->addItem('http://example.com/mylink1'); - $sitemap->addItem('notlink', time()); - } catch (\InvalidArgumentException $e) { - $exceptionCaught = true; - } - - unlink($fileName); - - $this->assertTrue($exceptionCaught, 'Expected InvalidArgumentException wasn\'t thrown.'); - } - - public function testMultiLanguageLocationValidation() - { - $fileName = __DIR__ . '/sitemap.xml'; - $sitemap = new Sitemap($fileName); - - - $sitemap->addItem(array( - 'ru' => 'http://example.com/mylink1', - 'en' => 'http://example.com/mylink2', - )); - - $exceptionCaught = false; - try { - $sitemap->addItem(array( - 'ru' => 'http://example.com/mylink3', - 'en' => 'notlink', - ), time()); - } catch (\InvalidArgumentException $e) { - $exceptionCaught = true; - } - - unlink($fileName); + $this->expectException(InvalidArgumentException::class); - $this->assertTrue($exceptionCaught, 'Expected InvalidArgumentException wasn\'t thrown.'); + $sitemap->addUrl( + (new Url('http://example.com/mylink1')) + ->setPriority(2.0) + ); } public function testWritingFileGzipped() { - $fileName = __DIR__ . '/sitemap_gzipped.xml.gz'; + $fileName = $this->getTempPath('testWritingFileGzipped.xml.gz'); $sitemap = new Sitemap($fileName); $sitemap->setUseGzip(true); - $sitemap->addItem('http://example.com/mylink1'); - $sitemap->addItem('http://example.com/mylink2', time()); - $sitemap->addItem('http://example.com/mylink3', time(), Sitemap::HOURLY); - $sitemap->addItem('http://example.com/mylink4', time(), Sitemap::DAILY, 0.3); + $sitemap->addUrl(new Url('http://example.com/mylink1')); $sitemap->write(); - $this->assertTrue(file_exists($fileName)); + $this->assertFileExists($fileName); $finfo = new \finfo(FILEINFO_MIME_TYPE); $this->assertEquals('application/x-gzip', $finfo->file($fileName)); - $this->assertIsValidSitemap('compress.zlib://' . $fileName); + $this->assertValidXml('compress.zlib://' . $fileName, 'sitemap'); $this->assertIsOneMemberGzipFile($fileName); - - unlink($fileName); } public function testMultipleFilesGzipped() { - $sitemap = new Sitemap(__DIR__ . '/sitemap_multi_gzipped.xml.gz'); + $sitemap = new Sitemap($this->getTempPath('testMultipleFilesGzipped.xml.gz')); $sitemap->setUseGzip(true); $sitemap->setMaxUrls(2); for ($i = 0; $i < 20; $i++) { - $sitemap->addItem('http://example.com/mylink' . $i, time()); + $sitemap->addUrl( + (new Url('http://example.com/mylink' . $i)) + ->setLastModified(new \DateTime()) + ); } $sitemap->write(); - $expectedFiles = array( - __DIR__ . '/' .'sitemap_multi_gzipped.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_2.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_3.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_4.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_5.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_6.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_7.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_8.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_9.xml.gz', - __DIR__ . '/' .'sitemap_multi_gzipped_10.xml.gz', - ); + $expectedFiles = [ + $this->getTempPath('testMultipleFilesGzipped.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_2.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_3.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_4.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_5.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_6.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_7.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_8.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_9.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped_10.xml.gz'), + ]; $finfo = new \finfo(FILEINFO_MIME_TYPE); foreach ($expectedFiles as $expectedFile) { - $this->assertTrue(file_exists($expectedFile), "$expectedFile does not exist!"); + $this->assertFileExists($expectedFile, "$expectedFile does not exist!"); $this->assertEquals('application/x-gzip', $finfo->file($expectedFile)); - $this->assertIsValidSitemap('compress.zlib://' . $expectedFile); + $this->assertValidXml('compress.zlib://' . $expectedFile, 'sitemap'); $this->assertIsOneMemberGzipFile($expectedFile); - unlink($expectedFile); } $urls = $sitemap->getSitemapUrls('http://example.com/'); - $this->assertEquals(10, count($urls), print_r($urls, true)); - $this->assertContains('http://example.com/sitemap_multi_gzipped.xml.gz', $urls); - $this->assertContains('http://example.com/sitemap_multi_gzipped_10.xml.gz', $urls); + $this->assertCount(10, $urls, print_r($urls, true)); + $this->assertContains('http://example.com/testMultipleFilesGzipped.xml.gz', $urls); + $this->assertContains('http://example.com/testMultipleFilesGzipped_10.xml.gz', $urls); } public function testFileSizeLimit() { - $sitemap = new Sitemap(__DIR__ . '/sitemap_multi.xml'); + $sitemap = new Sitemap($this->getTempPath('testFileSizeLimit.xml')); $sizeLimit = 1036; $sitemap->setMaxBytes($sizeLimit); $sitemap->setBufferSize(1); for ($i = 0; $i < 20; $i++) { - $sitemap->addItem('http://example.com/mylink' . $i, time()); + $sitemap->addUrl( + (new Url('http://example.com/mylink' . $i)) + ->setLastModified(new \DateTime()) + ); } $sitemap->write(); - $expectedFiles = array( - __DIR__ . '/' .'sitemap_multi.xml', - __DIR__ . '/' .'sitemap_multi_2.xml', - __DIR__ . '/' .'sitemap_multi_3.xml', - ); - - $this->assertEquals($sizeLimit, filesize($expectedFiles[1])); + $expectedFiles = [ + $this->getTempPath('testFileSizeLimit.xml'), + $this->getTempPath('testFileSizeLimit_2.xml'), + $this->getTempPath('testFileSizeLimit_3.xml'), + ]; foreach ($expectedFiles as $expectedFile) { - $this->assertTrue(file_exists($expectedFile), "$expectedFile does not exist!"); - $this->assertIsValidSitemap($expectedFile); + $this->assertFileExists($expectedFile); + $this->assertValidXml($expectedFile, 'sitemap'); $this->assertLessThanOrEqual($sizeLimit, filesize($expectedFile), "$expectedFile exceeds the size limit"); - unlink($expectedFile); } $urls = $sitemap->getSitemapUrls('http://example.com/'); - $this->assertEquals(3, count($urls), print_r($urls, true)); - $this->assertContains('http://example.com/sitemap_multi.xml', $urls); - $this->assertContains('http://example.com/sitemap_multi_3.xml', $urls); + $this->assertCount(3, $urls, print_r($urls, true)); + $this->assertContains('http://example.com/testFileSizeLimit.xml', $urls); + $this->assertContains('http://example.com/testFileSizeLimit_3.xml', $urls); } public function testSmallSizeLimit() { - $fileName = __DIR__ . '/sitemap_regular.xml'; + $this->expectException(OverflowException::class); + + $fileName = $this->getTempPath('testSmallSizeLimit.xml'); $sitemap = new Sitemap($fileName); $sitemap->setMaxBytes(0); $sitemap->setBufferSize(1); - - $exceptionCaught = false; - try { - $sitemap->addItem('http://example.com/mylink1'); - $sitemap->write(); - } catch (\OverflowException $e) { - $exceptionCaught = true; - } - - unlink($fileName); - - $this->assertTrue($exceptionCaught, 'Expected OverflowException wasn\'t thrown.'); + $sitemap->addUrl(new Url('http://example.com/mylink1')); + $sitemap->write(); } public function testBufferSizeImpact() { - if (getenv('TRAVIS') == 'true') { + if (getenv('TRAVIS') === 'true') { $this->markTestSkipped('Can not reliably test performance on travis-ci.'); return; } - $fileName = __DIR__ . '/sitemap_big.xml'; + $fileName = $this->getTempPath('testBufferSizeImpact.xml'); - $times = array(); + $times = []; - foreach (array(1000, 10) as $bufferSize) { + foreach ([1000, 10] as $bufferSize) { $startTime = microtime(true); $sitemap = new Sitemap($fileName); $sitemap->setBufferSize($bufferSize); for ($i = 0; $i < 50000; $i++) { - $sitemap->addItem('http://example.com/mylink' . $i, time()); + $sitemap->addUrl( + (new Url('http://example.com/mylink' . $i)) + ->setLastModified(new \DateTime()) + ); } $sitemap->write(); $times[] = microtime(true) - $startTime; - unlink($fileName); } $this->assertLessThan($times[0] * 1.2, $times[1]); diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..93874fa --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,42 @@ +tempPaths[] = $path; + return $path; + } + + protected function tearDown() + { + foreach ($this->tempPaths as $tempPath) { + @unlink($tempPath); + } + + $this->tempPaths = []; + } + + /** + * Asserts if file is valid XML accoring to XSD specified + * @param string $fileName + * @param string $xsdName + */ + protected function assertValidXml(string $fileName, string $xsdName) + { + $xml = new \DOMDocument(); + $xml->load($fileName); + $this->assertTrue($xml->schemaValidate(__DIR__ . '/xsd/' . $xsdName . '.xsd'), "$fileName is not valid accoring to $xsdName XML schema definition"); + } +} diff --git a/tests/runtime/.gitignore b/tests/runtime/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/tests/runtime/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/tests/siteindex.xsd b/tests/xsd/index.xsd similarity index 100% rename from tests/siteindex.xsd rename to tests/xsd/index.xsd diff --git a/tests/sitemap.xsd b/tests/xsd/sitemap.xsd similarity index 100% rename from tests/sitemap.xsd rename to tests/xsd/sitemap.xsd diff --git a/tests/sitemap_xhtml.xsd b/tests/xsd/sitemap_xhtml.xsd similarity index 100% rename from tests/sitemap_xhtml.xsd rename to tests/xsd/sitemap_xhtml.xsd diff --git a/tests/xhtml1-strict.xsd b/tests/xsd/xhtml1-strict.xsd similarity index 100% rename from tests/xhtml1-strict.xsd rename to tests/xsd/xhtml1-strict.xsd From 0dbc874afe1bb1a1807b2d5a8d132c5747419444 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Mon, 28 May 2018 00:51:25 +0300 Subject: [PATCH 2/7] Work in progress on Google extensions --- src/Extension/Image.php | 4 +- src/Extension/Video.php | 67 --- .../Video/AllowCountryRestriction.php | 14 + .../Video/AllowPlatformRestriction.php | 13 + src/Extension/Video/CountryRestriction.php | 25 ++ .../Video/DenyCountryRestriction.php | 12 + src/Extension/Video/GalleryLocation.php | 14 + src/Extension/Video/PlatformRestriction.php | 13 + src/Extension/Video/Price.php | 96 ++++ src/Extension/Video/Uploader.php | 57 +++ src/Extension/Video/Video.php | 414 ++++++++++++++++++ 11 files changed, 660 insertions(+), 69 deletions(-) delete mode 100644 src/Extension/Video.php create mode 100644 src/Extension/Video/AllowCountryRestriction.php create mode 100644 src/Extension/Video/AllowPlatformRestriction.php create mode 100644 src/Extension/Video/CountryRestriction.php create mode 100644 src/Extension/Video/DenyCountryRestriction.php create mode 100644 src/Extension/Video/GalleryLocation.php create mode 100644 src/Extension/Video/PlatformRestriction.php create mode 100644 src/Extension/Video/Price.php create mode 100644 src/Extension/Video/Uploader.php create mode 100644 src/Extension/Video/Video.php diff --git a/src/Extension/Image.php b/src/Extension/Image.php index 439e660..5cb6d11 100644 --- a/src/Extension/Image.php +++ b/src/Extension/Image.php @@ -5,7 +5,7 @@ /** - * Image + * Image extension * @see https://support.google.com/webmasters/answer/178636 */ class Image implements ExtensionInterface @@ -160,6 +160,6 @@ public function write(\XMLWriter $writer): void */ public static function writeXmlNamepsace(\XMLWriter $writer): void { - // TODO: Implement writeXmlNamepsace() method. + $writer->writeAttribute('xmlns:image', 'http://www.google.com/schemas/sitemap-image/1.1'); } } \ No newline at end of file diff --git a/src/Extension/Video.php b/src/Extension/Video.php deleted file mode 100644 index eef1516..0000000 --- a/src/Extension/Video.php +++ /dev/null @@ -1,67 +0,0 @@ -thumbnailLocation = $thumbnailLocation; - $this->title = $title; - $this->description = $description; - } - - - public function getLimit(): ?int - { - // TODO: Implement getLimit() method. - } - - public function getNamespace(): string - { - return 'video'; - } - - public function getUrl(): string - { - return 'http://www.google.com/schemas/sitemap-video/1.1'; - } - - public function write(\XMLWriter $writer) - { - // TODO: Implement write() method. - } - - public function writeXmlNamepsace(\XMLWriter $writer) - { - // TODO: Implement writeXmlNamepsace() method. - } -} \ No newline at end of file diff --git a/src/Extension/Video/AllowCountryRestriction.php b/src/Extension/Video/AllowCountryRestriction.php new file mode 100644 index 0000000..16766ea --- /dev/null +++ b/src/Extension/Video/AllowCountryRestriction.php @@ -0,0 +1,14 @@ +validateCountry($country); + } + + $this->countries = $countries; + } + + private function validateCountry() + { + // TODO: ISO 3166 + } + + abstract public function areAllowed(): bool; +} \ No newline at end of file diff --git a/src/Extension/Video/DenyCountryRestriction.php b/src/Extension/Video/DenyCountryRestriction.php new file mode 100644 index 0000000..b9bd593 --- /dev/null +++ b/src/Extension/Video/DenyCountryRestriction.php @@ -0,0 +1,12 @@ + tag can be listed for each video. The optional attribute title indicates the title of the gallery. + * + */ +class GalleryLocation +{ + private $link; + private $title; +} \ No newline at end of file diff --git a/src/Extension/Video/PlatformRestriction.php b/src/Extension/Video/PlatformRestriction.php new file mode 100644 index 0000000..17ef3e0 --- /dev/null +++ b/src/Extension/Video/PlatformRestriction.php @@ -0,0 +1,13 @@ +currency = $currency; + $this->value = $value; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @param string $type + */ + public function setType(string $type): void + { + $this->type = $type; + } + + /** + * @return string + */ + public function getResolution(): string + { + return $this->resolution; + } + + /** + * @param string $resolution + */ + public function setResolution(string $resolution): void + { + $this->resolution = $resolution; + } + + /** + * @return string + */ + public function getCurrency(): string + { + return $this->currency; + } + + /** + * @return float + */ + public function getValue(): float + { + return $this->value; + } + + + + +} \ No newline at end of file diff --git a/src/Extension/Video/Uploader.php b/src/Extension/Video/Uploader.php new file mode 100644 index 0000000..a2f71a2 --- /dev/null +++ b/src/Extension/Video/Uploader.php @@ -0,0 +1,57 @@ +name = $name; + } + + /** + * @return string + */ + public function getInfoUrl(): string + { + return $this->infoUrl; + } + + /** + * @param string $infoUrl + * @return self + */ + public function setInfoUrl(string $infoUrl): self + { + $this->infoUrl = $infoUrl; + return $this; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + + + +} \ No newline at end of file diff --git a/src/Extension/Video/Video.php b/src/Extension/Video/Video.php new file mode 100644 index 0000000..0260406 --- /dev/null +++ b/src/Extension/Video/Video.php @@ -0,0 +1,414 @@ +thumbnailLocation = $thumbnailLocation; + $this->title = $title; + $this->description = $description; + } + + /** + * @inheritdoc + */ + public static function getLimit(): ?int + { + return 1; + } + + /** + * @inheritdoc + */ + public function write(\XMLWriter $writer): void + { + // TODO: Implement write() method. + } + + /** + * @inheritdoc + */ + public static function writeXmlNamepsace(\XMLWriter $writer): void + { + $writer->writeAttribute('xmlns:video', 'http://www.google.com/schemas/sitemap-video/1.1'); + } + + /** + * @return string + */ + public function getContentLocations() + { + return $this->contentLocations; + } + + /** + * @param string $contentLocation + * @return self + */ + public function addContentLocation($contentLocation) + { + $this->contentLocations[] = $contentLocation; + + return $this; + } + + /** + * @return array + */ + public function getPlayerLocations() + { + return $this->playerLocations; + } + + /** + * @param string $playerLocation + * @return self + */ + public function addPlayerLocation($playerLocation): self + { + $this->playerLocations[] = $playerLocation; + return $this; + } + + /** + * @return int Duration of the video in seconds + */ + public function getDuration(): int + { + return $this->duration; + } + + /** + * @param int $duration Duration of the video in seconds + * @return self + */ + public function setDuration(int $duration): self + { + $this->duration = $duration; + return $this; + } + + /** + * @return mixed + */ + public function getExpirationDate() + { + return $this->expirationDate; + } + + /** + * @param mixed $expirationDate + * @return self + */ + public function setExpirationDate($expirationDate): self + { + $this->expirationDate = $expirationDate; + return $this; + } + + /** + * @return mixed + */ + public function getRating() + { + return $this->rating; + } + + /** + * @param mixed $rating + * @return self + */ + public function setRating($rating): self + { + $this->rating = $rating; + return $this; + } + + /** + * @return mixed + */ + public function getViewCount() + { + return $this->viewCount; + } + + /** + * @param mixed $viewCount + * @return self + */ + public function setViewCount($viewCount): self + { + $this->viewCount = $viewCount; + return $this; + } + + /** + * @return mixed + */ + public function getPublictionDate() + { + return $this->publictionDate; + } + + /** + * @param mixed $publictionDate + * @return self + */ + public function setPublictionDate($publictionDate): self + { + $this->publictionDate = $publictionDate; + return $this; + } + + /** + * @return mixed + */ + public function getFamilyFriendly() + { + return $this->familyFriendly; + } + + /** + * @param mixed $familyFriendly + * @return self + */ + public function setFamilyFriendly($familyFriendly): self + { + $this->familyFriendly = $familyFriendly; + return $this; + } + + /** + * @return CountryRestriction + */ + public function getRestriction(): CountryRestriction + { + return $this->restriction; + } + + /** + * @param CountryRestriction $restriction + * @return self + */ + public function setRestriction(CountryRestriction $restriction): self + { + $this->restriction = $restriction; + return $this; + } + + /** + * @return GalleryLocation + */ + public function getGalleryLocation(): GalleryLocation + { + return $this->galleryLocation; + } + + /** + * @param GalleryLocation $galleryLocation + * @return self + */ + public function setGalleryLocation(GalleryLocation $galleryLocation): self + { + $this->galleryLocation = $galleryLocation; + return $this; + } + + /** + * @return Price[] + */ + public function getPrices() + { + return $this->prices; + } + + /** + * @param Price $price + * @return self + */ + public function addPrice(Price $price): self + { + $this->prices[] = $price; + + return $this; + } + + /** + * @return bool + */ + public function requiresSubscribtion(): bool + { + return $this->requiresSubscribtion; + } + + /** + * @param bool $requiresSubscribtion + * @return self + */ + public function setRequiresSubscribtion(bool $requiresSubscribtion): self + { + $this->requiresSubscribtion = $requiresSubscribtion; + + return $this; + } + + /** + * @return Uploader + */ + public function getUploader(): Uploader + { + return $this->uploader; + } + + /** + * @param Uploader $uploader + * @return self + */ + public function setUploader(Uploader $uploader): self + { + $this->uploader = $uploader; + return $this; + } + + /** + * @return bool + */ + public function isLive(): bool + { + return $this->live; + } + + /** + * @param bool $live + * @return self + */ + public function setLive(bool $live): self + { + $this->live = $live; + + return $this; + } + + +} \ No newline at end of file From 43817d73c0fc24e3c472a6973e8ca4270571338d Mon Sep 17 00:00:00 2001 From: Alexey Chernousov Date: Tue, 19 Jun 2018 13:19:59 +0300 Subject: [PATCH 3/7] Fixes: Image extension write (#61) --- src/Extension/Image.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Extension/Image.php b/src/Extension/Image.php index 5cb6d11..5133b99 100644 --- a/src/Extension/Image.php +++ b/src/Extension/Image.php @@ -135,20 +135,20 @@ public function write(\XMLWriter $writer): void { $writer->startElement('image:image'); - if (!empty($image['loc'])) { - $writer->writeElement('image:loc', $image['loc']); + if (!empty($this->location)) { + $writer->writeElement('image:loc', $this->location); } - if (!empty($image['caption'])) { - $writer->writeElement('image:caption', $image['caption']); + if (!empty($this->caption)) { + $writer->writeElement('image:caption', $this->caption); } - if (!empty($image['geo_location'])) { - $writer->writeElement('image:geo_location', $image['geo_location']); + if (!empty($this->geoLocation)) { + $writer->writeElement('image:geo_location', $this->geoLocation); } - if (!empty($image['title'])) { - $writer->writeElement('image:title', $image['title']); + if (!empty($this->title)) { + $writer->writeElement('image:title', $this->title); } - if (!empty($image['license'])) { - $writer->writeElement('image:license', $image['license']); + if (!empty($this->license)) { + $writer->writeElement('image:license', $this->license); } $writer->endElement(); From f0d5b8aa5b5f81292e96f8caac3ae85947369922 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 10 Jul 2018 11:22:34 +0300 Subject: [PATCH 4/7] Removed unused PHP version from .travis.yml --- .travis.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 43ed454..86c0ccc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,7 @@ language: php php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 - 7.1 - nightly -matrix: - include: - - php: hhvm - dist: trusty - - php: 5.3 - dist: precise + before_script: - composer install From 4ae092f63050c52bb99b53ff0bdb5738c2b43c5c Mon Sep 17 00:00:00 2001 From: Alexey Chernousov Date: Tue, 23 Jun 2020 13:05:14 +0300 Subject: [PATCH 5/7] Replace separator to make Google happy (#68) Google can't properly read sitemap files with `_` in their name --- src/Sitemap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sitemap.php b/src/Sitemap.php index cbbc6c0..a02d102 100644 --- a/src/Sitemap.php +++ b/src/Sitemap.php @@ -283,7 +283,7 @@ protected function getCurrentFilePath(): string $parts['extension'] = $filenameParts['extension'] . '.gz'; } } - return $parts['dirname'] . DIRECTORY_SEPARATOR . $parts['filename'] . '_' . $this->fileCount . '.' . $parts['extension']; + return $parts['dirname'] . DIRECTORY_SEPARATOR . $parts['filename'] . '-' . $this->fileCount . '.' . $parts['extension']; } /** From c59aa8753735f10794c5ec363b7b162558d139ed Mon Sep 17 00:00:00 2001 From: David Goodwin Date: Fri, 2 Jul 2021 17:09:31 +0100 Subject: [PATCH 6/7] Add Psalm static analysis, fix issues (#76) --- composer.json | 11 +- composer.lock | 1475 -------------------- src/Extension/Video/CountryRestriction.php | 4 +- src/Sitemap.php | 4 +- src/Url.php | 4 +- src/Writer/PlainFileWriter.php | 3 +- src/Writer/TempFileGZIPWriter.php | 5 +- 7 files changed, 21 insertions(+), 1485 deletions(-) delete mode 100644 composer.lock diff --git a/composer.json b/composer.json index 7c4d2bb..9264b5b 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "ext-xmlwriter": "*" }, "require-dev": { - "phpunit/phpunit": "~7.1.5" + "phpunit/phpunit": "~7.1.5", + "vimeo/psalm": "*" }, "autoload": { "psr-4": { @@ -33,5 +34,13 @@ "psr-4": { "SamDark\\Sitemap\\tests\\": "tests" } + }, + "scripts": { + "test" : "@php vendor/bin/phpunit tests", + "psalm" : "@php vendor/bin/psalm", + "build" : [ + "@psalm", + "@test" + ] } } diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 6c624e5..0000000 --- a/composer.lock +++ /dev/null @@ -1,1475 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "7df6b111745c1e2ac134452e19aed1c9", - "packages": [], - "packages-dev": [ - { - "name": "doctrine/instantiator", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2017-07-22T11:58:36+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.7.0", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, - "files": [ - "src/DeepCopy/deep_copy.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "time": "2017-10-19T19:58:43+00:00" - }, - { - "name": "phar-io/manifest", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "phar-io/version": "^1.0.1", - "php": "^5.6 || ^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" - }, - { - "name": "phar-io/version", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2017-09-11T18:02:19+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", - "shasum": "" - }, - "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "doctrine/instantiator": "~1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "0.4.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", - "shasum": "" - }, - "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "time": "2017-07-14T14:27:02+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "1.7.6", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2018-04-18T13:57:24+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "6.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "52187754b0eed0b8159f62a6fa30073327e8c2ca" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/52187754b0eed0b8159f62a6fa30073327e8c2ca", - "reference": "52187754b0eed0b8159f62a6fa30073327e8c2ca", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^7.1", - "phpunit/php-file-iterator": "^1.4.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "suggest": { - "ext-xdebug": "^2.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2018-04-29T14:59:09+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2017-11-27T13:52:08+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", - "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2018-02-01T13:07:23+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", - "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2018-02-01T13:16:43+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "7.1.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ca64dba53b88aba6af32aebc6b388068db95c435" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ca64dba53b88aba6af32aebc6b388068db95c435", - "reference": "ca64dba53b88aba6af32aebc6b388068db95c435", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.1", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0.1", - "phpunit/php-file-iterator": "^1.4.3", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.0", - "phpunit/phpunit-mock-objects": "^6.1.1", - "sebastian/comparator": "^3.0", - "sebastian/diff": "^3.0", - "sebastian/environment": "^3.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", - "sebastian/version": "^2.0.1" - }, - "require-dev": { - "ext-pdo": "*" - }, - "suggest": { - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "7.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2018-04-29T15:09:19+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "6.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/70c740bde8fd9ea9ea295be1cd875dd7b267e157", - "reference": "70c740bde8fd9ea9ea295be1cd875dd7b267e157", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.1", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2018-04-11T04:50:36+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" - }, - { - "name": "sebastian/comparator", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/ed5fd2281113729f1ebcc64d101ad66028aeb3d5", - "reference": "ed5fd2281113729f1ebcc64d101ad66028aeb3d5", - "shasum": "" - }, - "require": { - "php": "^7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2018-04-18T13:33:00+00:00" - }, - { - "name": "sebastian/diff", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8", - "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0", - "symfony/process": "^2 || ^3.3 || ^4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "time": "2018-02-01T13:45:15+00:00" - }, - { - "name": "sebastian/environment", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2017-07-01T08:51:00+00:00" - }, - { - "name": "sebastian/exporter", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2017-04-03T13:19:02+00:00" - }, - { - "name": "sebastian/global-state", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2017-04-27T15:39:26+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "shasum": "" - }, - "require": { - "php": ">=5.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" - }, - { - "name": "sebastian/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2018-01-29T19:49:41+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=7.1.0", - "ext-xmlwriter": "*" - }, - "platform-dev": [] -} diff --git a/src/Extension/Video/CountryRestriction.php b/src/Extension/Video/CountryRestriction.php index 5de3093..5f9f66c 100644 --- a/src/Extension/Video/CountryRestriction.php +++ b/src/Extension/Video/CountryRestriction.php @@ -16,10 +16,10 @@ public function __construct(array $countries) $this->countries = $countries; } - private function validateCountry() + private function validateCountry($name) { // TODO: ISO 3166 } abstract public function areAllowed(): bool; -} \ No newline at end of file +} diff --git a/src/Sitemap.php b/src/Sitemap.php index a02d102..a7c43e6 100644 --- a/src/Sitemap.php +++ b/src/Sitemap.php @@ -3,7 +3,7 @@ use SamDark\Sitemap\Writer\DeflateWriter; use SamDark\Sitemap\Writer\PlainFileWriter; -use Samdark\Sitemap\Writer\TempFileGZIPWriter; +use SamDark\Sitemap\Writer\TempFileGZIPWriter; use SamDark\Sitemap\Writer\WriterInterface; use XMLWriter; @@ -143,7 +143,7 @@ protected function createNewFile(): void * elements that did not fit into the previous file. (See self::flush) */ $this->writer->text(PHP_EOL); - $this->flush(true); + $this->flush(); } /** diff --git a/src/Url.php b/src/Url.php index 7d2e3ae..38a55a8 100644 --- a/src/Url.php +++ b/src/Url.php @@ -25,7 +25,7 @@ class Url private $changeFrequency; /** - * @var string priority (0.0-1.0). Default is 0.5. + * @var float priority (0.0-1.0). Default is 0.5. */ private $priority = 0.5; @@ -164,4 +164,4 @@ public function getExtensionItems(): array { return $this->extensionItems; } -} \ No newline at end of file +} diff --git a/src/Writer/PlainFileWriter.php b/src/Writer/PlainFileWriter.php index fb4f900..b7ef88e 100644 --- a/src/Writer/PlainFileWriter.php +++ b/src/Writer/PlainFileWriter.php @@ -8,7 +8,7 @@ class PlainFileWriter implements WriterInterface { /** - * @var resource for target file + * @var null|resource|closed-resource for target file */ private $file; @@ -38,6 +38,7 @@ public function finish(): void \assert($this->file !== null); fclose($this->file); + $this->file = null; } } diff --git a/src/Writer/TempFileGZIPWriter.php b/src/Writer/TempFileGZIPWriter.php index 5c68b16..2b50916 100644 --- a/src/Writer/TempFileGZIPWriter.php +++ b/src/Writer/TempFileGZIPWriter.php @@ -1,6 +1,6 @@ tempFile, $file); fclose($file); + fclose($this->tempFile); $this->tempFile = null; } From 2dc856a36d32a4d52fe0f678e649bde480192bd0 Mon Sep 17 00:00:00 2001 From: David Goodwin Date: Fri, 2 Jul 2021 18:25:33 +0100 Subject: [PATCH 7/7] Fix unit tests (#75) php7.4 - mime type seems to change to application/gzip rather than application/x-grip file names not correct. --- tests/IndexTest.php | 3 ++- tests/SitemapTest.php | 51 ++++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/tests/IndexTest.php b/tests/IndexTest.php index 0a5dc62..f40a0f3 100644 --- a/tests/IndexTest.php +++ b/tests/IndexTest.php @@ -32,7 +32,8 @@ public function testWritingFileGzipped() $this->assertFileExists($fileName); $finfo = new \finfo(FILEINFO_MIME_TYPE); - $this->assertEquals('application/x-gzip', $finfo->file($fileName)); + + $this->assertRegExp('!application/(x-)?gzip!', $finfo->file($fileName)); $this->assertValidXml('compress.zlib://' . $fileName, 'index'); } } diff --git a/tests/SitemapTest.php b/tests/SitemapTest.php index 2d99fbb..cb85d94 100644 --- a/tests/SitemapTest.php +++ b/tests/SitemapTest.php @@ -66,15 +66,15 @@ public function testMultipleFiles() $expectedFiles = [ $this->getTempPath('testMultipleFiles.xml'), - $this->getTempPath('testMultipleFiles_2.xml'), - $this->getTempPath('testMultipleFiles_3.xml'), - $this->getTempPath('testMultipleFiles_4.xml'), - $this->getTempPath('testMultipleFiles_5.xml'), - $this->getTempPath('testMultipleFiles_6.xml'), - $this->getTempPath('testMultipleFiles_7.xml'), - $this->getTempPath('testMultipleFiles_8.xml'), - $this->getTempPath('testMultipleFiles_9.xml'), - $this->getTempPath('testMultipleFiles_10.xml'), + $this->getTempPath('testMultipleFiles-2.xml'), + $this->getTempPath('testMultipleFiles-3.xml'), + $this->getTempPath('testMultipleFiles-4.xml'), + $this->getTempPath('testMultipleFiles-5.xml'), + $this->getTempPath('testMultipleFiles-6.xml'), + $this->getTempPath('testMultipleFiles-7.xml'), + $this->getTempPath('testMultipleFiles-8.xml'), + $this->getTempPath('testMultipleFiles-9.xml'), + $this->getTempPath('testMultipleFiles-10.xml'), ]; foreach ($expectedFiles as $expectedFile) { $this->assertFileExists($expectedFile, "$expectedFile does not exist!"); @@ -84,7 +84,7 @@ public function testMultipleFiles() $urls = $sitemap->getSitemapUrls('http://example.com/'); $this->assertCount(10, $urls, print_r($urls, true)); $this->assertContains('http://example.com/testMultipleFiles.xml', $urls); - $this->assertContains('http://example.com/testMultipleFiles_10.xml', $urls); + $this->assertContains('http://example.com/testMultipleFiles-10.xml', $urls); } @@ -142,7 +142,7 @@ public function testWritingFileGzipped() $this->assertFileExists($fileName); $finfo = new \finfo(FILEINFO_MIME_TYPE); - $this->assertEquals('application/x-gzip', $finfo->file($fileName)); + $this->assertRegExp('!application/(x-)?gzip!', $finfo->file($fileName)); $this->assertValidXml('compress.zlib://' . $fileName, 'sitemap'); $this->assertIsOneMemberGzipFile($fileName); } @@ -163,20 +163,21 @@ public function testMultipleFilesGzipped() $expectedFiles = [ $this->getTempPath('testMultipleFilesGzipped.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_2.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_3.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_4.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_5.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_6.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_7.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_8.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_9.xml.gz'), - $this->getTempPath('testMultipleFilesGzipped_10.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-2.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-3.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-4.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-5.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-6.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-7.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-8.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-9.xml.gz'), + $this->getTempPath('testMultipleFilesGzipped-10.xml.gz'), ]; $finfo = new \finfo(FILEINFO_MIME_TYPE); foreach ($expectedFiles as $expectedFile) { + $this->assertFileExists($expectedFile, "$expectedFile does not exist!"); - $this->assertEquals('application/x-gzip', $finfo->file($expectedFile)); + $this->assertRegExp('!application/(x-)?gzip!', $finfo->file($expectedFile)); $this->assertValidXml('compress.zlib://' . $expectedFile, 'sitemap'); $this->assertIsOneMemberGzipFile($expectedFile); } @@ -184,7 +185,7 @@ public function testMultipleFilesGzipped() $urls = $sitemap->getSitemapUrls('http://example.com/'); $this->assertCount(10, $urls, print_r($urls, true)); $this->assertContains('http://example.com/testMultipleFilesGzipped.xml.gz', $urls); - $this->assertContains('http://example.com/testMultipleFilesGzipped_10.xml.gz', $urls); + $this->assertContains('http://example.com/testMultipleFilesGzipped-10.xml.gz', $urls); } public function testFileSizeLimit() @@ -204,8 +205,8 @@ public function testFileSizeLimit() $expectedFiles = [ $this->getTempPath('testFileSizeLimit.xml'), - $this->getTempPath('testFileSizeLimit_2.xml'), - $this->getTempPath('testFileSizeLimit_3.xml'), + $this->getTempPath('testFileSizeLimit-2.xml'), + $this->getTempPath('testFileSizeLimit-3.xml'), ]; foreach ($expectedFiles as $expectedFile) { @@ -217,7 +218,7 @@ public function testFileSizeLimit() $urls = $sitemap->getSitemapUrls('http://example.com/'); $this->assertCount(3, $urls, print_r($urls, true)); $this->assertContains('http://example.com/testFileSizeLimit.xml', $urls); - $this->assertContains('http://example.com/testFileSizeLimit_3.xml', $urls); + $this->assertContains('http://example.com/testFileSizeLimit-3.xml', $urls); } public function testSmallSizeLimit()