From 78480ac8531a7abe7e1cac666c7df275184b82bb Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 2 Dec 2017 12:53:32 +0100 Subject: [PATCH 01/70] .gitignore - ignore .env --- .env => .env.dist | 0 .gitignore | 6 ++++++ composer.json | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) rename .env => .env.dist (100%) diff --git a/.env b/.env.dist similarity index 100% rename from .env rename to .env.dist diff --git a/.gitignore b/.gitignore index 0bd0569..735ca31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +# ---------------------------------------------------------------------------------------------------------------------- +# Environment-related parameters +# ---------------------------------------------------------------------------------------------------------------------- +.env + + # ---------------------------------------------------------------------------------------------------------------------- ### Vendors # ---------------------------------------------------------------------------------------------------------------------- diff --git a/composer.json b/composer.json index 5240f99..10278cf 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "meritoo/common-library", "description": "Useful classes, methods, extensions etc.", "license": "MIT", - "version": "0.0.18", + "version": "0.0.19", "authors": [ { "name": "Meritoo.pl", From 3588c0000920fed028fe8635ca9326c4dd51dd56 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 2 Dec 2017 13:12:34 +0100 Subject: [PATCH 02/70] Docker - do not install "zip" package --- .docker/config/Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/.docker/config/Dockerfile b/.docker/config/Dockerfile index 13802c4..222acc8 100644 --- a/.docker/config/Dockerfile +++ b/.docker/config/Dockerfile @@ -7,9 +7,7 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends \ vim \ git \ - zip \ unzip \ - zlib1g-dev \ libicu-dev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* @@ -18,7 +16,6 @@ RUN apt-get update \ # PHP extensions # RUN docker-php-ext-install \ - zip \ intl \ mbstring From 8bb529b88df65a00efa3285d376a6ae6305c424b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 2 Dec 2017 13:23:26 +0100 Subject: [PATCH 03/70] Docker - Dockerfile - minor refactoring --- .docker/config/Dockerfile | 65 +++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/.docker/config/Dockerfile b/.docker/config/Dockerfile index 222acc8..db62e09 100644 --- a/.docker/config/Dockerfile +++ b/.docker/config/Dockerfile @@ -1,4 +1,5 @@ FROM php:5.5-cli +MAINTAINER Meritoo # # Tools & libraries @@ -10,7 +11,10 @@ RUN apt-get update \ unzip \ libicu-dev \ && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + && rm -rf \ + /var/lib/apt/lists/* \ + /tmp/* \ + /var/tmp/* # # PHP extensions @@ -19,6 +23,17 @@ RUN docker-php-ext-install \ intl \ mbstring +# +# PHP extensions (PECL): +# - Xdebug +# +RUN pecl install \ + xdebug \ + && docker-php-ext-enable \ + xdebug + +COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini + # # PHP configuration: # - default configuration @@ -26,14 +41,11 @@ RUN docker-php-ext-install \ # COPY php.ini /usr/local/etc/php/php.ini ARG TIMEZONE -RUN echo "\n""date.timezone = $TIMEZONE""\n" >> /usr/local/etc/php/php.ini - -# -# Xdebug -# -RUN pecl install xdebug \ - && docker-php-ext-enable xdebug -COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini +RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \ + && echo ${TIMEZONE} > /etc/timezone \ + && printf '[PHP]\ndate.timezone = "%s"\n', ${TIMEZONE} > /usr/local/etc/php/conf.d/tzone.ini \ + && "date" +#RUN echo "\n""date.timezone = $TIMEZONE""\n" >> /usr/local/etc/php/php.ini # # Phing @@ -41,21 +53,42 @@ COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini RUN pear channel-discover pear.phing.info \ && pear install [--alldeps] phing/phing +# +# Composer - environment variables: +# - disable warning about running commands as root/super user +# - disable automatic clearing of sudo sessions +# +# More: +# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser +# +ENV COMPOSER_ALLOW_SUPERUSER 1 + # # Composer + https://packagist.org/packages/hirak/prestissimo package # RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ && php -r "if (hash_file('SHA384', 'composer-setup.php') === \ - '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo \ - 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \ + '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo \ + 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \ && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \ && php -r "unlink('composer-setup.php');" \ - && composer global require --no-plugins --no-scripts hirak/prestissimo \ - && rm -rf /root/.composer/cache/* + && composer global require \ + --no-plugins \ + --no-scripts \ + --no-progress \ + --no-suggest \ + --no-interaction \ + --prefer-dist \ + --optimize-autoloader \ + --classmap-authoritative \ + hirak/prestissimo \ + && rm -rf ~/.composer/cache/* \ + && composer clear-cache \ + && composer --version # # Bash # -RUN sed -i 's/^# export/export/g' /root/.bashrc \ - && sed -i 's/^# alias/alias/g' /root/.bashrc \ - && echo "\n"'export PATH=/project/vendor/bin:$PATH'"\n" >> /root/.bashrc +RUN sed -i 's/^# export/export/g' ~/.bashrc \ + && sed -i 's/^# alias/alias/g' ~/.bashrc \ + && echo "\n"'export PATH=/project/vendor/bin:$PATH'"\n" >> ~/.bashrc From 5aaf7cde72fb81a38005ec09e406a1d6367198ba Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 21 Dec 2017 20:41:12 +0100 Subject: [PATCH 04/70] Minor refactoring --- src/Utilities/Bundle.php | 2 +- src/Utilities/Regex.php | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index 12e31cd..ce0a5fc 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -20,7 +20,7 @@ class Bundle * Returns path to view / template of given bundle * * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" - * @param string $bundleName Name of the bundle, e.g. "MyExtraBundle" + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" * @param string $extension (optional) Extension of the view / template * @return string|null */ diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 85cf1c0..41b69c2 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -62,14 +62,14 @@ class Regex } /** - * Returns information if given tax ID (in polish: NIP) is valid + * Returns information if given tax ID is valid (in Poland it's named "NIP") * - * @param string $taxidString Tax ID (NIP) string + * @param string $taxIdString Tax ID (NIP) string * @return bool */ - public static function isValidTaxid($taxidString) + public static function isValidTaxId($taxIdString) { - if (!empty($taxidString)) { + if (!empty($taxIdString)) { $weights = [ 6, 5, @@ -81,15 +81,15 @@ class Regex 6, 7, ]; - $taxid = preg_replace('/[\s-]/', '', $taxidString); + $taxId = preg_replace('/[\s-]/', '', $taxIdString); $sum = 0; - if (10 == strlen($taxid) && is_numeric($taxid)) { + if (10 == strlen($taxId) && is_numeric($taxId)) { for ($x = 0; $x <= 8; ++$x) { - $sum += $taxid[$x] * $weights[$x]; + $sum += $taxId[$x] * $weights[$x]; } - if ((($sum % 11) % 10) == $taxid[9]) { + if ((($sum % 11) % 10) == $taxId[9]) { return true; } } From 66aefa24466fe4dab3f6101735a42b284f9221ab Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 21 Dec 2017 21:47:45 +0100 Subject: [PATCH 05/70] Regex - isValidBundleName() method - returns information if given name of bundle is valid --- src/Utilities/Regex.php | 18 ++++++++++ tests/Utilities/RegexTest.php | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 41b69c2..6a0ac04 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -37,6 +37,7 @@ class Regex 'windowsBasedPath' => '/^[A-Z]{1}:\\\.*$/', 'money' => '/^[-+]?\d+([\.,]{1}\d*)?$/', 'color' => '/^[a-f0-9]{6}$/i', + 'bundleName' => '/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', ]; /** @@ -723,4 +724,21 @@ class Regex return strtolower($color); } + + /** + * Returns information if given name of bundle is valid + * + * @param string $bundleName Full name of bundle to verify, e.g. "MyExtraBundle" + * @return bool + */ + public static function isValidBundleName($bundleName) + { + if (!is_string($bundleName)) { + return false; + } + + $pattern = self::$patterns['bundleName']; + + return (bool)preg_match($pattern, $bundleName); + } } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index fe89710..07c74d0 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Common\Utilities; +use Generator; use Meritoo\Common\Test\Base\BaseTestCase; /** @@ -273,6 +274,69 @@ class RegexTest extends BaseTestCase self::assertTrue(Regex::isValidNip('5252530705')); // Facebook Poland sp. z o.o. } + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testIsValidBundleNameUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidBundleName($emptyValue)); + } + + /** + * @param string $bundleName Full name of bundle to verify, e.g. "MyExtraBundle" + * @param bool $expected Information if it's valid name + * + * @dataProvider provideBundleName + */ + public function testIsValidBundleName($bundleName, $expected) + { + self::assertEquals($expected, Regex::isValidBundleName($bundleName)); + } + + /** + * Provides name of bundle and information if it's valid name + * + * @return Generator + */ + public function provideBundleName() + { + yield[ + 'something', + false, + ]; + + yield[ + 'something_different', + false, + ]; + + yield[ + 'something-else', + false, + ]; + + yield[ + 'myExtraBundle', + false, + ]; + + yield[ + 'MyExtra', + false, + ]; + + yield[ + 'MyExtraBundle', + true, + ]; + + yield[ + 'MySuperExtraGorgeousBundle', + true, + ]; + } + /** * {@inheritdoc} */ From 0e4c33241e7d547f8263d1493a9a528713627522 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 21 Dec 2017 22:05:07 +0100 Subject: [PATCH 06/70] Tests - BundleTest - minor refactoring --- tests/Utilities/BundleTest.php | 103 +++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 10 deletions(-) diff --git a/tests/Utilities/BundleTest.php b/tests/Utilities/BundleTest.php index f7af8b1..fa7555b 100644 --- a/tests/Utilities/BundleTest.php +++ b/tests/Utilities/BundleTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Common\Test\Utilities; +use Generator; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Bundle; @@ -24,22 +25,104 @@ class BundleTest extends BaseTestCase static::assertHasNoConstructor(Bundle::class); } - public function testGetBundleViewPathEmptyPathAndBundle() + /** + * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" + * + * @dataProvider provideEmptyViewPathAndBundle + */ + public function testGetBundleViewPathUsingEmptyPathAndBundle($viewPath, $bundleName) { - self::assertNull(Bundle::getBundleViewPath('', '')); - self::assertNull(Bundle::getBundleViewPath('test', '')); - self::assertNull(Bundle::getBundleViewPath('', 'test')); + self::assertNull(Bundle::getBundleViewPath($viewPath, $bundleName)); } - public function testGetBundleViewPathWithDefaultExtension() + /** + * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" + * @param string $expected Expected path to view / template + * + * @dataProvider provideViewPathAndBundle + */ + public function testGetBundleViewPathUsingDefaultExtension($viewPath, $bundleName, $expected) { - self::assertEquals('Lorem:Ipsum.html.twig', Bundle::getBundleViewPath('Ipsum', 'Lorem')); - self::assertEquals('LobortisTincidunt:FusceElementum.html.twig', Bundle::getBundleViewPath('FusceElementum', 'LobortisTincidunt')); + self::assertEquals($expected, Bundle::getBundleViewPath($viewPath, $bundleName)); } - public function testGetBundleViewPathWithCustomExtension() + /** + * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" + * @param string $extension (optional) Extension of the view / template + * @param string $expected Expected path to view / template + * + * @dataProvider provideViewPathAndBundleAndExtension + */ + public function testGetBundleViewPathUsingCustomExtension($viewPath, $bundleName, $extension, $expected) { - self::assertNull(Bundle::getBundleViewPath('Ipsum', 'Lorem', '')); - self::assertEquals('Lorem:Ipsum.js.twig', Bundle::getBundleViewPath('Ipsum', 'Lorem', 'js.twig')); + self::assertEquals($expected, Bundle::getBundleViewPath($viewPath, $bundleName, $extension)); + } + + /** + * Provides empty path of the view / template and/or name of bundle + * + * @return Generator + */ + public function provideEmptyViewPathAndBundle() + { + yield[ + '', + '', + ]; + + yield[ + 'test', + '', + ]; + + yield[ + '', + 'test', + ]; + } + + /** + * Provides path of the view / template and name of bundle + * + * @return Generator + */ + public function provideViewPathAndBundle() + { + yield[ + 'Ipsum', + 'Lorem', + 'Lorem:Ipsum.html.twig', + ]; + + yield[ + 'FusceElementum', + 'LobortisTincidunt', + 'LobortisTincidunt:FusceElementum.html.twig', + ]; + } + + /** + * Provides path of the view / template, name of bundle and extension of the view / template + * + * @return Generator + */ + public function provideViewPathAndBundleAndExtension() + { + yield[ + 'Ipsum', + 'Lorem', + '', + null, + ]; + + yield[ + 'Ipsum', + 'Lorem', + 'js.twig', + 'Lorem:Ipsum.js.twig', + ]; } } From 7d23ff59d133f1189317940da6f6b1a2b86f283a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 21 Dec 2017 22:43:45 +0100 Subject: [PATCH 07/70] Bundle - getBundleViewPath() method - verify name of bundle --- .../Bundle/IncorrectBundleNameException.php | 34 +++++++++ src/Utilities/Bundle.php | 13 +++- tests/Utilities/BundleTest.php | 73 ++++++++++++++++--- 3 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 src/Exception/Bundle/IncorrectBundleNameException.php diff --git a/src/Exception/Bundle/IncorrectBundleNameException.php b/src/Exception/Bundle/IncorrectBundleNameException.php new file mode 100644 index 0000000..1686967 --- /dev/null +++ b/src/Exception/Bundle/IncorrectBundleNameException.php @@ -0,0 +1,34 @@ + + * @copyright Meritoo.pl + */ +class IncorrectBundleNameException extends Exception +{ + /** + * Class constructor + * + * @param string $bundleName Incorrect name of bundle + */ + public function __construct($bundleName) + { + $template = 'Name of bundle \'%s\' is incorrect. It should start with big letter and end with "Bundle". Is' + . ' there everything ok?'; + + $message = sprintf($template, $bundleName); + parent::__construct($message); + } +} diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index ce0a5fc..2fa3206 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -8,6 +8,8 @@ namespace Meritoo\Common\Utilities; +use Meritoo\Common\Exception\Bundle\IncorrectBundleNameException; + /** * Useful methods for bundle * @@ -17,12 +19,14 @@ namespace Meritoo\Common\Utilities; class Bundle { /** - * Returns path to view / template of given bundle + * Returns path of given bundle to view / template with given extension * * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" * @param string $extension (optional) Extension of the view / template * @return string|null + * + * @throws IncorrectBundleNameException */ public static function getBundleViewPath($viewPath, $bundleName, $extension = 'html.twig') { @@ -34,6 +38,13 @@ class Bundle return null; } + /* + * Given name of bundle is invalid? + */ + if (!Regex::isValidBundleName($bundleName)) { + throw new IncorrectBundleNameException($bundleName); + } + /* * Path of the view / template doesn't end with given extension? */ diff --git a/tests/Utilities/BundleTest.php b/tests/Utilities/BundleTest.php index fa7555b..909810c 100644 --- a/tests/Utilities/BundleTest.php +++ b/tests/Utilities/BundleTest.php @@ -9,6 +9,7 @@ namespace Meritoo\Common\Test\Utilities; use Generator; +use Meritoo\Common\Exception\Bundle\IncorrectBundleNameException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Bundle; @@ -29,6 +30,7 @@ class BundleTest extends BaseTestCase * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" * + * @throws IncorrectBundleNameException * @dataProvider provideEmptyViewPathAndBundle */ public function testGetBundleViewPathUsingEmptyPathAndBundle($viewPath, $bundleName) @@ -36,11 +38,30 @@ class BundleTest extends BaseTestCase self::assertNull(Bundle::getBundleViewPath($viewPath, $bundleName)); } + /** + * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" + * + * @throws IncorrectBundleNameException + * @dataProvider provideViewPathAndIncorrectBundleName + */ + public function testGetBundleViewPathUsingIncorrectBundleName($viewPath, $bundleName) + { + $template = 'Name of bundle \'%s\' is incorrect. It should start with big letter and end with "Bundle". Is' + . ' there everything ok?'; + + $message = sprintf($template, $bundleName); + $this->setExpectedException(IncorrectBundleNameException::class, $message); + + Bundle::getBundleViewPath($viewPath, $bundleName); + } + /** * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" * @param string $expected Expected path to view / template * + * @throws IncorrectBundleNameException * @dataProvider provideViewPathAndBundle */ public function testGetBundleViewPathUsingDefaultExtension($viewPath, $bundleName, $expected) @@ -54,6 +75,7 @@ class BundleTest extends BaseTestCase * @param string $extension (optional) Extension of the view / template * @param string $expected Expected path to view / template * + * @throws IncorrectBundleNameException * @dataProvider provideViewPathAndBundleAndExtension */ public function testGetBundleViewPathUsingCustomExtension($viewPath, $bundleName, $extension, $expected) @@ -84,6 +106,29 @@ class BundleTest extends BaseTestCase ]; } + /** + * Provides path of the view / template and incorrect name of bundle + * + * @return Generator + */ + public function provideViewPathAndIncorrectBundleName() + { + yield[ + 'User:Active', + 'myExtra', + ]; + + yield[ + 'User:Active', + 'MyExtra', + ]; + + yield[ + 'User:Active', + 'MySuperExtraGorgeous', + ]; + } + /** * Provides path of the view / template and name of bundle * @@ -92,15 +137,21 @@ class BundleTest extends BaseTestCase public function provideViewPathAndBundle() { yield[ - 'Ipsum', - 'Lorem', - 'Lorem:Ipsum.html.twig', + ':User', + 'MyExtraBundle', + 'MyExtraBundle::User.html.twig', ]; yield[ - 'FusceElementum', - 'LobortisTincidunt', - 'LobortisTincidunt:FusceElementum.html.twig', + 'User:Active', + 'MyExtraBundle', + 'MyExtraBundle:User:Active.html.twig', + ]; + + yield[ + 'User:Active', + 'MySuperExtraGorgeousBundle', + 'MySuperExtraGorgeousBundle:User:Active.html.twig', ]; } @@ -112,17 +163,17 @@ class BundleTest extends BaseTestCase public function provideViewPathAndBundleAndExtension() { yield[ - 'Ipsum', - 'Lorem', + 'User:Active', + 'MyExtraBundle', '', null, ]; yield[ - 'Ipsum', - 'Lorem', + 'User:Active', + 'MyExtraBundle', 'js.twig', - 'Lorem:Ipsum.js.twig', + 'MyExtraBundle:User:Active.js.twig', ]; } } From ebbed4825cba806a5173f739f0938ea71d62f961 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 21 Dec 2017 23:44:39 +0100 Subject: [PATCH 08/70] Bundle - getBundleViewPath() method - return path using namespaced syntax --- src/Utilities/Bundle.php | 36 ++++++++++++++- src/Utilities/Regex.php | 12 ++++- tests/Utilities/BundleTest.php | 84 ++++++++++++++++++++++++++++++++-- tests/Utilities/RegexTest.php | 5 ++ 4 files changed, 130 insertions(+), 7 deletions(-) diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index 2fa3206..d2ffbca 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -52,6 +52,40 @@ class Bundle $viewPath = sprintf('%s.%s', $viewPath, $extension); } - return sprintf('%s:%s', $bundleName, $viewPath); + /* + * Prepare short name of bundle and path of view / template with "/" (instead of ":") + */ + $shortBundleName = static::getShortBundleName($bundleName); + $viewPath = str_replace(':', '/', $viewPath); + + return sprintf('@%s/%s', $shortBundleName, $viewPath); + } + + /** + * Returns short name of bundle (without "Bundle") + * + * @param string $fullBundleName Full name of the bundle, e.g. "MyExtraBundle" + * @return string|null + * + * @throws IncorrectBundleNameException + */ + public static function getShortBundleName($fullBundleName) + { + /* + * Given name of bundle is invalid? + */ + if (!Regex::isValidBundleName($fullBundleName)) { + if (!is_string($fullBundleName)) { + $fullBundleName = gettype($fullBundleName); + } + + throw new IncorrectBundleNameException($fullBundleName); + } + + $matches = []; + $pattern = Regex::getBundleNamePattern(); + preg_match($pattern, $fullBundleName, $matches); + + return $matches[1]; } } diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 6a0ac04..3004740 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -737,8 +737,18 @@ class Regex return false; } - $pattern = self::$patterns['bundleName']; + $pattern = self::getBundleNamePattern(); return (bool)preg_match($pattern, $bundleName); } + + /** + * Returns pattern used to validate / verify name of bundle + * + * @return string + */ + public static function getBundleNamePattern() + { + return self::$patterns['bundleName']; + } } diff --git a/tests/Utilities/BundleTest.php b/tests/Utilities/BundleTest.php index 909810c..20dd847 100644 --- a/tests/Utilities/BundleTest.php +++ b/tests/Utilities/BundleTest.php @@ -83,6 +83,42 @@ class BundleTest extends BaseTestCase self::assertEquals($expected, Bundle::getBundleViewPath($viewPath, $bundleName, $extension)); } + /** + * @param mixed $emptyValue Empty value, e.g. "" + * + * @throws IncorrectBundleNameException + * @dataProvider provideEmptyValue + */ + public function testGetShortBundleNameUsingEmptyValue($emptyValue) + { + $this->setExpectedException(IncorrectBundleNameException::class); + Bundle::getShortBundleName($emptyValue); + } + + /** + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" + * + * @throws IncorrectBundleNameException + * @dataProvider provideIncorrectBundleName + */ + public function testGetShortBundleNameUsingIncorrectBundleName($bundleName) + { + $this->setExpectedException(IncorrectBundleNameException::class); + Bundle::getShortBundleName($bundleName); + } + + /** + * @param string $fullBundleName Full name of the bundle, e.g. "MyExtraBundle" + * @param string $shortBundleName Short name of bundle (without "Bundle") + * + * @throws IncorrectBundleNameException + * @dataProvider provideFullAndShortBundleName + */ + public function testGetShortBundleName($fullBundleName, $shortBundleName) + { + self::assertEquals($shortBundleName, Bundle::getShortBundleName($fullBundleName)); + } + /** * Provides empty path of the view / template and/or name of bundle * @@ -137,21 +173,21 @@ class BundleTest extends BaseTestCase public function provideViewPathAndBundle() { yield[ - ':User', + 'User', 'MyExtraBundle', - 'MyExtraBundle::User.html.twig', + '@MyExtra/User.html.twig', ]; yield[ 'User:Active', 'MyExtraBundle', - 'MyExtraBundle:User:Active.html.twig', + '@MyExtra/User/Active.html.twig', ]; yield[ 'User:Active', 'MySuperExtraGorgeousBundle', - 'MySuperExtraGorgeousBundle:User:Active.html.twig', + '@MySuperExtraGorgeous/User/Active.html.twig', ]; } @@ -173,7 +209,45 @@ class BundleTest extends BaseTestCase 'User:Active', 'MyExtraBundle', 'js.twig', - 'MyExtraBundle:User:Active.js.twig', + '@MyExtra/User/Active.js.twig', + ]; + } + + /** + * Provides incorrect name of bundle + * + * @return Generator + */ + public function provideIncorrectBundleName() + { + yield[ + 'myExtra', + ]; + + yield[ + 'MyExtra', + ]; + + yield[ + 'MySuperExtraGorgeous', + ]; + } + + /** + * Provides full and short name of bundle + * + * @return Generator + */ + public function provideFullAndShortBundleName() + { + yield[ + 'MyExtraBundle', + 'MyExtra', + ]; + + yield[ + 'MySuperExtraGorgeousBundle', + 'MySuperExtraGorgeous', ]; } } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index 07c74d0..196aef4 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -294,6 +294,11 @@ class RegexTest extends BaseTestCase self::assertEquals($expected, Regex::isValidBundleName($bundleName)); } + public function testGetBundleNamePattern() + { + self::assertEquals('/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', Regex::getBundleNamePattern()); + } + /** * Provides name of bundle and information if it's valid name * From 7f713e0c6e1eabb288569568dadce6ae84492409 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 22 Dec 2017 10:44:07 +0100 Subject: [PATCH 09/70] Docker - name of containers - use custom prefix --- .env.dist | 13 +++++++++++++ docker-compose.yml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.env.dist b/.env.dist index c6eb126..c613201 100644 --- a/.env.dist +++ b/.env.dist @@ -1 +1,14 @@ +# ----------------------------------------------------------------------------- +# Docker +# ----------------------------------------------------------------------------- + +# +# All containers +# +DOCKER_CONTAINER_PREFIX=__ENTER__CONTAINER__PREFIX__ + +# +# PHP configuration: +# - timezone +# TIMEZONE=Europe/Warsaw diff --git a/docker-compose.yml b/docker-compose.yml index 38655bd..17c10e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ version: '3' services: php-cli: image: meritoo/common-library - container_name: meritoo-common-library + container_name: ${DOCKER_CONTAINER_PREFIX} working_dir: /project entrypoint: php command: -S 0.0.0.0:9999 From 67530769372cd456922c299ec53a8314bf4ba7af Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 23 Dec 2017 23:08:49 +0100 Subject: [PATCH 10/70] Regex - isValidHtmlAttribute() & areValidHtmlAttributes() methods - returns information if given html attribute is valid & if given html attributes are valid --- src/Utilities/Regex.php | 45 ++++++++++++ tests/Utilities/RegexTest.php | 131 ++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 3004740..427bf49 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -32,6 +32,7 @@ class Regex 'urlDomain' => '([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i', 'letterOrDigit' => '/[a-zA-Z0-9]+/', 'htmlEntity' => '/&[a-z0-9]+;/', + 'htmlAttribute' => '/([\w-]+)="([\w -]+)"/', 'fileName' => '/.+\.\w+$/', 'isQuoted' => '/^[\'"]{1}.+[\'"]{1}$/', 'windowsBasedPath' => '/^[A-Z]{1}:\\\.*$/', @@ -751,4 +752,48 @@ class Regex { return self::$patterns['bundleName']; } + + /** + * Returns pattern used to validate / verify html attribute + * + * @return string + */ + public static function getHtmlAttributePattern() + { + return self::$patterns['htmlAttribute']; + } + + /** + * Returns information if given html attribute is valid + * + * @param string $htmlAttribute The html attribute to verify + * @return bool + */ + public static function isValidHtmlAttribute($htmlAttribute) + { + if (!is_string($htmlAttribute)) { + return false; + } + + $pattern = self::getHtmlAttributePattern(); + + return (bool)preg_match($pattern, $htmlAttribute); + } + + /** + * Returns information if given html attributes are valid + * + * @param string $htmlAttributes The html attributes to verify + * @return bool + */ + public static function areValidHtmlAttributes($htmlAttributes) + { + if (!is_string($htmlAttributes)) { + return false; + } + + $pattern = self::getHtmlAttributePattern(); + + return (bool)preg_match_all($pattern, $htmlAttributes); + } } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index 196aef4..e97544c 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -299,6 +299,51 @@ class RegexTest extends BaseTestCase self::assertEquals('/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', Regex::getBundleNamePattern()); } + public function testGetHtmlAttributePattern() + { + self::assertEquals('/([\w-]+)="([\w -]+)"/', Regex::getHtmlAttributePattern()); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testIsValidHtmlAttributeUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidHtmlAttribute($emptyValue)); + } + + /** + * @param string $htmlAttribute The html attribute to verify + * @param bool $expected Information if it's valid attribute + * + * @dataProvider provideHtmlAttribute + */ + public function testIsValidHtmlAttribute($htmlAttribute, $expected) + { + self::assertEquals($expected, Regex::isValidHtmlAttribute($htmlAttribute)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testAreValidHtmlAttributesUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::areValidHtmlAttributes($emptyValue)); + } + + /** + * @param string $htmlAttributes The html attributes to verify + * @param bool $expected Information if attributes are valid + * + * @dataProvider provideHtmlAttributes + */ + public static function testAreValidHtmlAttributes($htmlAttributes, $expected) + { + self::assertEquals($expected, Regex::areValidHtmlAttributes($htmlAttributes)); + } + /** * Provides name of bundle and information if it's valid name * @@ -342,6 +387,92 @@ class RegexTest extends BaseTestCase ]; } + /** + * Provides html attribute and information if it's valid + * + * @return Generator + */ + public function provideHtmlAttribute() + { + yield[ + 'abc = def', + false, + ]; + + yield[ + 'a b c=def', + false, + ]; + + yield[ + 'abc=def', + false, + ]; + + yield[ + 'a1b2c=d3e4f', + false, + ]; + + yield[ + 'abc="def"', + true, + ]; + + yield[ + 'a1b2c="d3e4f"', + true, + ]; + } + + /** + * Provides html attribute and information if attributes are valid + * + * @return Generator + */ + public function provideHtmlAttributes() + { + yield[ + 'abc = def', + false, + ]; + + yield[ + 'abc = def ghi = jkl', + false, + ]; + + yield[ + 'abc=def ghi=jkl', + false, + ]; + + yield[ + 'abc=def ghi=jkl mno=pqr', + false, + ]; + + yield[ + 'abc="def"', + true, + ]; + + yield[ + 'abc="def" ghi="jkl"', + true, + ]; + + yield[ + 'abc="def" ghi="jkl" mno="pqr"', + true, + ]; + + yield[ + 'a2bc="d4ef" ghi="j k l" mno="pq9r"', + true, + ]; + } + /** * {@inheritdoc} */ From d801e675fc1a0853cd7fb3f281b7bcd9a328a7aa Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 24 Dec 2017 00:03:23 +0100 Subject: [PATCH 11/70] Exception - InvalidHtmlAttributesException - an exception used while html attributes are invalid --- .../Regex/InvalidHtmlAttributesException.php | 29 ++++++++ .../InvalidColorHexValueExceptionTest.php | 4 ++ .../InvalidHtmlAttributesExceptionTest.php | 69 +++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 src/Exception/Regex/InvalidHtmlAttributesException.php create mode 100644 tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php diff --git a/src/Exception/Regex/InvalidHtmlAttributesException.php b/src/Exception/Regex/InvalidHtmlAttributesException.php new file mode 100644 index 0000000..a09c9ed --- /dev/null +++ b/src/Exception/Regex/InvalidHtmlAttributesException.php @@ -0,0 +1,29 @@ + + * @copyright Meritoo.pl + */ +class InvalidHtmlAttributesException extends \Exception +{ + /** + * Class constructor + * + * @param string $htmlAttributes Invalid html attributes + */ + public function __construct($htmlAttributes) + { + $message = sprintf('HTML attributes \'%s\' are invalid. Is there everything ok?', $htmlAttributes); + parent::__construct($message); + } +} diff --git a/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php b/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php index 7376676..921ccb3 100644 --- a/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php +++ b/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php @@ -10,6 +10,7 @@ namespace Meritoo\Common\Test\Exception\Regex; use Generator; use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; +use Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; @@ -21,6 +22,9 @@ use Meritoo\Common\Type\OopVisibilityType; */ class InvalidColorHexValueExceptionTest extends BaseTestCase { + /** + * @throws UnknownOopVisibilityTypeException + */ public function testConstructorVisibilityAndArguments() { static::assertConstructorVisibilityAndArguments(InvalidColorHexValueException::class, OopVisibilityType::IS_PUBLIC, 1, 1); diff --git a/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php b/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php new file mode 100644 index 0000000..8a067fd --- /dev/null +++ b/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php @@ -0,0 +1,69 @@ + + * @copyright Meritoo.pl + */ +class InvalidHtmlAttributesExceptionTest extends BaseTestCase +{ + /** + * @throws UnknownOopVisibilityTypeException + */ + public function testConstructorVisibilityAndArguments() + { + static::assertConstructorVisibilityAndArguments(InvalidHtmlAttributesException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + } + + /** + * @param string $htmlAttributes Invalid html attributes + * @param string $expectedMessage Expected exception's message + * + * @dataProvider provideHtmlAttributes + */ + public function testConstructorMessage($htmlAttributes, $expectedMessage) + { + $exception = new InvalidHtmlAttributesException($htmlAttributes); + static::assertEquals($expectedMessage, $exception->getMessage()); + } + + /** + * Provides html attributes + * + * @return Generator + */ + public function provideHtmlAttributes() + { + $template = 'HTML attributes \'%s\' are invalid. Is there everything ok?'; + + yield[ + 'abc = def', + sprintf($template, 'abc = def'), + ]; + + yield[ + 'abc = def ghi = jkl', + sprintf($template, 'abc = def ghi = jkl'), + ]; + + yield[ + 'abc=def ghi=jkl', + sprintf($template, 'abc=def ghi=jkl'), + ]; + } +} From 780d4df17e42083c5ae01f5dbb5682fd584fb8c1 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 25 Dec 2017 23:50:47 +0100 Subject: [PATCH 12/70] Tests - increase code coverage --- src/Utilities/Uri.php | 94 +++++++++--- tests/Utilities/UriTest.php | 287 +++++++++++++++++++++++++++++++++++- 2 files changed, 356 insertions(+), 25 deletions(-) diff --git a/src/Utilities/Uri.php b/src/Utilities/Uri.php index 96253b0..c5e470d 100644 --- a/src/Utilities/Uri.php +++ b/src/Utilities/Uri.php @@ -24,13 +24,25 @@ class Uri */ public static function getFullUri($withoutHost = false) { - $effect = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'REQUEST_URI'); + $requestedUrl = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'REQUEST_URI'); - if ($withoutHost) { - return $effect; + /* + * Unknown requested url? + * Nothing to do + */ + if (empty($requestedUrl)) { + return ''; } - return self::getServerNameOrIp(true) . $effect; + /* + * Without host / server name? + * All is done + */ + if ($withoutHost) { + return $requestedUrl; + } + + return self::getServerNameOrIp(true) . $requestedUrl; } /** @@ -41,13 +53,25 @@ class Uri */ public static function getServerNameOrIp($withProtocol = false) { - $protocol = ''; + $host = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_HOST'); - if ($withProtocol) { - $protocol .= self::getProtocolName() . '://'; + /* + * Unknown host / server? + * Nothing to do + */ + if (empty($host)) { + return ''; } - return $protocol . Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_HOST'); + /* + * With protocol? + * Let's include the protocol + */ + if ($withProtocol) { + return sprintf('%s://%s', self::getProtocolName(), $host); + } + + return $host; } /** @@ -57,8 +81,6 @@ class Uri */ public static function getProtocolName() { - $effect = ''; - $matches = []; $protocolData = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'SERVER_PROTOCOL'); // e.g. HTTP/1.1 $matchCount = preg_match('|(.+)\/(.+)|', $protocolData, $matches); @@ -68,11 +90,14 @@ class Uri * $matches[2] - protocol version, e.g. 1.1 */ - if ($matchCount > 0) { - $effect = strtolower($matches[1]); + /* + * Oops, cannot match protocol + */ + if (0 == $matchCount) { + return ''; } - return $effect; + return strtolower($matches[1]); } /** @@ -82,13 +107,7 @@ class Uri */ public static function getRefererUri() { - $effect = ''; - - if (filter_has_var(INPUT_SERVER, 'HTTP_REFERER')) { - $effect = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_REFERER'); - } - - return $effect; + return Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_REFERER'); } /** @@ -214,10 +233,35 @@ class Uri */ public static function isExternalUrl($url) { + /* + * Unknown url or it's just slash? + * Nothing to do + */ + if (empty($url) || '/' === $url) { + return false; + } + $currentUrl = self::getServerNameOrIp(true); $url = self::replenishProtocol($url); - return !Regex::contains($currentUrl, $url); + /* + * Let's prepare pattern of current url + */ + $search = [ + ':', + '/', + '.', + ]; + + $replace = [ + '\:', + '\/', + '\.', + ]; + + $currentUrlPattern = str_replace($search, $replace, $currentUrl); + + return !Regex::contains($url, $currentUrlPattern); } /** @@ -273,6 +317,14 @@ class Uri */ public static function getSecuredUrl($url, $user = '', $password = '') { + /* + * Url is not provided? + * Nothing to do + */ + if (empty($url)) { + return ''; + } + $protocol = self::getProtocolName(); $host = self::getServerNameOrIp(); diff --git a/tests/Utilities/UriTest.php b/tests/Utilities/UriTest.php index 6c195d9..80fbba7 100644 --- a/tests/Utilities/UriTest.php +++ b/tests/Utilities/UriTest.php @@ -8,6 +8,7 @@ namespace Meritoo\Common\Test\Utilities; +use Generator; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Uri; @@ -55,19 +56,199 @@ class UriTest extends BaseTestCase * @param string $protocol (optional) The protocol which is replenished. If is empty, protocol of current request * is used. * - * @dataProvider provideUrlsToReplenishProtocol + * @dataProvider provideUrlToReplenishProtocol */ public function testReplenishProtocol($expected, $url, $protocol = '') { self::assertSame($expected, Uri::replenishProtocol($url, $protocol)); } + public function testGetServerNameOrIpWithoutProtocol() + { + $_SERVER['HTTP_HOST'] = ''; + self::assertEquals('', Uri::getServerNameOrIp()); + + $host = 'lorem.com'; + $_SERVER['HTTP_HOST'] = $host; + + self::assertEquals($host, Uri::getServerNameOrIp()); + } + + public function testGetServerNameOrIpWithProtocol() + { + $_SERVER['HTTP_HOST'] = ''; + $_SERVER['SERVER_PROTOCOL'] = ''; + + self::assertEquals('', Uri::getServerNameOrIp(true)); + + $host = 'lorem.com'; + $protocol = 'HTTP/1.1'; + + $_SERVER['HTTP_HOST'] = $host; + $_SERVER['SERVER_PROTOCOL'] = $protocol; + + self::assertEquals(sprintf('http://%s', $host), Uri::getServerNameOrIp(true)); + } + + public function testGetFullUriWithHost() + { + $_SERVER['HTTP_HOST'] = ''; + $_SERVER['SERVER_PROTOCOL'] = ''; + $_SERVER['REQUEST_URI'] = ''; + + self::assertEquals('', Uri::getFullUri()); + + $host = 'lorem.com'; + $protocol = 'HTTP/1.1'; + $requestedUrl = '/test/123'; + + $_SERVER['HTTP_HOST'] = $host; + $_SERVER['SERVER_PROTOCOL'] = $protocol; + $_SERVER['REQUEST_URI'] = $requestedUrl; + + self::assertEquals(sprintf('http://%s%s', $host, $requestedUrl), Uri::getFullUri()); + } + + public function testGetFullUriWithoutHost() + { + $_SERVER['HTTP_HOST'] = ''; + $_SERVER['SERVER_PROTOCOL'] = ''; + $_SERVER['REQUEST_URI'] = ''; + + self::assertEquals('', Uri::getFullUri(true)); + + $requestedUrl = '/test/123'; + $_SERVER['REQUEST_URI'] = $requestedUrl; + + self::assertEquals($requestedUrl, Uri::getFullUri(true)); + } + + public function testGetProtocolName() + { + $_SERVER['SERVER_PROTOCOL'] = ''; + self::assertEquals('', Uri::getProtocolName()); + + $protocol = 'HTTP/1.1'; + $_SERVER['SERVER_PROTOCOL'] = $protocol; + + self::assertEquals('http', Uri::getProtocolName()); + } + + public function testGetRefererUri() + { + $_SERVER['HTTP_REFERER'] = ''; + self::assertEquals('', Uri::getRefererUri()); + + $refererUrl = 'http://lorem.com/test/123'; + $_SERVER['HTTP_REFERER'] = $refererUrl; + + self::assertEquals($refererUrl, Uri::getRefererUri()); + } + + public function testGetUserAddressIp() + { + $_SERVER['REMOTE_ADDR'] = ''; + self::assertEquals('', Uri::getUserAddressIp()); + + $userAddressIp = '1.2.3.4'; + $_SERVER['REMOTE_ADDR'] = $userAddressIp; + + self::assertEquals($userAddressIp, Uri::getUserAddressIp()); + } + + public function testGetUserWebBrowserInfo() + { + $_SERVER['HTTP_USER_AGENT'] = ''; + self::assertEquals('', Uri::getUserWebBrowserInfo()); + + $browserInfo = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko)' + . ' Version/8.0.2 Safari/600.2.5'; + + $_SERVER['HTTP_USER_AGENT'] = $browserInfo; + self::assertEquals($browserInfo, Uri::getUserWebBrowserInfo()); + } + + public function testGetUserWebBrowserNameWithoutVersion() + { + $_SERVER['HTTP_USER_AGENT'] = ''; + self::assertEquals('', Uri::getUserWebBrowserName()); + + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like' + . ' Gecko) Version/8.0.2 Safari/600.2.5'; + + self::assertEquals('Apple Safari', Uri::getUserWebBrowserName()); + } + + public function testGetUserWebBrowserNameWithVersion() + { + $_SERVER['HTTP_USER_AGENT'] = ''; + self::assertEquals('', Uri::getUserWebBrowserName(true)); + + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like' + . ' Gecko) Version/8.0.2 Safari/600.2.5'; + + self::assertEquals('Apple Safari 600.2.5', Uri::getUserWebBrowserName(true)); + } + + public function testGetUserOperatingSystemName() + { + $_SERVER['HTTP_USER_AGENT'] = ''; + self::assertEquals('', Uri::getUserOperatingSystemName()); + + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like' + . ' Gecko) Version/8.0.2 Safari/600.2.5'; + + self::assertEquals('Mac OS', Uri::getUserOperatingSystemName()); + } + + public function testIsServerLocalhost() + { + $_SERVER['HTTP_HOST'] = ''; + self::assertFalse(Uri::isServerLocalhost()); + + $_SERVER['HTTP_HOST'] = '127.0.0.1'; + self::assertTrue(Uri::isServerLocalhost()); + } + /** - * Provides urls to replenish protocol + * @param string $url The url to check + * @param bool $expected Information if verified url is external * - * @return \Generator + * @dataProvider provideUrlToVerifyIfIsExternal */ - public function provideUrlsToReplenishProtocol() + public function testIsExternalUrl($url, $expected) + { + $host = 'lorem.com'; + $protocol = 'HTTP/1.1'; + + $_SERVER['HTTP_HOST'] = $host; + $_SERVER['SERVER_PROTOCOL'] = $protocol; + + self::assertEquals($expected, Uri::isExternalUrl($url)); + } + + /** + * @param string $url A path / url to some resource, e.g. page, image, css file + * @param string $user User name used to log in + * @param string $password User password used to log in + * @param string $expectedUrl Expected, secured url + * + * @dataProvider provideDataForSecuredUrl + */ + public function testGetSecuredUrl($url, $user, $password, $expectedUrl) + { + $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; + $_SERVER['HTTP_HOST'] = 'lorem.com'; + + self::assertEquals($expectedUrl, Uri::getSecuredUrl($url, $user, $password)); + } + + /** + * Provides url to replenish protocol + * + * @return Generator + */ + public function provideUrlToReplenishProtocol() { yield[ '://test', @@ -81,4 +262,102 @@ class UriTest extends BaseTestCase 'ftp', ]; } + + /** + * Provides url used to verify if it's external, from another server / domain + * + * @return Generator + */ + public function provideUrlToVerifyIfIsExternal() + { + yield[ + '', + false, + ]; + + yield[ + '/', + false, + ]; + + yield[ + 'http://something.different/first-page', + true, + ]; + + yield[ + 'something.different/first-page', + true, + ]; + + yield[ + 'http://lorem.com', + false, + ]; + + yield[ + 'http://lorem.com/contact', + false, + ]; + + yield[ + 'lorem.com', + false, + ]; + + yield[ + 'lorem.com/contact', + false, + ]; + } + + /** + * Provides data used to build secured url + * + * @return Generator + */ + public function provideDataForSecuredUrl() + { + yield[ + '', + '', + '', + '', + ]; + + yield[ + '/', + '', + '', + 'http://lorem.com/', + ]; + + yield[ + 'contact', + '', + '', + 'http://lorem.com/contact', + ]; + + yield[ + 'contact', + 'john', + '', + 'http://lorem.com/contact', + ]; + + yield[ + 'contact', + '', + 'pass123', + 'http://lorem.com/contact', + ]; + + yield[ + 'contact', + 'john', + 'pass123', + 'http://john:pass123@lorem.com/contact', + ]; + } } From e9b8fb8852d07eff293e6543f368ba4260053e9a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 10 Jan 2018 17:35:42 +0100 Subject: [PATCH 13/70] Regex - isBinaryValue() method - returns information if given value is a binary value --- src/Utilities/Regex.php | 18 ++++++++++ tests/Utilities/RegexTest.php | 67 +++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 427bf49..525720a 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -39,6 +39,7 @@ class Regex 'money' => '/^[-+]?\d+([\.,]{1}\d*)?$/', 'color' => '/^[a-f0-9]{6}$/i', 'bundleName' => '/^(([A-Z]{1}[a-z0-9]+)((?2))*)(Bundle)$/', + 'binaryValue' => '/[^\x20-\x7E\t\r\n]/', ]; /** @@ -796,4 +797,21 @@ class Regex return (bool)preg_match_all($pattern, $htmlAttributes); } + + /** + * Returns information if given value is a binary value + * + * @param string $value Value to verify + * @return bool + */ + public static function isBinaryValue($value) + { + if (!is_string($value)) { + return false; + } + + $pattern = self::$patterns['binaryValue']; + + return (bool)preg_match($pattern, $value); + } } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index e97544c..f040190 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -344,6 +344,17 @@ class RegexTest extends BaseTestCase self::assertEquals($expected, Regex::areValidHtmlAttributes($htmlAttributes)); } + /** + * @param string $value Value to verify + * @param bool $expected Information if value is a binary value + * + * @dataProvider provideBinaryValue + */ + public static function testIsBinaryValue($value, $expected) + { + self::assertEquals($expected, Regex::isBinaryValue($value)); + } + /** * Provides name of bundle and information if it's valid name * @@ -473,6 +484,62 @@ class RegexTest extends BaseTestCase ]; } + /** + * Provides value to verify if it is a binary value + * + * @return Generator + */ + public function provideBinaryValue() + { + $file1Path = $this->getFilePathForTesting('lorem-ipsum.txt'); + $file2Path = $this->getFilePathForTesting('minion.jpg'); + + yield[ + null, + false, + ]; + + yield[ + [], + false, + ]; + + yield[ + '', + false, + ]; + + yield[ + 'abc', + false, + ]; + + yield[ + '1234', + false, + ]; + + yield[ + 1234, + false, + ]; + + yield[ + 12.34, + false, + ]; + + yield[ + fread(fopen($file1Path, 'r'), 1), + false, + ]; + + yield[ + fread(fopen($file2Path, 'r'), 1), + true, + ]; + } + /** * {@inheritdoc} */ From 8a4860088f407bc1fd7eb35d9721d7ed887ced93 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 14 Jan 2018 21:19:06 +0100 Subject: [PATCH 14/70] Phing - Composer-related task - validate Composer --- .phing/app.xml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.phing/app.xml b/.phing/app.xml index 028fe2b..89848ec 100644 --- a/.phing/app.xml +++ b/.phing/app.xml @@ -21,9 +21,9 @@ depends="app:composer, app:vendors, app:checkout" description="Prepares app to build." /> - - - + + + @@ -42,7 +42,14 @@ + + + + + + + @@ -68,6 +75,8 @@ + + From 57b411b59f09c364b77a948bc23d011e30208449 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 17 Jan 2018 21:37:07 +0100 Subject: [PATCH 15/70] Tests - increase code coverage --- src/Utilities/Regex.php | 76 ++++++++++++++------ tests/Utilities/RegexTest.php | 127 ++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 23 deletions(-) diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 525720a..c0a5dd1 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -25,7 +25,7 @@ class Regex * @var array */ private static $patterns = [ - 'email' => '/[\w-]{2,}@[\w-]+\.[\w]{2,}+/', + 'email' => '/^[\w-.]{2,}@[\w-]+\.[\w]{2,}+$/', 'phone' => '/^\+?[0-9 ]+$/', 'camelCasePart' => '/([a-z]|[A-Z]){1}[a-z]*/', 'urlProtocol' => '/^([a-z]+:\/\/)', @@ -59,6 +59,10 @@ class Regex */ public static function isValidEmail($email) { + if (!is_string($email)) { + return false; + } + $pattern = self::getEmailPattern(); return (bool)preg_match($pattern, $email); @@ -72,30 +76,56 @@ class Regex */ public static function isValidTaxId($taxIdString) { - if (!empty($taxIdString)) { - $weights = [ - 6, - 5, - 7, - 2, - 3, - 4, - 5, - 6, - 7, - ]; - $taxId = preg_replace('/[\s-]/', '', $taxIdString); - $sum = 0; + /* + * Not a string? + * Nothing to do + */ + if (!is_string($taxIdString)) { + return false; + } - if (10 == strlen($taxId) && is_numeric($taxId)) { - for ($x = 0; $x <= 8; ++$x) { - $sum += $taxId[$x] * $weights[$x]; - } + /* + * Empty/Unknown value? + * Nothing to do + */ + if (empty($taxIdString)) { + return false; + } - if ((($sum % 11) % 10) == $taxId[9]) { - return true; - } - } + $taxId = preg_replace('/[\s-]/', '', $taxIdString); + + /* + * Tax ID is not 10 characters length OR is not numeric? + * Nothing to do + */ + if (10 !== strlen($taxId) || !is_numeric($taxId)) { + return false; + } + + $weights = [ + 6, + 5, + 7, + 2, + 3, + 4, + 5, + 6, + 7, + ]; + + $sum = 0; + + for ($x = 0; $x <= 8; ++$x) { + $sum += $taxId[$x] * $weights[$x]; + } + + /* + * Last number it's not a remainder from dividing per 11? + * Nothing to do + */ + if ($sum % 11 == $taxId[9]) { + return true; } return false; diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index f040190..d95b389 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -355,6 +355,46 @@ class RegexTest extends BaseTestCase self::assertEquals($expected, Regex::isBinaryValue($value)); } + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testIsValidEmailUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidEmail($emptyValue)); + } + + /** + * @param string $email E-mail address to validate / verify + * @param bool $expected Information if e-mail is valid + * + * @dataProvider provideEmail + */ + public static function testIsValidEmail($email, $expected) + { + self::assertEquals($expected, Regex::isValidEmail($email)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testIsValidTaxIdUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidTaxId($emptyValue)); + } + + /** + * @param string $taxIdString Tax ID (NIP) string + * @param bool $expected Information if tax ID is valid + * + * @dataProvider provideTaxId + */ + public static function testIsValidTaxId($taxIdString, $expected) + { + self::assertEquals($expected, Regex::isValidTaxId($taxIdString)); + } + /** * Provides name of bundle and information if it's valid name * @@ -540,6 +580,93 @@ class RegexTest extends BaseTestCase ]; } + /** + * Provides e-mail and information if it's valid + * + * @return Generator + */ + public function provideEmail() + { + yield[ + '1', + false, + ]; + + yield[ + 1, + false, + ]; + + yield[ + 'a@a', + false, + ]; + + yield[ + 'a@a.com', + false, + ]; + + yield[ + 'aa@a.com', + true, + ]; + + yield[ + 'a.b@d.com', + true, + ]; + } + + /** + * Provides tax ID and information if it's valid + * + * @return Generator + */ + public function provideTaxId() + { + yield[ + '123', + false, + ]; + + yield[ + '12345', + false, + ]; + + yield[ + '1122334455', + false, + ]; + + yield[ + '1234567890', + false, + ]; + + yield[ + '0987654321', + false, + ]; + + /* + * Microsoft sp. z o.o. + */ + yield[ + '5270103391', + true, + ]; + + /* + * Onet S.A. + */ + yield[ + '7340009469', + true, + ]; + } + /** * {@inheritdoc} */ From 1e3e1d454e96898117f7331c81cca4b387d95318 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 27 Jan 2018 12:59:55 +0100 Subject: [PATCH 16/70] Docker - Dockerfile - install "locales" package & generate popular locales Required to run tests related to setlocale() function (and Meritoo\Common\Utilities\Locale class) properly --- .docker/config/Dockerfile | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.docker/config/Dockerfile b/.docker/config/Dockerfile index db62e09..5f3a6cf 100644 --- a/.docker/config/Dockerfile +++ b/.docker/config/Dockerfile @@ -10,12 +10,34 @@ RUN apt-get update \ git \ unzip \ libicu-dev \ + locales \ && apt-get clean \ && rm -rf \ /var/lib/apt/lists/* \ /tmp/* \ /var/tmp/* +# +# Generating locales: +# - de_DE +# - es_ES +# - en_GB +# - en_US +# - fr_FR +# - it_IT +# - pl_PL +# - ru_RU +# +RUN sed -i 's/^# de_DE/de_DE/g; \ + s/^# es_ES/es_ES/g; \ + s/^# en_GB/en_GB/g; \ + s/^# en_US/en_US/g; \ + s/^# fr_FR/fr_FR/g; \ + s/^# it_IT/it_IT/g; \ + s/^# pl_PL/pl_PL/g; \ + s/^# ru_RU/ru_RU/g;' /etc/locale.gen \ + && locale-gen + # # PHP extensions # From af38c35a1bd8e89e9a7fc2046ff23f079c834ce6 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 27 Jan 2018 13:04:04 +0100 Subject: [PATCH 17/70] Utilities - Locale - setLocale() method - return result of setting new locale (instead of "true") Tests - Locale - fix incorrectly prepared tests --- src/Utilities/Locale.php | 5 +- tests/Utilities/LocaleTest.php | 99 +++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/Utilities/Locale.php b/src/Utilities/Locale.php index 5ae1157..ee391a2 100644 --- a/src/Utilities/Locale.php +++ b/src/Utilities/Locale.php @@ -23,7 +23,7 @@ class Locale * setting. It's the same constant as required by setlocale() function. * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". * @param string $countryCode (optional) Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" - * @return bool + * @return false|string * * Available categories (values of $category argument): * - LC_ALL for all of the below @@ -57,9 +57,8 @@ class Locale } $localeLongForm = self::getLongForm($languageCode, $countryCode); - setlocale($category, $localeLongForm); - return true; + return setlocale($category, $localeLongForm); } /** diff --git a/tests/Utilities/LocaleTest.php b/tests/Utilities/LocaleTest.php index d3f089c..c990235 100644 --- a/tests/Utilities/LocaleTest.php +++ b/tests/Utilities/LocaleTest.php @@ -40,7 +40,7 @@ class LocaleTest extends BaseTestCase * @param string $encoding Encoding of the final locale * @param string $expected Expected long form of the locale * - * @dataProvider provideLanguageAndCountryCode + * @dataProvider provideLanguageEncodingAndCountryCode */ public function testGetLongForm($languageCode, $countryCode, $encoding, $expected) { @@ -56,24 +56,31 @@ class LocaleTest extends BaseTestCase self::assertFalse(Locale::setLocale($emptyValue, $emptyValue)); } - /** - * @param int $category Named constant specifying the category of the functions affected by the locale - * setting. It's the same constant as required by setlocale() function. - * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". - * - * @dataProvider provideCategoryAndLanguageCode - */ - public function testSetLocale($category, $languageCode) + public function testSetLocaleIncorrectCategory() { - self::assertTrue(Locale::setLocale($category, $languageCode)); + self::assertFalse(Locale::setLocale(-1, 'en')); } /** - * Provides language and country code + * @param int $category Named constant specifying the category of the functions affected by the locale + * setting. It's the same constant as required by setlocale() function. + * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". + * @param string $countryCode Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" + * @param string $expectedLocale Expected locale + * + * @dataProvider provideCategoryLanguageCodeAndExpectedLocale + */ + public function testSetLocale($category, $languageCode, $countryCode, $expectedLocale) + { + self::assertEquals($expectedLocale, Locale::setLocale($category, $languageCode, $countryCode)); + } + + /** + * Provides language, encoding and country code * * @return Generator */ - public function provideLanguageAndCountryCode() + public function provideLanguageEncodingAndCountryCode() { yield[ 'fr', @@ -102,33 +109,97 @@ class LocaleTest extends BaseTestCase 'UTF-8', 'fr_FR.UTF-8', ]; + + yield[ + 'en', + 'US', + '', + 'en_US', + ]; + + yield[ + 'en', + 'US', + 'UTF-8', + 'en_US.UTF-8', + ]; + + yield[ + 'en', + 'US', + 'ISO-8859-1', + 'en_US.ISO-8859-1', + ]; } /** - * Provides category and language + * Provides category * * @return Generator */ - public function provideCategoryAndLanguageCode() + public function provideCategoryLanguageCodeAndExpectedLocale() { yield[ LC_ALL, 'fr', + '', + 'fr_FR.UTF-8', ]; yield[ LC_COLLATE, 'fr', + 'FR', + 'fr_FR.UTF-8', ]; yield[ LC_CTYPE, 'en', + 'US', + 'en_US.UTF-8', ]; yield[ LC_NUMERIC, 'en', + 'GB', + 'en_GB.UTF-8', + ]; + + yield[ + LC_MONETARY, + 'es', + '', + 'es_ES.UTF-8', + ]; + + yield[ + LC_MONETARY, + 'es', + 'ES', + 'es_ES.UTF-8', + ]; + + yield[ + LC_TIME, + 'it', + '', + 'it_IT.UTF-8', + ]; + + yield[ + LC_TIME, + 'it', + 'IT', + 'it_IT.UTF-8', + ]; + + yield[ + LC_TIME, + 'it', + 'it', + 'it_IT.UTF-8', ]; } } From 470b8244ecc19616245fd803309470c2b983f851 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 27 Jan 2018 13:05:20 +0100 Subject: [PATCH 18/70] Utilities - Locale - getLocale() method - returns locale for given category --- src/Utilities/Locale.php | 21 +++++++++++++++++++++ tests/Utilities/LocaleTest.php | 15 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/Utilities/Locale.php b/src/Utilities/Locale.php index ee391a2..bb89a73 100644 --- a/src/Utilities/Locale.php +++ b/src/Utilities/Locale.php @@ -61,6 +61,27 @@ class Locale return setlocale($category, $localeLongForm); } + /** + * Returns locale for given category + * + * @param int $category Named constant specifying the category of the functions affected by the locale setting. + * It's the same constant as required by setlocale() function. + * @return string + * + * Available categories (values of $category argument): + * - LC_ALL for all of the below + * - LC_COLLATE for string comparison, see strcoll() + * - LC_CTYPE for character classification and conversion, for example strtoupper() + * - LC_MONETARY for localeconv() + * - LC_NUMERIC for decimal separator (See also localeconv()) + * - LC_TIME for date and time formatting with strftime() + * - LC_MESSAGES for system responses (available if PHP was compiled with libintl) + */ + public static function getLocale($category) + { + return setlocale($category, '0'); + } + /** * Returns long form of the locale * diff --git a/tests/Utilities/LocaleTest.php b/tests/Utilities/LocaleTest.php index c990235..b695469 100644 --- a/tests/Utilities/LocaleTest.php +++ b/tests/Utilities/LocaleTest.php @@ -75,6 +75,21 @@ class LocaleTest extends BaseTestCase self::assertEquals($expectedLocale, Locale::setLocale($category, $languageCode, $countryCode)); } + /** + * @param int $category Named constant specifying the category of the functions affected by the locale setting. + * It's the same constant as required by setlocale() function. + * @param string $languageCode Language code, in ISO 639-1 format. Short form of the locale, e.g. "fr". + * @param string $countryCode Country code, in ISO 3166-1 alpha-2 format, e.g. "FR" + * @param string $expectedLocale Expected locale + * + * @dataProvider provideCategoryLanguageCodeAndExpectedLocale + */ + public function testGetLocale($category, $languageCode, $countryCode, $expectedLocale) + { + Locale::setLocale($category, $languageCode, $countryCode); + self::assertEquals($expectedLocale, Locale::getLocale($category)); + } + /** * Provides language, encoding and country code * From ad64d2e02a6c4c13e2758b6a5388b4f71747dc7a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 27 Jan 2018 13:10:14 +0100 Subject: [PATCH 19/70] Docker - Dockerfile - minor update --- .docker/config/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.docker/config/Dockerfile b/.docker/config/Dockerfile index 5f3a6cf..2d8e5a0 100644 --- a/.docker/config/Dockerfile +++ b/.docker/config/Dockerfile @@ -111,6 +111,6 @@ RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ # # Bash # -RUN sed -i 's/^# export/export/g' ~/.bashrc \ - && sed -i 's/^# alias/alias/g' ~/.bashrc \ +RUN sed -i 's/^# export/export/g; \ + s/^# alias/alias/g;' ~/.bashrc \ && echo "\n"'export PATH=/project/vendor/bin:$PATH'"\n" >> ~/.bashrc From b7d0b61094c9421a1caa4c78c9c1bb496a913d5a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 30 Mar 2018 21:15:42 +0200 Subject: [PATCH 20/70] tests > PHPUnit configuration > update --- phpunit.xml.dist | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index fd0219d..ffd8beb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,35 @@ - + + + + ./tests/ @@ -30,6 +49,6 @@ - + From 8d1df9ced85693235a1408765bc37b105f0a3862 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 30 Mar 2018 22:07:04 +0200 Subject: [PATCH 21/70] Tests - increase code coverage --- src/Traits/Test/Base/BaseTestCaseTrait.php | 22 + src/Utilities/Reflection.php | 2 +- src/Utilities/Regex.php | 203 ++-- tests/Utilities/RegexTest.php | 1039 ++++++++++++++++++++ 4 files changed, 1186 insertions(+), 80 deletions(-) diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 6f3f2e5..2f0ae16 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -14,7 +14,9 @@ use Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException; use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Common\Utilities\Miscellaneous; use ReflectionClass; +use ReflectionException; use ReflectionMethod; +use stdClass; /** * BaseTestCaseTrait @@ -103,6 +105,26 @@ trait BaseTestCaseTrait yield['surprise/me/one/more/time.txt']; } + /** + * Provides non scalar value, e.g. [] or null + * + * @return Generator + */ + public function provideNonScalarValue() + { + yield[ + [], + ]; + + yield[ + null, + ]; + + yield[ + new stdClass(), + ]; + } + /** * Returns path of file used by tests. * It should be placed in /.data/tests directory of this project. diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 6577d08..23ecd58 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -428,7 +428,7 @@ class Reflection $parents = class_parents($childClassName); - if (is_array($parents)) { + if (is_array($parents) && 0 < count($parents)) { return in_array($parentClassName, $parents); } diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index c0a5dd1..cc39b19 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -154,88 +154,104 @@ class Regex */ public static function isValidPhoneNumber($phoneNumber) { + if (!is_string($phoneNumber)) { + return false; + } + $pattern = self::getPhoneNumberPattern(); - return (bool)preg_match($pattern, $phoneNumber); + return (bool)preg_match($pattern, trim($phoneNumber)); } /** - * Returns array values that matches given pattern (or values that keys matches) + * Returns array values that match given pattern (or values that keys match the pattern) * * @param string $pattern Pattern to match - * @param array $dataArray The array - * @param bool $itsKeyPattern (optional) If is set to true, keys are checks if they match pattern. Otherwise - - * values are checks. + * @param array $array The array (scalar values only) + * @param bool $itsKeyPattern (optional) If is set to true, keys will be checked if they match pattern. + * Otherwise - values will be checked (default behaviour). * @return array */ - public static function getArrayValuesByPattern($pattern, $dataArray, $itsKeyPattern = false) + public static function getArrayValuesByPattern($pattern, array $array, $itsKeyPattern = false) { + /* + * No elements? + * Nothing to do + */ + if (empty($array)) { + return []; + } + if ($itsKeyPattern) { $effect = []; - if (!empty($dataArray)) { - $matches = []; - - foreach ($dataArray as $key => $value) { - if (preg_match($pattern, $key, $matches)) { - $effect[$key] = $value; - } + foreach ($array as $key => $value) { + if ((bool)preg_match($pattern, $key)) { + $effect[$key] = $value; } } return $effect; } - return preg_grep($pattern, $dataArray); + return preg_grep($pattern, $array); } /** * Filters array by given expression and column * - * Expression can be simple compare expression, like ' == 2', or regular expression. + * Expression can be simple compare expression, like " == 2", or regular expression. * Returns filtered array. * - * @param array $array The array that should be filtered + * @param array $array The 2-dimensional array that should be filtered * @param string $arrayColumnKey Column name - * @param string $filterExpression Filter expression, e.g. '== 2' or '!= \'home\'' - * @param bool $itsRegularExpression (optional) If is set to true, means that filter expression is a - * regular expression + * @param string $filterExpression Simple filter expression (e.g. "== 2" or "!= \'home\'") or regular + * expression (e.g. "/\d+/" or "/[a-z]+[,;]{2,}/") + * @param bool $itsRegularExpression (optional) If is set to true, means that filter expression is a regular + * expression. Otherwise - not (default behaviour). * @return array */ public static function arrayFilter($array, $arrayColumnKey, $filterExpression, $itsRegularExpression = false) { - $effect = []; + /* + * No elements? + * Nothing to do + */ + if (empty($array)) { + return []; + } - if (!empty($array)) { - $effect = $array; + $effect = $array; - foreach ($effect as $key => &$item) { - if (isset($item[$arrayColumnKey])) { - $value = $item[$arrayColumnKey]; + foreach ($effect as $key => &$item) { + if (!isset($item[$arrayColumnKey])) { + continue; + } - if ($itsRegularExpression) { - $matches = []; - $pattern = '|' . $filterExpression . '|'; - $matchesCount = preg_match($pattern, $value, $matches); + $value = $item[$arrayColumnKey]; - $remove = 0 == $matchesCount; + if ($itsRegularExpression) { + $matchesCount = preg_match($filterExpression, $value); + $remove = 0 == $matchesCount; + } else { + if (is_string($value)) { + $value = sprintf('\'%s\'', $value); + } elseif (is_bool($value)) { + if (true === $value) { + $value = 'true'; } else { - if ('' == $value) { - $value = '\'\''; - } elseif (is_string($value)) { - $value = '\'' . $value . '\''; - } - - eval('$isTrue = ' . $value . $filterExpression . ';'); - - /* @var bool $isTrue */ - $remove = !$isTrue; - } - - if ($remove) { - unset($effect[$key]); + $value = 'false'; } } + + eval(sprintf('$isEqual = %s%s;', $value, $filterExpression)); + + /* @var bool $isEqual */ + $remove = !$isEqual; + } + + if ($remove) { + unset($effect[$key]); } } @@ -243,36 +259,41 @@ class Regex } /** - * Perform regular expression match with many given patterns. + * Performs regular expression match with many given patterns. * Returns information if given $subject matches one or all given $patterns. * * @param array|string $patterns The patterns to match * @param string $subject The string to check * @param bool $mustAllMatch (optional) If is set to true, $subject must match all $patterns. Otherwise - - * not. + * not (default behaviour). * @return bool */ public static function pregMultiMatch($patterns, $subject, $mustAllMatch = false) { + /* + * No patterns? + * Nothing to do + */ + if (empty($patterns)) { + return false; + } + $effect = false; $patterns = Arrays::makeArray($patterns); - if (!empty($patterns)) { + if ($mustAllMatch) { + $effect = true; + } + + foreach ($patterns as $pattern) { + $matched = (bool)preg_match_all($pattern, $subject); + if ($mustAllMatch) { - $effect = true; - } - - foreach ($patterns as $pattern) { - $matches = []; - $matched = (bool)preg_match_all($pattern, $subject, $matches); - - if ($mustAllMatch) { - $effect = $effect && $matched; - } else { - if ($matched) { - $effect = $matched; - break; - } + $effect = $effect && $matched; + } else { + if ($matched) { + $effect = $matched; + break; } } } @@ -709,6 +730,10 @@ class Regex */ public static function isValidMoneyValue($value) { + if (!is_scalar($value)) { + return false; + } + $pattern = self::getMoneyPattern(); return (bool)preg_match($pattern, $value); @@ -728,33 +753,53 @@ class Regex */ public static function getValidColorHexValue($color, $throwException = true) { + /* + * Not a scalar value? + * Nothing to do + */ + if (!is_scalar($color)) { + return false; + } + $color = Miscellaneous::replace($color, '/#/', ''); $length = strlen($color); - if (3 === $length) { - $color = Miscellaneous::replace($color, '/(.)(.)(.)/', '$1$1$2$2$3$3'); - } else { - if (6 !== $length) { - if ($throwException) { - throw new IncorrectColorHexLengthException($color); - } - - return false; - } - } - - $pattern = self::$patterns['color']; - $match = (bool)preg_match($pattern, $color); - - if (!$match) { + /* + * Color is not 3 or 6 characters long? + * Nothing to do + */ + if (3 !== $length && 6 !== $length) { if ($throwException) { - throw new InvalidColorHexValueException($color); + throw new IncorrectColorHexLengthException($color); } return false; } - return strtolower($color); + /* + * Color is 3 characters long? + * Let's make it 6 characters long + */ + if (3 === $length) { + $color = Miscellaneous::replace($color, '/(.)(.)(.)/', '$1$1$2$2$3$3'); + } + + $pattern = self::$patterns['color']; + $match = (bool)preg_match($pattern, $color); + + /* + * It's valid color + * Nothing to do more + */ + if ($match) { + return strtolower($color); + } + + if ($throwException) { + throw new InvalidColorHexValueException($color); + } + + return false; } /** diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index d95b389..db3c2b9 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -9,6 +9,8 @@ namespace Meritoo\Common\Utilities; use Generator; +use Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException; +use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; use Meritoo\Common\Test\Base\BaseTestCase; /** @@ -165,6 +167,12 @@ class RegexTest extends BaseTestCase public function testStartsWithDirectorySeparator() { + /* + * Not provided, default separator + */ + self::assertTrue(Regex::startsWithDirectorySeparator('/my/extra/directory')); + self::assertFalse(Regex::startsWithDirectorySeparator('my/extra/directory')); + /* * Slash as separator */ @@ -184,6 +192,12 @@ class RegexTest extends BaseTestCase public function testEndsWithDirectorySeparator() { + /* + * Not provided, default separator + */ + self::assertTrue(Regex::endsWithDirectorySeparator('my simple text/')); + self::assertFalse(Regex::endsWithDirectorySeparator('my simple text')); + /* * Slash as separator */ @@ -395,6 +409,233 @@ class RegexTest extends BaseTestCase self::assertEquals($expected, Regex::isValidTaxId($taxIdString)); } + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public static function testIsValidPhoneNumberUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidPhoneNumber($emptyValue)); + } + + /** + * @param string $phoneNumber The phone number to validate / verify + * @param bool $expected Information if phone number is valid + * + * @dataProvider providePhoneNumber + */ + public static function testIsValidPhoneNumber($phoneNumber, $expected) + { + self::assertEquals($expected, Regex::isValidPhoneNumber($phoneNumber)); + } + + /** + * @param string $pattern Pattern to match + * @param array $dataArray The array + * @param array $expected Expected array + * + * @dataProvider providePatternForArrayValues + */ + public static function testGetArrayValuesByPatternUsingValues($pattern, array $dataArray, $expected) + { + self::assertEquals($expected, Regex::getArrayValuesByPattern($pattern, $dataArray)); + } + + /** + * @param string $pattern Pattern to match + * @param array $dataArray The array + * @param array $expected Expected array + * + * @dataProvider providePatternForArrayKeys + */ + public static function testGetArrayValuesByPatternUsingKeys($pattern, array $dataArray, $expected) + { + self::assertEquals($expected, Regex::getArrayValuesByPattern($pattern, $dataArray, true)); + } + + /** + * @param array $array The array that should be filtered + * @param string $arrayColumnKey Column name + * @param string $filterExpression Simple filter expression, e.g. "== 2" or "!= \'home\'" + * @param array $expected Expected array + * + * @dataProvider provideSimpleExpressionForArrayFiltering + */ + public function testArrayFilterUsingSimpleExpression($array, $arrayColumnKey, $filterExpression, $expected) + { + self::assertEquals($expected, Regex::arrayFilter($array, $arrayColumnKey, $filterExpression)); + } + + /** + * @param array $array The array that should be filtered + * @param string $arrayColumnKey Column name + * @param string $filterExpression Regular expression, e.g. "/\d+/" or "/[a-z]+[,;]{2,}/" + * @param array $expected Expected array + * + * @dataProvider provideRegularExpressionForArrayFiltering + */ + public function testArrayFilterUsingRegularExpression($array, $arrayColumnKey, $filterExpression, $expected) + { + self::assertEquals($expected, Regex::arrayFilter($array, $arrayColumnKey, $filterExpression, true)); + } + + /** + * @param array|string $patterns The patterns to match + * @param string $subject The string to check + * @param bool $expected Information if given $subject matches given $patterns + * + * @dataProvider providePatternsAndSubjectForPregMultiMatch + */ + public function testPregMultiMatch($patterns, $subject, $expected) + { + self::assertEquals($expected, Regex::pregMultiMatch($patterns, $subject)); + } + + /** + * @param array|string $patterns The patterns to match + * @param string $subject The string to check + * @param bool $expected Information if given $subject matches given $patterns + * + * @dataProvider providePatternsAndSubjectForPregMultiMatchWhenMustMatchAllPatterns + */ + public function testPregMultiMatchWhenMustMatchAllPatterns($patterns, $subject, $expected) + { + self::assertEquals($expected, Regex::pregMultiMatch($patterns, $subject, true)); + } + + public function testGetMoneyPattern() + { + self::assertEquals('/^[-+]?\d+([\.,]{1}\d*)?$/', Regex::getMoneyPattern()); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * @dataProvider provideEmptyNonMoneyValue + */ + public function testIsValidMoneyValueUsingEmptyValue($emptyValue) + { + self::assertFalse(Regex::isValidMoneyValue($emptyValue)); + } + + /** + * @param mixed $value Value to verify + * @param bool $expected Information if given value is a money value + * + * @dataProvider provideMoneyValue + */ + public function testIsValidMoneyValue($value, $expected) + { + self::assertEquals($expected, Regex::isValidMoneyValue($value)); + } + + /** + * @param mixed $nonScalarValue Non scalar value, e.g. [] or null + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + * + * @dataProvider provideNonScalarValue + */ + public function testGetValidColorHexValueUsingNonScalarValue($nonScalarValue) + { + self::assertFalse(Regex::getValidColorHexValue($nonScalarValue)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + * + * @dataProvider provideColorEmptyValue + */ + public function testGetValidColorHexValueUsingEmptyValueWithoutException($emptyValue) + { + self::assertFalse(Regex::getValidColorHexValue($emptyValue, false)); + } + + /** + * @param mixed $emptyValue Empty value, e.g. "" + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + * + * @dataProvider provideColorEmptyValue + */ + public function testGetValidColorHexValueUsingEmptyValue($emptyValue) + { + $this->setExpectedException(IncorrectColorHexLengthException::class); + Regex::getValidColorHexValue($emptyValue); + } + + /** + * @param string $incorrectColor Incorrect value of color + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + * + * @dataProvider provideColorIncorrectLength + */ + public function testGetValidColorHexValueUsingIncorrectValueWithoutException($incorrectColor) + { + self::assertFalse(Regex::getValidColorHexValue($incorrectColor, false)); + } + + /** + * @param string $incorrectColor Incorrect value of color + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + * + * @dataProvider provideColorIncorrectLength + */ + public function testGetValidColorHexValueUsingIncorrectValue($incorrectColor) + { + $this->setExpectedException(IncorrectColorHexLengthException::class); + Regex::getValidColorHexValue($incorrectColor); + } + + /** + * @param string $invalidColor Invalid value of color + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + * + * @dataProvider provideColorInvalidValue + */ + public function testGetValidColorHexValueUsingInvalidValueWithoutException($invalidColor) + { + self::assertFalse(Regex::getValidColorHexValue($invalidColor, false)); + } + + /** + * @param string $invalidColor Invalid value of color + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + * + * @dataProvider provideColorInvalidValue + */ + public function testGetValidColorHexValueUsingInvalidValue($invalidColor) + { + $this->setExpectedException(InvalidColorHexValueException::class); + Regex::getValidColorHexValue($invalidColor); + } + + /** + * @param string $color Color to verify + * @param string $expected Expected value of color + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + * + * @dataProvider provideColor + */ + public function testGetValidColorHexValue($color, $expected) + { + self::assertEquals($expected, Regex::getValidColorHexValue($color)); + } + /** * Provides name of bundle and information if it's valid name * @@ -667,6 +908,804 @@ class RegexTest extends BaseTestCase ]; } + /** + * Provides phone number and information if it's valid + * + * @return Generator + */ + public function providePhoneNumber() + { + yield[ + 'abc', + false, + ]; + + yield[ + '1-2-3', + false, + ]; + + yield[ + '123', + true, + ]; + + yield[ + '123 456 789', + true, + ]; + + yield[ + '123456789', + true, + ]; + } + + /** + * Provides pattern and array with values that should match that pattern + * + * @return Generator + */ + public function providePatternForArrayValues() + { + yield[ + '/\d/', + [], + [], + ]; + + yield[ + '/\d+/', + [ + 'lorem', + 'ipsum', + 123, + 'dolor', + '456', + ], + [ + 2 => 123, + 4 => '456', + ], + ]; + + yield[ + '/\d+-[a-z]+/', + [ + 'lorem', + 123, + false, + 'dolor', + '456-ipsum', + ], + [ + 4 => '456-ipsum', + ], + ]; + } + + /** + * Provides pattern and array with keys that should match that pattern + * + * @return Generator + */ + public function providePatternForArrayKeys() + { + yield[ + '/\d/', + [], + [], + ]; + + yield[ + '/\d+/', + [ + 'lorem' => 'ipsum', + 'dolor' => 123, + 'sit', + 4 => '456', + ], + [ + 0 => 'sit', + 4 => '456', + ], + ]; + + yield[ + '/\d+-[a-z]+/', + [ + 'lorem', + '456-ipsum' => 123, + '001-sit' => false, + 'dolor', + ], + [ + '456-ipsum' => 123, + '001-sit' => false, + ], + ]; + } + + /** + * Provides simple compare expression for array filtering and the array + * + * @return Generator + */ + public function provideSimpleExpressionForArrayFiltering() + { + yield[ + [], + 'id', + ' == 2', + [], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'birth_date', + ' == 2', + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'id', + ' == 2', + [ + 1 => [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + ], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'id', + ' >= 2', + [ + 1 => [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + 2 => [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'is_active', + ' !== true', + [ + 2 => [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'first_name', + ' == \'Mike\'', + [ + 2 => [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + } + + /** + * Provides regular expression for array filtering and the array + * + * @return Generator + */ + public function provideRegularExpressionForArrayFiltering() + { + yield[ + [], + 'id', + '/\d+/', + [], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'birth_date', + '/\d+/', + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 123, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'id', + '/\d{3}/', + [ + 1 => [ + 'id' => 123, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + ], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 123, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 456, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + 'first_name', + '/George|Mike/', + [ + 1 => [ + 'id' => 123, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + 2 => [ + 'id' => 456, + 'first_name' => 'Mike', + 'last_name' => 'Green', + 'is_active' => false, + ], + ], + ]; + + yield[ + [ + [ + 'id' => 1, + 'first_name' => 'Jane', + 'last_name' => 'Scott', + 'is_active' => true, + ], + [ + 'id' => 2, + 'first_name' => 'George', + 'last_name' => 'Brown', + 'is_active' => true, + ], + [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green-Blue', + 'is_active' => false, + ], + ], + 'last_name', + '/\w+-\w+/', + [ + 2 => [ + 'id' => 3, + 'first_name' => 'Mike', + 'last_name' => 'Green-Blue', + 'is_active' => false, + ], + ], + ]; + } + + /** + * Provides patterns and subject for the pregMultiMatch() method + * + * @return Generator + */ + public function providePatternsAndSubjectForPregMultiMatch() + { + yield[ + '', + '', + false, + ]; + + yield[ + [], + '', + false, + ]; + + yield[ + '/\d+/', + 'Lorem ipsum dolor sit', + false, + ]; + + yield[ + [ + '/\d+/', + '/^[a-z]{4}$/', + ], + 'Lorem ipsum dolor sit', + false, + ]; + + yield[ + '/\w+/', + 'Lorem ipsum dolor sit', + true, + ]; + + yield[ + [ + '/\d+/', + '/\w+/', + ], + 'Lorem ipsum dolor sit', + true, + ]; + } + + /** + * Provides patterns and subject for the pregMultiMatch() method when must match all patterns + * + * @return Generator + */ + public function providePatternsAndSubjectForPregMultiMatchWhenMustMatchAllPatterns() + { + yield[ + '', + '', + false, + ]; + + yield[ + [], + '', + false, + ]; + + yield[ + '/\d+/', + 'Lorem ipsum dolor sit', + false, + ]; + + yield[ + [ + '/\d+/', + '/^[a-z]{4}$/', + ], + 'Lorem ipsum dolor sit', + false, + ]; + + yield[ + '/\w+/', + 'Lorem ipsum dolor sit', + true, + ]; + + yield[ + [ + '/[a-zA-Z ]+/', + '/\w+/', + ], + 'Lorem ipsum dolor sit', + true, + ]; + } + + /** + * Provides empty non money-related value + * + * @return Generator + */ + public function provideEmptyNonMoneyValue() + { + yield['']; + yield[' ']; + yield[null]; + yield[false]; + yield[[]]; + } + + /** + * Provides money-related value and information if the value is valid + * + * @return Generator + */ + public function provideMoneyValue() + { + yield[ + 'abc', + false, + ]; + + yield[ + '-a.b', + false, + ]; + + yield[ + 'a,b', + false, + ]; + + yield[ + 0, + true, + ]; + + yield[ + 1, + true, + ]; + + yield[ + -1, + true, + ]; + + yield[ + 1.2, + true, + ]; + + yield[ + 1.202, + true, + ]; + + yield[ + -1.202, + true, + ]; + + yield[ + '0', + true, + ]; + + yield[ + '1', + true, + ]; + + yield[ + '-1', + true, + ]; + + yield[ + '1.2', + true, + ]; + + yield[ + '1.202', + true, + ]; + + yield[ + '-1.202', + true, + ]; + + yield[ + '1,202', + true, + ]; + + yield[ + '-1,2', + true, + ]; + + yield[ + '-1,202', + true, + ]; + } + + /** + * Provides value of color with incorrect length + * + * @return Generator + */ + public function provideColorIncorrectLength() + { + yield[ + '12', + ]; + + yield[ + '1234', + ]; + + yield[ + '12345678', + ]; + + yield[ + '#12', + ]; + + yield[ + '#1234', + ]; + + yield[ + '#12345678', + ]; + } + + /** + * Provides invalid value of color + * + * @return Generator + */ + public function provideColorInvalidValue() + { + yield[ + '#qwerty', + ]; + + yield[ + 'qwerty', + ]; + } + + /** + * Provides empty non color-related value + * + * @return Generator + */ + public function provideColorEmptyValue() + { + yield[ + '', + ]; + + yield[ + 0, + ]; + + yield[ + '0', + ]; + + yield[ + false, + ]; + } + + /** + * Provides value of color + * + * @return Generator + */ + public function provideColor() + { + yield[ + '#1b0', + '11bb00', + ]; + + yield[ + '#1B0', + '11bb00', + ]; + + yield[ + '#1ab1ab', + '1ab1ab', + ]; + + yield[ + '#1AB1AB', + '1ab1ab', + ]; + + yield[ + '#000', + '000000', + ]; + } + /** * {@inheritdoc} */ From ddbff1b5578f729049066aaab776fccb26777615 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 2 Apr 2018 22:46:02 +0200 Subject: [PATCH 22/70] Update PHPDoc and comments --- src/Traits/Test/Base/BaseTestCaseTrait.php | 3 +++ src/Utilities/Arrays.php | 12 +++++++++ src/Utilities/Bundle.php | 2 +- src/Utilities/Miscellaneous.php | 5 ++++ src/Utilities/Reflection.php | 29 ++++++++++++++++++++++ src/Utilities/Regex.php | 4 +++ tests/Utilities/RegexTest.php | 4 +++ 7 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 2f0ae16..a175bbe 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -159,6 +159,7 @@ trait BaseTestCaseTrait * @param int $requiredArgumentsCount (optional) Expected count/amount of required arguments * of the verified method * @throws UnknownOopVisibilityTypeException + * @throws ReflectionException * * Attention. 2nd argument, the $method, may be: * - string - name of the method @@ -215,6 +216,7 @@ trait BaseTestCaseTrait * @param int $argumentsCount (optional) Expected count/amount of arguments of the verified method * @param int $requiredArgumentsCount (optional) Expected count/amount of required arguments of the verified * method + * @throws ReflectionException * @throws UnknownOopVisibilityTypeException */ protected static function assertConstructorVisibilityAndArguments( @@ -236,6 +238,7 @@ trait BaseTestCaseTrait * Asserts that class with given namespace has no constructor * * @param string $classNamespace Namespace of class that contains constructor to verify + * @throws ReflectionException */ protected static function assertHasNoConstructor($classNamespace) { diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index bdfe20b..c01a9d8 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -530,6 +530,10 @@ class Arrays */ public static function removeElement(array $array, $item) { + /* + * No elements or the element does not exist? + * Nothing to do + */ if (empty($array) || !in_array($item, $array)) { return false; } @@ -626,6 +630,10 @@ class Arrays */ public static function setKeysAsValues(array $array, $ignoreDuplicatedValues = true) { + /* + * No elements? + * Nothing to do + */ if (empty($array)) { return []; } @@ -1083,6 +1091,10 @@ class Arrays */ public static function getAllValuesOfKey(array $array, $key) { + /* + * No elements? + * Nothing to do + */ if (empty($array)) { return null; } diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index d2ffbca..af79c27 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -23,7 +23,7 @@ class Bundle * * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" - * @param string $extension (optional) Extension of the view / template + * @param string $extension (optional) Extension of the view / template (default: "html.twig") * @return string|null * * @throws IncorrectBundleNameException diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 9fc924b..7aa731e 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -9,6 +9,8 @@ namespace Meritoo\Common\Utilities; use Gedmo\Sluggable\Util\Urlizer; +use Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException; +use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; use Symfony\Component\HttpFoundation\Cookie; use Transliterator; @@ -1433,6 +1435,9 @@ class Miscellaneous * * @param string $color Hexadecimal value of color to invert (with or without hash), e.g. "dd244c" or "#22a5fe" * @return string + * + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException */ public static function getInvertedColor($color) { diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 23ecd58..849a879 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -35,6 +35,8 @@ class Reflection * @param bool $withoutInheritance (optional) If is set to true, only methods for given class are returned. * Otherwise - all methods, with inherited methods too. * @return array + * + * @throws ReflectionException */ public static function getMethods($class, $withoutInheritance = false) { @@ -65,6 +67,8 @@ class Reflection * * @param object|string $class The object or name of object's class * @return array + * + * @throws ReflectionException */ public static function getConstants($class) { @@ -79,6 +83,8 @@ class Reflection * * @param object|string $class The object or name of object's class * @return int|null + * + * @throws ReflectionException */ public static function getMaxNumberConstant($class) { @@ -105,6 +111,8 @@ class Reflection * @param object|string $class The object or name of object's class * @param string $method Name of the method to find * @return bool + * + * @throws ReflectionException */ public static function hasMethod($class, $method) { @@ -119,6 +127,8 @@ class Reflection * @param object|string $class The object or name of object's class * @param string $property Name of the property to find * @return bool + * + * @throws ReflectionException */ public static function hasProperty($class, $property) { @@ -133,6 +143,8 @@ class Reflection * @param object|string $class The object or name of object's class * @param string $constant Name of the constant to find * @return bool + * + * @throws ReflectionException */ public static function hasConstant($class, $constant) { @@ -147,6 +159,8 @@ class Reflection * @param object|string $class The object or name of object's class * @param string $constant Name of the constant that contains a value * @return mixed + * + * @throws ReflectionException */ public static function getConstantValue($class, $constant) { @@ -169,6 +183,8 @@ class Reflection * @param bool $force (optional) If is set to true, try to retrieve value even if the object doesn't have * property. Otherwise - not. * @return mixed + * + * @throws ReflectionException */ public static function getPropertyValue($object, $property, $force = false) { @@ -285,6 +301,8 @@ class Reflection * @param bool $force (optional) If is set to true, try to retrieve value even if the * object does not have property. Otherwise - not. * @return array + * + * @throws ReflectionException */ public static function getPropertyValues($objects, $property, $force = false) { @@ -444,6 +462,8 @@ class Reflection * @param bool $includeParents (optional) If is set to true, properties of parent classes are * included (recursively). Otherwise - not. * @return array|ReflectionProperty + * + * @throws ReflectionException */ public static function getProperties($source, $filter = null, $includeParents = false) { @@ -477,6 +497,8 @@ class Reflection * * @param array|object|string $source An array of objects, namespaces, object or namespace * @return ReflectionClass|bool + * + * @throws ReflectionException */ public static function getParentClass($source) { @@ -549,6 +571,7 @@ class Reflection * namespaces, object or namespace. * @return mixed * + * @throws CannotResolveClassNameException * @throws MissingChildClassesException * @throws TooManyChildClassesException */ @@ -583,6 +606,8 @@ class Reflection * @param int $filter (optional) Filter of properties. Uses ReflectionProperty class constants. * By default all properties are allowed / processed. * @return null|ReflectionProperty + * + * @throws ReflectionException */ public static function getProperty($class, $property, $filter = null) { @@ -609,7 +634,9 @@ class Reflection * @param bool $verifyParents If is set to true, parent classes are verified if they use given * trait. Otherwise - not. * @return bool|null + * * @throws CannotResolveClassNameException + * @throws ReflectionException */ public static function usesTrait($class, $trait, $verifyParents = false) { @@ -652,6 +679,8 @@ class Reflection * * @param array|object|string $class An array of objects, namespaces, object or namespace * @return string|null + * + * @throws ReflectionException */ public static function getParentClassName($class) { diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index cc39b19..f281746 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -730,6 +730,10 @@ class Regex */ public static function isValidMoneyValue($value) { + /* + * Not a scalar value? + * Nothing to do + */ if (!is_scalar($value)) { return false; } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index db3c2b9..377bd7e 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -12,6 +12,7 @@ use Generator; use Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException; use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; use Meritoo\Common\Test\Base\BaseTestCase; +use ReflectionException; /** * Test case of the useful regular expressions methods @@ -24,6 +25,9 @@ class RegexTest extends BaseTestCase private $simpleText; private $camelCaseText; + /** + * @throws ReflectionException + */ public function testConstructor() { static::assertHasNoConstructor(Regex::class); From f111174ed284f9e18f4c12c0fe7d233d7f7ecaef Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 08:22:10 +0200 Subject: [PATCH 23/70] Tests - increase code coverage --- tests/Utilities/RegexTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index 377bd7e..9e3fc6f 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -152,6 +152,10 @@ class RegexTest extends BaseTestCase { $string = 'Lorem ipsum dolor sit amet'; + $beginning = ''; + self::assertFalse(Regex::startsWith($string, $beginning)); + self::assertFalse(Regex::startsWith('', $string)); + $beginning = 'Lor'; self::assertTrue(Regex::startsWith($string, $beginning)); @@ -247,6 +251,9 @@ class RegexTest extends BaseTestCase { self::assertTrue(Regex::contains($this->simpleText, 'ipsum')); self::assertFalse(Regex::contains($this->simpleText, 'neque')); + + self::assertFalse(Regex::contains($this->simpleText, '.')); + self::assertTrue(Regex::contains($this->simpleText, 'l')); } public function testIsFileName() @@ -457,6 +464,18 @@ class RegexTest extends BaseTestCase self::assertEquals($expected, Regex::getArrayValuesByPattern($pattern, $dataArray, true)); } + public static function testGetUrlPatternWithProtocolRequired() + { + $pattern = '/^([a-z]+:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i'; + self::assertEquals($pattern, Regex::getUrlPattern(true)); + } + + public static function testGetUrlPatternWithoutProtocol() + { + $pattern = '/^([a-z]+:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i'; + self::assertEquals($pattern, Regex::getUrlPattern()); + } + /** * @param array $array The array that should be filtered * @param string $arrayColumnKey Column name From 5578b051a75c77d456ab9f99cec4bc2a02de2759 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 08:26:51 +0200 Subject: [PATCH 24/70] Update PHPDoc and comments --- src/Utilities/Date.php | 8 +++++++ src/Utilities/QueryBuilderUtility.php | 6 +++-- src/Utilities/Regex.php | 32 +++++++++++++++++++++++++++ src/Utilities/Repository.php | 11 +++++++-- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 827e973..c19c530 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -10,6 +10,7 @@ namespace Meritoo\Common\Utilities; use DateInterval; use DateTime; +use Exception; use Meritoo\Common\Exception\Date\UnknownDatePartTypeException; use Meritoo\Common\Type\DatePartType; use Meritoo\Common\Type\DatePeriod; @@ -68,6 +69,8 @@ class Date * * @param int $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. * @return null|DatePeriod + * + * @throws Exception */ public static function getDatesForPeriod($period) { @@ -219,6 +222,7 @@ class Date * Returns current day of week * * @return int + * @throws UnknownDatePartTypeException */ public static function getCurrentDayOfWeek() { @@ -485,6 +489,8 @@ class Date * placeholder which is replaced with a number that represents each iteration. * Default: interval for days. * @return array + * + * @throws Exception */ public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD') { @@ -530,6 +536,8 @@ class Date * @param string $intervalTemplate (optional) Template used to build date interval. The placeholder is replaced * with next, iterated value. * @return DateTime + * + * @throws Exception */ public static function getRandomDate(DateTime $startDate = null, $start = 1, $end = 100, $intervalTemplate = 'P%sD') { diff --git a/src/Utilities/QueryBuilderUtility.php b/src/Utilities/QueryBuilderUtility.php index 294879d..037a9bd 100644 --- a/src/Utilities/QueryBuilderUtility.php +++ b/src/Utilities/QueryBuilderUtility.php @@ -10,6 +10,7 @@ namespace Meritoo\Common\Utilities; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Parameter; use Doctrine\ORM\QueryBuilder; @@ -155,9 +156,10 @@ class QueryBuilderUtility * * @param EntityManager $entityManager The entity manager * @param array|ArrayCollection $entities The entities to delete - * @param bool $flushDeleted (optional) If is set to true, flushes the deleted objects. - * Otherwise - not. + * @param bool $flushDeleted (optional) If is set to true, flushes the deleted objects (default + * behaviour). Otherwise - not. * @return bool + * @throws OptimisticLockException */ public static function deleteEntities(EntityManager $entityManager, $entities, $flushDeleted = true) { diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index f281746..638552e 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -59,6 +59,10 @@ class Regex */ public static function isValidEmail($email) { + /* + * Not a string? + * Nothing to do + */ if (!is_string($email)) { return false; } @@ -141,6 +145,14 @@ class Regex */ public static function isValidUrl($url, $requireProtocol = false) { + /* + * Not a string? + * Nothing to do + */ + if (!is_string($url)) { + return false; + } + $pattern = self::getUrlPattern($requireProtocol); return (bool)preg_match($pattern, $url); @@ -154,6 +166,10 @@ class Regex */ public static function isValidPhoneNumber($phoneNumber) { + /* + * Not a string? + * Nothing to do + */ if (!is_string($phoneNumber)) { return false; } @@ -814,6 +830,10 @@ class Regex */ public static function isValidBundleName($bundleName) { + /* + * Not a string? + * Nothing to do + */ if (!is_string($bundleName)) { return false; } @@ -851,6 +871,10 @@ class Regex */ public static function isValidHtmlAttribute($htmlAttribute) { + /* + * Not a string? + * Nothing to do + */ if (!is_string($htmlAttribute)) { return false; } @@ -868,6 +892,10 @@ class Regex */ public static function areValidHtmlAttributes($htmlAttributes) { + /* + * Not a string? + * Nothing to do + */ if (!is_string($htmlAttributes)) { return false; } @@ -885,6 +913,10 @@ class Regex */ public static function isBinaryValue($value) { + /* + * Not a string? + * Nothing to do + */ if (!is_string($value)) { return false; } diff --git a/src/Utilities/Repository.php b/src/Utilities/Repository.php index 94a9737..65c07a9 100644 --- a/src/Utilities/Repository.php +++ b/src/Utilities/Repository.php @@ -10,6 +10,7 @@ namespace Meritoo\Common\Utilities; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; +use ReflectionException; /** * Useful methods for repository @@ -23,9 +24,13 @@ class Repository * Replenishes positions of given items * * @param array $items The items - * @param bool $asLast (optional) If is set to true, items are placed at the end. Otherwise - at the top. + * @param bool $asLast (optional) If is set to true, items are placed at the end (default behaviour). Otherwise + * - at top. * @param bool $force (optional) If is set to true, positions are set even there is no extreme position. - * Otherwise - if extreme position is not found (is null) replenishment is stopped / skipped. + * Otherwise - if extreme position is not found (is null) replenishment is stopped / skipped + * (default behaviour). + * + * @throws ReflectionException */ public static function replenishPositions($items, $asLast = true, $force = false) { @@ -60,6 +65,8 @@ class Repository * @param array $items The items * @param bool $max (optional) If is set to true, maximum value is returned. Otherwise - minimum. * @return int + * + * @throws ReflectionException */ public static function getExtremePosition($items, $max = true) { From aae7609c8c08a201b939c67e86981abe99feaa1d Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 16:55:12 +0200 Subject: [PATCH 25/70] TravisCI - install locales before running tests --- .travis.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5cc2936..8774112 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,18 @@ php: - 7.0 - 7.1 +before_install: + - sudo apt-get install locales + - sed -i 's/^# de_DE/de_DE/g; \ + s/^# es_ES/es_ES/g; \ + s/^# en_GB/en_GB/g; \ + s/^# en_US/en_US/g; \ + s/^# fr_FR/fr_FR/g; \ + s/^# it_IT/it_IT/g; \ + s/^# pl_PL/pl_PL/g; \ + s/^# ru_RU/ru_RU/g;' /etc/locale.gen \ + && locale-gen + install: - composer install From 129b75ea939bb1ab9f6a2ebff49dd33bdef2d1f7 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 16:58:32 +0200 Subject: [PATCH 26/70] Revert "TravisCI - install locales before running tests" This reverts commit aae7609 --- .travis.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8774112..5cc2936 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,18 +5,6 @@ php: - 7.0 - 7.1 -before_install: - - sudo apt-get install locales - - sed -i 's/^# de_DE/de_DE/g; \ - s/^# es_ES/es_ES/g; \ - s/^# en_GB/en_GB/g; \ - s/^# en_US/en_US/g; \ - s/^# fr_FR/fr_FR/g; \ - s/^# it_IT/it_IT/g; \ - s/^# pl_PL/pl_PL/g; \ - s/^# ru_RU/ru_RU/g;' /etc/locale.gen \ - && locale-gen - install: - composer install From 1cbc87222f003b9125078e8010190d30a0e47f35 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 16:58:54 +0200 Subject: [PATCH 27/70] TravisCI - install locales before running tests --- .travis.yml | 4 ++++ tests/Utilities/LocaleTest.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5cc2936..8e70f7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,10 @@ php: - 7.0 - 7.1 +before_install: + - sudo apt-get install locales + - sed -i 's/^# de_DE/de_DE/g; s/^# es_ES/es_ES/g; s/^# en_GB/en_GB/g; s/^# en_US/en_US/g; s/^# fr_FR/fr_FR/g; s/^# it_IT/it_IT/g; s/^# pl_PL/pl_PL/g; s/^# ru_RU/ru_RU/g;' /etc/locale.gen && locale-gen + install: - composer install diff --git a/tests/Utilities/LocaleTest.php b/tests/Utilities/LocaleTest.php index b695469..4f84cc1 100644 --- a/tests/Utilities/LocaleTest.php +++ b/tests/Utilities/LocaleTest.php @@ -11,6 +11,7 @@ namespace Meritoo\Common\Test\Utilities; use Generator; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Locale; +use ReflectionException; /** * Test case of the useful locale methods @@ -20,6 +21,9 @@ use Meritoo\Common\Utilities\Locale; */ class LocaleTest extends BaseTestCase { + /** + * @throws ReflectionException + */ public function testConstructor() { static::assertHasNoConstructor(Locale::class); From 499c603d545f48e6ad9933e718524a0ba059712a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 17:04:43 +0200 Subject: [PATCH 28/70] TravisCI - install locales before running tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8e70f7f..b87bd4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ php: before_install: - sudo apt-get install locales - - sed -i 's/^# de_DE/de_DE/g; s/^# es_ES/es_ES/g; s/^# en_GB/en_GB/g; s/^# en_US/en_US/g; s/^# fr_FR/fr_FR/g; s/^# it_IT/it_IT/g; s/^# pl_PL/pl_PL/g; s/^# ru_RU/ru_RU/g;' /etc/locale.gen && locale-gen + - sudo sed -i 's/^# de_DE/de_DE/g; s/^# es_ES/es_ES/g; s/^# en_GB/en_GB/g; s/^# en_US/en_US/g; s/^# fr_FR/fr_FR/g; s/^# it_IT/it_IT/g; s/^# pl_PL/pl_PL/g; s/^# ru_RU/ru_RU/g;' /etc/locale.gen && locale-gen install: - composer install From 180a8b8b5d3408a27d755ec35f2cd0358ab7a53b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 17:10:40 +0200 Subject: [PATCH 29/70] TravisCI - install locales before running tests --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b87bd4d..fb81446 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,15 @@ php: before_install: - sudo apt-get install locales - - sudo sed -i 's/^# de_DE/de_DE/g; s/^# es_ES/es_ES/g; s/^# en_GB/en_GB/g; s/^# en_US/en_US/g; s/^# fr_FR/fr_FR/g; s/^# it_IT/it_IT/g; s/^# pl_PL/pl_PL/g; s/^# ru_RU/ru_RU/g;' /etc/locale.gen && locale-gen + - sudo sed -i 's/^# de_DE/de_DE/g;' /etc/locale.gen + - sudo sed -i 's/^# es_ES/es_ES/g;' /etc/locale.gen + - sudo sed -i 's/^# en_GB/en_GB/g;' /etc/locale.gen + - sudo sed -i 's/^# en_US/en_US/g;' /etc/locale.gen + - sudo sed -i 's/^# fr_FR/fr_FR/g;' /etc/locale.gen + - sudo sed -i 's/^# it_IT/it_IT/g;' /etc/locale.gen + - sudo sed -i 's/^# pl_PL/pl_PL/g;' /etc/locale.gen + - sudo sed -i 's/^# ru_RU/ru_RU/g;' /etc/locale.gen + - sudo locale-gen install: - composer install From 122ff41dadebfc32c0d6457bd584e2c7b4924545 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 19:13:38 +0200 Subject: [PATCH 30/70] TravisCI - install locales before running tests --- .travis.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index fb81446..02ed4ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,15 +7,7 @@ php: before_install: - sudo apt-get install locales - - sudo sed -i 's/^# de_DE/de_DE/g;' /etc/locale.gen - - sudo sed -i 's/^# es_ES/es_ES/g;' /etc/locale.gen - - sudo sed -i 's/^# en_GB/en_GB/g;' /etc/locale.gen - - sudo sed -i 's/^# en_US/en_US/g;' /etc/locale.gen - - sudo sed -i 's/^# fr_FR/fr_FR/g;' /etc/locale.gen - - sudo sed -i 's/^# it_IT/it_IT/g;' /etc/locale.gen - - sudo sed -i 's/^# pl_PL/pl_PL/g;' /etc/locale.gen - - sudo sed -i 's/^# ru_RU/ru_RU/g;' /etc/locale.gen - - sudo locale-gen + - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 install: - composer install From 834c12f280c4908136fd56153795e6388445df0e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Tue, 3 Apr 2018 22:57:41 +0200 Subject: [PATCH 31/70] TravisCI - install locales before running tests - remove unnecessary command --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 02ed4ae..ada4db8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,6 @@ php: - 7.1 before_install: - - sudo apt-get install locales - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 install: From ec2f3c6eadd12d2fa2a1e2ae09b3cfa2221d149a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 4 Apr 2018 08:57:08 +0200 Subject: [PATCH 32/70] TravisCI - fix "No output has been received in the last 10m0s" bug (build times out because no output was received) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ada4db8..70a4eb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ before_install: - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 install: - - composer install + - travis_wait composer install script: - php ./vendor/bin/phpunit From ec2b5742ecaca294d7b59083cf0ddbd0c504a121 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 4 Apr 2018 21:16:36 +0200 Subject: [PATCH 33/70] Revert "TravisCI - fix "No output has been received in the last 10m0s" bug (build times out because no output was received)" This reverts commit ec2f3c6 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 70a4eb9..ada4db8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ before_install: - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 install: - - travis_wait composer install + - composer install script: - php ./vendor/bin/phpunit From bedb6333b993f9e564c3d73eec9917913be33c2a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 4 Apr 2018 21:21:51 +0200 Subject: [PATCH 34/70] TravisCI > "composer install" command > increase verbosity to maximum --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ada4db8..56e37e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ before_install: - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 install: - - composer install + - composer install -vvv script: - php ./vendor/bin/phpunit From 26c63ecb5c18e56bf9b2204ee9f37611230e4f03 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 4 Apr 2018 21:40:44 +0200 Subject: [PATCH 35/70] TravisCI > composer > install hirak/prestissimo package globally --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 56e37e3..ebf0aac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ php: before_install: - sudo locale-gen de_DE.UTF-8 es_ES.UTF-8 en_GB.UTF-8 en_US.UTF-8 fr_FR.UTF-8 it_IT.UTF-8 pl_PL.UTF-8 ru_RU.UTF-8 + - composer global require hirak/prestissimo install: - composer install -vvv From 6fd18111b4d07612ce4841b932ff6bae352eb37d Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 4 Apr 2018 21:54:45 +0200 Subject: [PATCH 36/70] TravisCI - fix "No output has been received in the last 10m0s" bug (build times out because no output was received) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ebf0aac..c710f3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - composer global require hirak/prestissimo install: - - composer install -vvv + - travis_wait 30 composer install -vvv script: - php ./vendor/bin/phpunit From 132a0a00e7b3cd156e39c33ed55ac97c1f70682b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 4 May 2018 12:53:45 +0200 Subject: [PATCH 37/70] Docker > Dockerfile > fix bug "pecl/xdebug requires PHP (version >= 7.0.0), installed version is 5.5.38" --- .docker/config/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docker/config/Dockerfile b/.docker/config/Dockerfile index 2d8e5a0..abd0209 100644 --- a/.docker/config/Dockerfile +++ b/.docker/config/Dockerfile @@ -50,7 +50,7 @@ RUN docker-php-ext-install \ # - Xdebug # RUN pecl install \ - xdebug \ + xdebug-2.5.5 \ && docker-php-ext-enable \ xdebug From 5be449a83d99574112a14cb73a1ad018729e6df2 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 6 May 2018 14:40:17 +0200 Subject: [PATCH 38/70] Docker > Dockerfile > fix bug when error messages are displayed in french instead of english language (example: "chmod(): Aucun fichier ou dossier de ce type") --- .docker/config/Dockerfile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.docker/config/Dockerfile b/.docker/config/Dockerfile index abd0209..2b15489 100644 --- a/.docker/config/Dockerfile +++ b/.docker/config/Dockerfile @@ -38,6 +38,14 @@ RUN sed -i 's/^# de_DE/de_DE/g; \ s/^# ru_RU/ru_RU/g;' /etc/locale.gen \ && locale-gen +# +# Set default language +# +# Required to avoid problem with using strange language by error messages. +# Example: "chmod(): Aucun fichier ou dossier de ce type" +# +ENV LANGUAGE=en_US.UTF-8 + # # PHP extensions # @@ -65,7 +73,7 @@ COPY php.ini /usr/local/etc/php/php.ini ARG TIMEZONE RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \ && echo ${TIMEZONE} > /etc/timezone \ - && printf '[PHP]\ndate.timezone = "%s"\n', ${TIMEZONE} > /usr/local/etc/php/conf.d/tzone.ini \ + && printf '[PHP]\ndate.timezone = "%s"\n' ${TIMEZONE} > /usr/local/etc/php/conf.d/tzone.ini \ && "date" #RUN echo "\n""date.timezone = $TIMEZONE""\n" >> /usr/local/etc/php/php.ini From 96bdb6eb605fd76bed902e29c6300aa7472f68d5 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 6 May 2018 14:41:13 +0200 Subject: [PATCH 39/70] Improve coding standard --- src/Utilities/Miscellaneous.php | 25 +++++++++++----- tests/Utilities/MiscellaneousTest.php | 42 ++++++++++++++++++--------- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 7aa731e..9014bcd 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -628,10 +628,10 @@ class Miscellaneous * Breaks long text * * @param string $text The text to check and break - * @param int $perLine (optional) Characters count per line - * @param string $separator (optional) Separator that is placed beetwen lines - * @param string $encoding (optional) Character encoding. Used by mb_substr(). - * @param int $proportionalAberration (optional) Proportional aberration for chars (percent value) + * @param int $perLine (optional) Characters count per line. Default: 100. + * @param string $separator (optional) Separator that is placed between lines. Default: "
". + * @param string $encoding (optional) Character encoding. Used by mb_substr(). Default: "UTF-8". + * @param int $proportionalAberration (optional) Proportional aberration for chars (percent value). Default: 20. * @return string */ public static function breakLongText( @@ -718,15 +718,23 @@ class Miscellaneous * * @param string $directoryPath Directory path * @param bool $contentOnly (optional) If is set to true, only content of the directory is removed, not - * directory. Otherwise - directory is removed too. - * @return bool + * directory itself. Otherwise - directory is removed too (default behaviour). + * @return bool|null */ public static function removeDirectory($directoryPath, $contentOnly = false) { + /* + * Directory does not exist? + * Nothing to do + */ if (!file_exists($directoryPath)) { - return true; + return null; } + /* + * It's not a directory? + * Let's treat it like file + */ if (!is_dir($directoryPath)) { return unlink($directoryPath); } @@ -741,6 +749,9 @@ class Miscellaneous } } + /* + * Directory should be removed too? + */ if (!$contentOnly) { return rmdir($directoryPath); } diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 90cb155..967a879 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -14,6 +14,7 @@ use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Locale; use Meritoo\Common\Utilities\Miscellaneous; +use ReflectionException; use stdClass; /** @@ -28,6 +29,9 @@ class MiscellaneousTest extends BaseTestCase private $stringCommaSeparated; private $stringDotSeparated; + /** + * @throws ReflectionException + */ public function testConstructor() { static::assertHasNoConstructor(Miscellaneous::class); @@ -363,35 +367,33 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals('Lorem ipsum dolor sit---amet, consectetur---adipiscing---elit', Miscellaneous::breakLongText($this->stringCommaSeparated, 20, '---')); } - public function testRemoveDirectory() + public function testRemoveDirectoryUsingNotExistingDirectory() { - /* - * Removing not existing directory - */ - self::assertTrue(Miscellaneous::removeDirectory('/abc/def/ghi')); + self::assertNull(Miscellaneous::removeDirectory('/abc/def/ghi')); + } - /* - * Removing not directory - */ + public function testRemoveDirectoryUsingNoDirectory() + { $directoryPath = sys_get_temp_dir() . '/ipsum.txt'; touch($directoryPath); self::assertTrue(Miscellaneous::removeDirectory($directoryPath)); + } - /* - * Removing simple directory - */ + public function testRemoveDirectoryUsingSimpleDirectory() + { $directoryPath = sys_get_temp_dir() . '/lorem/ipsum'; mkdir($directoryPath, 0777, true); self::assertTrue(Miscellaneous::removeDirectory($directoryPath)); + } - /* - * Removing more complex directory - */ + public function testRemoveDirectoryUsingComplexDirectory() + { $directory1Path = sys_get_temp_dir() . '/lorem/ipsum'; $directory2Path = sys_get_temp_dir() . '/lorem/dolor/sit'; mkdir($directory1Path, 0777, true); mkdir($directory2Path, 0777, true); + self::assertTrue(Miscellaneous::removeDirectory(sys_get_temp_dir() . '/lorem', false)); } @@ -661,6 +663,10 @@ class MiscellaneousTest extends BaseTestCase self::assertEquals(255, Miscellaneous::getValidColorComponent(255, false)); } + /** + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + */ public function testGetInvertedColorWithIncorrectLength() { $this->setExpectedException(IncorrectColorHexLengthException::class); @@ -675,6 +681,10 @@ class MiscellaneousTest extends BaseTestCase Miscellaneous::getInvertedColor('1234567'); } + /** + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + */ public function testGetInvertedColorWithInvalidValue() { $this->setExpectedException(InvalidColorHexValueException::class); @@ -686,6 +696,10 @@ class MiscellaneousTest extends BaseTestCase Miscellaneous::getInvertedColor('00ppqq'); } + /** + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + */ public function testGetInvertedColor() { /* From 52e74c8b489c0c14c86ead35c8528e44b5eed4d3 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sun, 6 May 2018 17:22:45 +0200 Subject: [PATCH 40/70] Tests > increase code coverage --- src/Utilities/Miscellaneous.php | 174 ++++++++++++++------------ tests/Utilities/MiscellaneousTest.php | 43 +++++++ 2 files changed, 134 insertions(+), 83 deletions(-) diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 9014bcd..2146a29 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -1229,104 +1229,112 @@ class Miscellaneous * to "true". To read exact length of HTTP headers from CURL you can use "curl_getinfo()" function * and read "CURLINFO_HEADER_SIZE" option. * - * @param string $response the full content of response, including HTTP headers - * @param int $headerSize The length of HTTP headers in content + * @param string $response Full content of response, including HTTP headers + * @param int $headerSize Length of HTTP headers in content * @return array */ public static function getCurlResponseWithHeaders($response, $headerSize) { - $headerContent = mb_substr($response, 0, $headerSize); - $content = mb_substr($response, $headerSize); $headers = []; $cookies = []; + $headerContent = ''; + $content = ''; + + if (0 < $headerSize) { + $headerContent = mb_substr($response, 0, $headerSize); + $content = mb_substr($response, $headerSize); + } + /* * Let's transform headers content into two arrays: headers and cookies */ - foreach (explode("\r\n", $headerContent) as $i => $line) { - /* - * First line is only HTTP status and is unneeded so skip it - */ - if (0 === $i) { - continue; - } - - if (Regex::contains($line, ':')) { - list($key, $value) = explode(': ', $line); - + if (!empty($headerContent)) { + foreach (explode("\r\n", $headerContent) as $i => $line) { /* - * If the header is a "set-cookie" let's save it to "cookies" array + * First line is only HTTP status and is unneeded so skip it */ - if ('Set-Cookie' === $key) { - $cookieParameters = explode(';', $value); - - $name = ''; - $value = ''; - $expire = 0; - $path = '/'; - $domain = null; - $secure = false; - $httpOnly = true; - - foreach ($cookieParameters as $j => $parameter) { - $param = explode('=', $parameter); - - /* - * First parameter will be always a cookie name and it's value. It is not needed to run - * further actions for them, so save the values and move to next parameter. - */ - if (0 === $j) { - $name = trim($param[0]); - $value = trim($param[1]); - continue; - } - - /* - * Now there would be the rest of cookie parameters, names of params are sent different way so - * I need to lowercase the names and remove unneeded spaces. - */ - $paramName = mb_strtolower(trim($param[0])); - $paramValue = true; - - /* - * Some parameters don't have value e.g. "secure", but the value for them if they're specified - * is "true". Otherwise - just read a value for parameter if exists. - */ - if (array_key_exists(1, $param)) { - $paramValue = trim($param[1]); - } - - switch ($paramName) { - case 'expires': - $expire = $paramValue; - break; - case 'path': - $path = $paramValue; - break; - case 'domain': - $domain = $paramValue; - break; - case 'secure': - $secure = $paramValue; - break; - case 'httponly': - $httpOnly = $paramValue; - break; - } - } - - /* - * Create new Cookie object and add it to "cookies" array. - * I must skip to next header as cookies shouldn't be saved in "headers" array. - */ - $cookies[] = new Cookie($name, $value, $expire, $path, $domain, $secure, $httpOnly); + if (0 === $i) { continue; } - /* - * Save response header which is not a cookie - */ - $headers[$key] = $value; + if (Regex::contains($line, ':')) { + list($key, $value) = explode(': ', $line); + + /* + * If the header is a "set-cookie" let's save it to "cookies" array + */ + if ('Set-Cookie' === $key) { + $cookieParameters = explode(';', $value); + + $name = ''; + $value = ''; + $expire = 0; + $path = '/'; + $domain = null; + $secure = false; + $httpOnly = true; + + foreach ($cookieParameters as $j => $parameter) { + $param = explode('=', $parameter); + + /* + * First parameter will be always a cookie name and it's value. It is not needed to run + * further actions for them, so save the values and move to next parameter. + */ + if (0 === $j) { + $name = trim($param[0]); + $value = trim($param[1]); + continue; + } + + /* + * Now there would be the rest of cookie parameters, names of params are sent different way so + * I need to lowercase the names and remove unneeded spaces. + */ + $paramName = mb_strtolower(trim($param[0])); + $paramValue = true; + + /* + * Some parameters don't have value e.g. "secure", but the value for them if they're specified + * is "true". Otherwise - just read a value for parameter if exists. + */ + if (array_key_exists(1, $param)) { + $paramValue = trim($param[1]); + } + + switch ($paramName) { + case 'expires': + $expire = $paramValue; + break; + case 'path': + $path = $paramValue; + break; + case 'domain': + $domain = $paramValue; + break; + case 'secure': + $secure = $paramValue; + break; + case 'httponly': + $httpOnly = $paramValue; + break; + } + } + + /* + * Create new Cookie object and add it to "cookies" array. + * I must skip to next header as cookies shouldn't be saved in "headers" array. + */ + $cookies[] = new Cookie($name, $value, $expire, $path, $domain, $secure, $httpOnly); + continue; + } + + /* + * Save response header which is not a cookie + */ + $headers[$key] = $value; + } } } diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 967a879..db3145d 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -28,6 +28,7 @@ class MiscellaneousTest extends BaseTestCase private $stringSmall; private $stringCommaSeparated; private $stringDotSeparated; + private $stringWithoutSpaces; /** * @throws ReflectionException @@ -365,6 +366,7 @@ class MiscellaneousTest extends BaseTestCase { self::assertEquals('Lorem ipsum dolor sit
amet, consectetur
adipiscing
elit', Miscellaneous::breakLongText($this->stringCommaSeparated, 20)); self::assertEquals('Lorem ipsum dolor sit---amet, consectetur---adipiscing---elit', Miscellaneous::breakLongText($this->stringCommaSeparated, 20, '---')); + self::assertEquals('LoremIpsum
DolorSitAm
etConsecte
turAdipisc
ingElit', Miscellaneous::breakLongText($this->stringWithoutSpaces, 10)); } public function testRemoveDirectoryUsingNotExistingDirectory() @@ -768,6 +770,21 @@ class MiscellaneousTest extends BaseTestCase self::assertNotEmpty(Miscellaneous::getProjectRootPath()); } + /** + * @param int $headerSize Length of HTTP headers in content + * @dataProvider provideHeaderSizeForEmptyCurlResponse + */ + public function testGetCurlResponseWithHeadersUsingEmptyResponse($headerSize) + { + $expected = [ + 'headers' => [], + 'cookies' => [], + 'content' => '', + ]; + + self::assertEquals($expected, Miscellaneous::getCurlResponseWithHeaders('', $headerSize)); + } + /** * Provides string to convert characters to latin characters and not lower cased and not human-readable * @@ -1178,6 +1195,30 @@ class MiscellaneousTest extends BaseTestCase ]; } + /** + * Provides length/size of HTTP headers for an empty response + * + * @return Generator + */ + public function provideHeaderSizeForEmptyCurlResponse() + { + yield[ + -10, + ]; + + yield[ + -1, + ]; + + yield[ + 0, + ]; + + yield[ + 10, + ]; + } + /** * {@inheritdoc} */ @@ -1188,6 +1229,7 @@ class MiscellaneousTest extends BaseTestCase $this->stringSmall = 'Lorem ipsum dolor sit amet.'; $this->stringCommaSeparated = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'; $this->stringDotSeparated = 'Etiam ullamcorper. Suspendisse a pellentesque dui, non felis.'; + $this->stringWithoutSpaces = 'LoremIpsumDolorSitAmetConsecteturAdipiscingElit'; } /** @@ -1200,5 +1242,6 @@ class MiscellaneousTest extends BaseTestCase unset($this->stringSmall); unset($this->stringCommaSeparated); unset($this->stringDotSeparated); + unset($this->stringWithoutSpaces); } } From 0eb5343df0686dd93eab8b1b2500a8e62dda734e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 28 May 2018 15:03:52 +0200 Subject: [PATCH 41/70] Docker > name of containers > use custom suffix Docker > the "composer" service --- .env.dist | 5 +++-- docker-compose.yml | 11 +++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.env.dist b/.env.dist index c613201..50e9ce0 100644 --- a/.env.dist +++ b/.env.dist @@ -1,11 +1,12 @@ # ----------------------------------------------------------------------------- -# Docker +### Docker # ----------------------------------------------------------------------------- # # All containers # -DOCKER_CONTAINER_PREFIX=__ENTER__CONTAINER__PREFIX__ +DOCKER_CONTAINER_OWNER=__ENTER__OWNER__NAME__ +DOCKER_CONTAINER_PROJECT=__ENTER__PROJECT__NAME__ # # PHP configuration: diff --git a/docker-compose.yml b/docker-compose.yml index 17c10e2..4dca04f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,8 +2,8 @@ version: '3' services: php-cli: - image: meritoo/common-library - container_name: ${DOCKER_CONTAINER_PREFIX} + image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php-cli + container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-php-cli working_dir: /project entrypoint: php command: -S 0.0.0.0:9999 @@ -13,3 +13,10 @@ services: - TIMEZONE=$TIMEZONE volumes: - .:/project + composer: + image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php-cli + container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-composer + working_dir: /project + command: composer + volumes: + - .:/project From bc54f734e2ee5b74f8bdd70ade2f5440d30d1544 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 28 May 2018 16:56:59 +0200 Subject: [PATCH 42/70] Phing > update properties.dist > remove unnecessary properties and disabled code --- .phing/properties.dist | 22 +------------- .phing/tests.xml | 65 ------------------------------------------ 2 files changed, 1 insertion(+), 86 deletions(-) diff --git a/.phing/properties.dist b/.phing/properties.dist index db05a3a..99977a9 100644 --- a/.phing/properties.dist +++ b/.phing/properties.dist @@ -102,27 +102,7 @@ dir.data.temporary = ${dir.data}/tmp # tests.database = ${dir.data.temporary}/database.sqlite -# -# Disabled, because unnecessary right now -# PHPUnit is installed and loaded by Composer -# -# Krzysztof Niziol -# 2017-02-22 -# -# Run PHPUnit using exec task instead of phpunitTask -#phpunit.useExec = false - -# -# Disabled, because unnecessary right now -# We want generate code coverage always -# -# Krzysztof Niziol -# 2017-02-22 -# -# Collect coverage data during tests -#phpunit.withCoverage = true - -# Path of the PHPUnit (https://phpunit.de) +# Path of the PHPUnit # phpUnit.path = ./vendor/bin/phpunit diff --git a/.phing/tests.xml b/.phing/tests.xml index 4567626..3482177 100644 --- a/.phing/tests.xml +++ b/.phing/tests.xml @@ -235,71 +235,6 @@ - - -
From c5b42017d2a78de66296e67dff9552c3ea0d9f3c Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 28 May 2018 17:03:19 +0200 Subject: [PATCH 43/70] Phing > tests > do not create database (for code coverage) --- .phing/properties.dist | 4 ---- .phing/tests.xml | 15 ++------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/.phing/properties.dist b/.phing/properties.dist index 99977a9..9ef38c9 100644 --- a/.phing/properties.dist +++ b/.phing/properties.dist @@ -98,10 +98,6 @@ dir.data.temporary = ${dir.data}/tmp # Testing # -------------------------------------------------------------------------------- -# Test database path -# -tests.database = ${dir.data.temporary}/database.sqlite - # Path of the PHPUnit # phpUnit.path = ./vendor/bin/phpunit diff --git a/.phing/tests.xml b/.phing/tests.xml index 3482177..7e53b15 100644 --- a/.phing/tests.xml +++ b/.phing/tests.xml @@ -213,7 +213,6 @@ - @@ -222,19 +221,9 @@ - - - - - - - - - - - - + From 7382bce842b3376624d8feb4249ebdf8d083519e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 28 May 2018 17:05:12 +0200 Subject: [PATCH 44/70] Phing > tests > do not verify if the "tests" directory exists --- .phing/properties.dist | 1 - .phing/tests.xml | 8 -------- 2 files changed, 9 deletions(-) diff --git a/.phing/properties.dist b/.phing/properties.dist index 9ef38c9..b515716 100644 --- a/.phing/properties.dist +++ b/.phing/properties.dist @@ -91,7 +91,6 @@ dir.reports.coverage = ${dir.reports}/phpunit_coverage # Data directories # -------------------------------------------------------------------------------- -dir.data.tests = ${dir.data}/tests dir.data.temporary = ${dir.data}/tmp # -------------------------------------------------------------------------------- diff --git a/.phing/tests.xml b/.phing/tests.xml index 7e53b15..5cdd1da 100644 --- a/.phing/tests.xml +++ b/.phing/tests.xml @@ -213,14 +213,6 @@ - - - - - - - - From 233473d9156a6791dc63df4168b1d08363d0586b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 28 May 2018 17:42:15 +0200 Subject: [PATCH 45/70] Tests > implement Codeception (instead of PHPUnit) --- .gitignore | 12 --------- .phing/properties.dist | 5 ++-- .phing/tests.xml | 8 +++--- codeception.yml | 22 ++++++++++++++++ composer.json | 2 +- phpunit.xml.dist | 54 ---------------------------------------- tests/_output/.gitignore | 2 ++ tests/_support/.gitkeep | 0 8 files changed, 30 insertions(+), 75 deletions(-) create mode 100644 codeception.yml delete mode 100644 phpunit.xml.dist create mode 100644 tests/_output/.gitignore create mode 100644 tests/_support/.gitkeep diff --git a/.gitignore b/.gitignore index 735ca31..bc4fe0a 100644 --- a/.gitignore +++ b/.gitignore @@ -23,24 +23,12 @@ /.phing/properties -# ---------------------------------------------------------------------------------------------------------------------- -### PHPUnit -# ---------------------------------------------------------------------------------------------------------------------- -/phpunit.xml - - # ---------------------------------------------------------------------------------------------------------------------- ### PHP Coding Standards Fixer generated files # ---------------------------------------------------------------------------------------------------------------------- /.php_cs.cache -# ---------------------------------------------------------------------------------------------------------------------- -### Build files -# ---------------------------------------------------------------------------------------------------------------------- -/.build/ - - # ---------------------------------------------------------------------------------------------------------------------- ### Generated databases # ---------------------------------------------------------------------------------------------------------------------- diff --git a/.phing/properties.dist b/.phing/properties.dist index b515716..e939825 100644 --- a/.phing/properties.dist +++ b/.phing/properties.dist @@ -76,7 +76,6 @@ dir.tests = ${project.basedir}/tests dir.build = ${project.basedir}/.build dir.reports = ${dir.build}/logs dir.reports.pdepend = ${dir.reports}/pdepend -dir.reports.coverage = ${dir.reports}/phpunit_coverage # # Disabled, because unnecessary right now # phpdocumentor/phpdocumentor cannot be installed via Composer @@ -97,9 +96,9 @@ dir.data.temporary = ${dir.data}/tmp # Testing # -------------------------------------------------------------------------------- -# Path of the PHPUnit +# Path of the framework used to run unit tests # -phpUnit.path = ./vendor/bin/phpunit +tests_framework.path = ./vendor/bin/codecept # Path of the PHP Coding Standards Fixer (http://cs.sensiolabs.org) # diff --git a/.phing/tests.xml b/.phing/tests.xml index 5cdd1da..243cb2e 100644 --- a/.phing/tests.xml +++ b/.phing/tests.xml @@ -87,7 +87,7 @@ @@ -103,7 +103,6 @@ - @@ -212,10 +211,9 @@ - + - + diff --git a/codeception.yml b/codeception.yml new file mode 100644 index 0000000..1883ff0 --- /dev/null +++ b/codeception.yml @@ -0,0 +1,22 @@ +namespace: 'Meritoo\Common\Test' +suites: + unit: + path: . +settings: + shuffle: true + lint: true +paths: + tests: tests + output: tests/_output + support: tests/_support + data: tests +coverage: + enabled: true + include: + - src/* + exclude: + - .data/* + - .docker/* + - .phing/* + - tests/* + - vendor/* diff --git a/composer.json b/composer.json index 10278cf..1dfe52a 100644 --- a/composer.json +++ b/composer.json @@ -17,11 +17,11 @@ "symfony/http-foundation": "^3.3" }, "require-dev": { + "codeception/codeception": "^2.4", "friendsofphp/php-cs-fixer": "^2.2", "pdepend/pdepend": "^2.5", "phploc/phploc": "^2.1", "phpmd/phpmd": "^2.6", - "phpunit/phpunit": "^4.8", "sebastian/phpcpd": "^2.0", "squizlabs/php_codesniffer": "^2.9" }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index ffd8beb..0000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - ./tests/ - - - - - - ./src/ - - - - - - performance - - - - - - - diff --git a/tests/_output/.gitignore b/tests/_output/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/tests/_output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/tests/_support/.gitkeep b/tests/_support/.gitkeep new file mode 100644 index 0000000..e69de29 From 3c83a8800ec85225ab251a8acf0a44845db6a4c1 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 28 May 2018 17:58:17 +0200 Subject: [PATCH 46/70] Start names of special directories without dot --- .gitignore | 4 ++-- build.xml | 12 ++++++------ codeception.yml | 6 +++--- {.data => data}/tests/composer.json | 0 {.data => data}/tests/lorem-ipsum.txt | 0 {.data => data}/tests/minion.jpg | Bin docker-compose.yml | 2 +- {.docker => docker}/config/Dockerfile | 0 {.docker => docker}/config/php.ini | 0 {.docker => docker}/config/xdebug.ini | 0 {.phing => phing}/app.xml | 6 +++--- {.phing => phing}/properties.dist | 4 ++-- {.phing => phing}/tests.xml | 6 +++--- src/Traits/Test/Base/BaseTestCaseTrait.php | 4 ++-- tests/Test/Base/BaseTestCaseTest.php | 2 +- 15 files changed, 23 insertions(+), 23 deletions(-) rename {.data => data}/tests/composer.json (100%) rename {.data => data}/tests/lorem-ipsum.txt (100%) rename {.data => data}/tests/minion.jpg (100%) rename {.docker => docker}/config/Dockerfile (100%) rename {.docker => docker}/config/php.ini (100%) rename {.docker => docker}/config/xdebug.ini (100%) rename {.phing => phing}/app.xml (94%) rename {.phing => phing}/properties.dist (97%) rename {.phing => phing}/tests.xml (97%) diff --git a/.gitignore b/.gitignore index bc4fe0a..950e56e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,7 @@ # ---------------------------------------------------------------------------------------------------------------------- ### Phing # ---------------------------------------------------------------------------------------------------------------------- -/.phing/properties +/phing/properties # ---------------------------------------------------------------------------------------------------------------------- @@ -32,7 +32,7 @@ # ---------------------------------------------------------------------------------------------------------------------- ### Generated databases # ---------------------------------------------------------------------------------------------------------------------- -/.data/tmp +/data/tmp *.sql *.sqlite diff --git a/build.xml b/build.xml index fccc179..d23552d 100644 --- a/build.xml +++ b/build.xml @@ -2,12 +2,12 @@ - + - + - + @@ -18,12 +18,12 @@ - + - + - + - + - + diff --git a/.phing/properties.dist b/phing/properties.dist similarity index 97% rename from .phing/properties.dist rename to phing/properties.dist index e939825..d823a6e 100644 --- a/.phing/properties.dist +++ b/phing/properties.dist @@ -65,7 +65,7 @@ composer.validate = false # System directories # -dir.data = ${project.basedir}/.data +dir.data = ${project.basedir}/data dir.src = ${project.basedir}/src dir.tests = ${project.basedir}/tests @@ -73,7 +73,7 @@ dir.tests = ${project.basedir}/tests # Build directories # -------------------------------------------------------------------------------- -dir.build = ${project.basedir}/.build +dir.build = ${project.basedir}/build dir.reports = ${dir.build}/logs dir.reports.pdepend = ${dir.reports}/pdepend # diff --git a/.phing/tests.xml b/phing/tests.xml similarity index 97% rename from .phing/tests.xml rename to phing/tests.xml index 243cb2e..d705e43 100644 --- a/.phing/tests.xml +++ b/phing/tests.xml @@ -11,12 +11,12 @@ - + - + - + diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index a175bbe..330fcd1 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -32,7 +32,7 @@ trait BaseTestCaseTrait * * @var string */ - private static $testsDataDirPath = '.data/tests'; + private static $testsDataDirPath = 'data/tests'; /** * Provides an empty value @@ -127,7 +127,7 @@ trait BaseTestCaseTrait /** * Returns path of file used by tests. - * It should be placed in /.data/tests directory of this project. + * It should be placed in /data/tests directory of this project. * * @param string $fileName Name of file * @param string $directoryPath (optional) Path of directory containing the file diff --git a/tests/Test/Base/BaseTestCaseTest.php b/tests/Test/Base/BaseTestCaseTest.php index 0a72083..5e54f9a 100644 --- a/tests/Test/Base/BaseTestCaseTest.php +++ b/tests/Test/Base/BaseTestCaseTest.php @@ -132,7 +132,7 @@ class BaseTestCaseTest extends BaseTestCase $directoryPath .= '/'; } - $expectedContains = sprintf('/.data/tests/%s%s', $directoryPath, $fileName); + $expectedContains = sprintf('/data/tests/%s%s', $directoryPath, $fileName); static::assertContains($expectedContains, $path); } From 8a6262a8c38c7f1e8a87b370411ccf9b7b158db3 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Mon, 28 May 2018 21:22:00 +0200 Subject: [PATCH 47/70] Phing > tests > update name of property with path (tests_framework.path > tests.framework.path) & ignore /build directory --- .gitignore | 6 ++++++ phing/properties.dist | 2 +- phing/tests.xml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 950e56e..818a538 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,12 @@ /.php_cs.cache +# ----------------------------------------------------------------------------- +### Build files +# ----------------------------------------------------------------------------- +/build/ + + # ---------------------------------------------------------------------------------------------------------------------- ### Generated databases # ---------------------------------------------------------------------------------------------------------------------- diff --git a/phing/properties.dist b/phing/properties.dist index d823a6e..8d72bf2 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -98,7 +98,7 @@ dir.data.temporary = ${dir.data}/tmp # Path of the framework used to run unit tests # -tests_framework.path = ./vendor/bin/codecept +tests.framework.path = ./vendor/bin/codecept # Path of the PHP Coding Standards Fixer (http://cs.sensiolabs.org) # diff --git a/phing/tests.xml b/phing/tests.xml index d705e43..1589cf9 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -213,7 +213,7 @@ - + From c351ce887aa1f568923ea64fb5ac8efe7b9622c4 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 7 Jun 2018 20:51:55 +0200 Subject: [PATCH 48/70] Tests > implement PHPUnit (instead of Codeception) --- .gitignore | 7 +++++- codeception.yml | 22 ----------------- composer.json | 2 +- phing/properties.dist | 3 ++- phing/tests.xml | 3 ++- phpunit.xml.dist | 53 ++++++++++++++++++++++++++++++++++++++++ tests/_output/.gitignore | 2 -- tests/_support/.gitkeep | 0 8 files changed, 64 insertions(+), 28 deletions(-) delete mode 100644 codeception.yml create mode 100644 phpunit.xml.dist delete mode 100644 tests/_output/.gitignore delete mode 100644 tests/_support/.gitkeep diff --git a/.gitignore b/.gitignore index 818a538..fb17df4 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,12 @@ /phing/properties +# ---------------------------------------------------------------------------------------------------------------------- +### PHPUnit +# ---------------------------------------------------------------------------------------------------------------------- +/phpunit.xml + + # ---------------------------------------------------------------------------------------------------------------------- ### PHP Coding Standards Fixer generated files # ---------------------------------------------------------------------------------------------------------------------- @@ -70,7 +76,6 @@ ### NetBeans template # ---------------------------------------------------------------------------------------------------------------------- nbproject/private/ -build/ nbbuild/ dist/ nbdist/ diff --git a/codeception.yml b/codeception.yml deleted file mode 100644 index e783baf..0000000 --- a/codeception.yml +++ /dev/null @@ -1,22 +0,0 @@ -namespace: 'Meritoo\Common\Test' -suites: - unit: - path: . -settings: - shuffle: true - lint: true -paths: - tests: tests - output: tests/_output - support: tests/_support - data: tests -coverage: - enabled: true - include: - - src/* - exclude: - - data/* - - docker/* - - phing/* - - tests/* - - vendor/* diff --git a/composer.json b/composer.json index 1dfe52a..10278cf 100644 --- a/composer.json +++ b/composer.json @@ -17,11 +17,11 @@ "symfony/http-foundation": "^3.3" }, "require-dev": { - "codeception/codeception": "^2.4", "friendsofphp/php-cs-fixer": "^2.2", "pdepend/pdepend": "^2.5", "phploc/phploc": "^2.1", "phpmd/phpmd": "^2.6", + "phpunit/phpunit": "^4.8", "sebastian/phpcpd": "^2.0", "squizlabs/php_codesniffer": "^2.9" }, diff --git a/phing/properties.dist b/phing/properties.dist index 8d72bf2..aaf0ccb 100644 --- a/phing/properties.dist +++ b/phing/properties.dist @@ -76,6 +76,7 @@ dir.tests = ${project.basedir}/tests dir.build = ${project.basedir}/build dir.reports = ${dir.build}/logs dir.reports.pdepend = ${dir.reports}/pdepend +dir.reports.coverage = ${dir.reports}/phpunit_coverage # # Disabled, because unnecessary right now # phpdocumentor/phpdocumentor cannot be installed via Composer @@ -98,7 +99,7 @@ dir.data.temporary = ${dir.data}/tmp # Path of the framework used to run unit tests # -tests.framework.path = ./vendor/bin/codecept +tests.framework.path = ./vendor/bin/phpunit --verbose --no-coverage --testdox # Path of the PHP Coding Standards Fixer (http://cs.sensiolabs.org) # diff --git a/phing/tests.xml b/phing/tests.xml index 1589cf9..c4e983b 100644 --- a/phing/tests.xml +++ b/phing/tests.xml @@ -104,6 +104,7 @@ + @@ -213,7 +214,7 @@ - + diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..b6d38e5 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,53 @@ + + + + + + + + + + ./tests/ + + + + + + ./src/ + + + + + + performance + + + + + + + diff --git a/tests/_output/.gitignore b/tests/_output/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/tests/_output/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/tests/_support/.gitkeep b/tests/_support/.gitkeep deleted file mode 100644 index e69de29..0000000 From 2e60176d959fe0749880c1ed1692f72791dc6630 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 7 Jun 2018 20:56:48 +0200 Subject: [PATCH 49/70] Docker > Dockerfile > make bash terminal wider (increase columns count) --- docker/config/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/config/Dockerfile b/docker/config/Dockerfile index 2b15489..9a015cd 100644 --- a/docker/config/Dockerfile +++ b/docker/config/Dockerfile @@ -121,4 +121,5 @@ RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ # RUN sed -i 's/^# export/export/g; \ s/^# alias/alias/g;' ~/.bashrc \ - && echo "\n"'export PATH=/project/vendor/bin:$PATH'"\n" >> ~/.bashrc + && echo "\n"'export PATH=/project/vendor/bin:$PATH'"\n" >> ~/.bashrc \ + && echo 'COLUMNS=200'"\n" >> ~/.bashrc From abf0ebf7ecf2223fc821f5d304c52a7e09a7fc85 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 9 Jun 2018 14:25:20 +0200 Subject: [PATCH 50/70] Tests > increase code coverage --- src/Utilities/Repository.php | 197 ++++++-- tests/Utilities/Repository/Sortable.php | 66 +++ tests/Utilities/RepositoryTest.php | 603 ++++++++++++++++++++++++ 3 files changed, 827 insertions(+), 39 deletions(-) create mode 100644 tests/Utilities/Repository/Sortable.php create mode 100644 tests/Utilities/RepositoryTest.php diff --git a/src/Utilities/Repository.php b/src/Utilities/Repository.php index 65c07a9..b9d48b5 100644 --- a/src/Utilities/Repository.php +++ b/src/Utilities/Repository.php @@ -10,7 +10,6 @@ namespace Meritoo\Common\Utilities; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; -use ReflectionException; /** * Useful methods for repository @@ -20,73 +19,143 @@ use ReflectionException; */ class Repository { + /** + * Name of key responsible for sorting/position of an item in array + * + * @var string + */ + const POSITION_KEY = 'position'; + /** * Replenishes positions of given items * - * @param array $items The items - * @param bool $asLast (optional) If is set to true, items are placed at the end (default behaviour). Otherwise - * - at top. + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $asLast (optional) If is set to true, items are placed at the end (default behaviour). Otherwise - + * at top. * @param bool $force (optional) If is set to true, positions are set even there is no extreme position. - * Otherwise - if extreme position is not found (is null) replenishment is stopped / skipped + * Otherwise - if extreme position is unknown (is null) replenishment is stopped / skipped * (default behaviour). - * - * @throws ReflectionException */ - public static function replenishPositions($items, $asLast = true, $force = false) + public static function replenishPositions(array &$items, $asLast = true, $force = false) { $position = self::getExtremePosition($items, $asLast); + /* + * Extreme position is unknown, but it's required? + * Use 0 as default/start value + */ if (null === $position && $force) { $position = 0; } - if (null !== $position && !empty($items)) { - foreach ($items as $item) { - if (method_exists($item, 'getPosition')) { - if (null === $item->getPosition()) { - if ($asLast) { - ++$position; - } else { - --$position; - } + /* + * Extreme position is unknown or there are no items to sort? + * Nothing to do + */ + if (null === $position || empty($items)) { + return; + } - if (method_exists($item, 'setPosition')) { - $item->setPosition($position); - } - } - } + foreach ($items as &$item) { + /* + * The item is not sortable? + */ + if (!self::isSortable($item)) { + continue; } + + /* + * Position has been set? + * Nothing to do + */ + if (self::isSorted($item)) { + continue; + } + + /* + * Calculate position + */ + if ($asLast) { + ++$position; + } else { + --$position; + } + + /* + * It's an object? + * Use proper method to set position + */ + if (is_object($item)) { + $item->setPosition($position); + continue; + } + + /* + * It's an array + * Use proper key to set position + */ + $item[static::POSITION_KEY] = $position; } } /** * Returns extreme position (max or min) of given items * - * @param array $items The items + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays * @param bool $max (optional) If is set to true, maximum value is returned. Otherwise - minimum. * @return int - * - * @throws ReflectionException */ - public static function getExtremePosition($items, $max = true) + public static function getExtremePosition(array $items, $max = true) { + /* + * No items? + * Nothing to do + */ + if (empty($items)) { + return null; + } + $extreme = null; - if (!empty($items)) { - foreach ($items as $item) { - if (Reflection::hasMethod($item, 'getPosition')) { - $position = $item->getPosition(); + foreach ($items as $item) { + /* + * The item is not sortable? + */ + if (!self::isSortable($item)) { + continue; + } - if ($max) { - if ($position > $extreme) { - $extreme = $position; - } - } else { - if ($position < $extreme) { - $extreme = $position; - } - } + $position = null; + + /* + * Let's grab the position + */ + if (is_object($item)) { + $position = $item->getPosition(); + } elseif (array_key_exists(static::POSITION_KEY, $item)) { + $position = $item[static::POSITION_KEY]; + } + + /* + * Maximum value is expected? + */ + if ($max) { + /* + * Position was found and it's larger than previously found position (the extreme position)? + */ + if (null === $extreme || (null !== $position && $position > $extreme)) { + $extreme = $position; } + + continue; + } + + /* + * Minimum value is expected here. + * Position was found and it's smaller than previously found position (the extreme position)? + */ + if (null === $extreme || (null !== $position && $position < $extreme)) { + $extreme = $position; } } @@ -113,4 +182,54 @@ class Repository ->createQueryBuilder($alias) ->orderBy(sprintf('%s.%s', $alias, $property), $direction); } + + /** + * Returns information if given item is sortable + * + * Sortable means it's an: + * - array + * or + * - object and has getPosition() and setPosition() + * + * @param mixed $item An item to verify (object who has "getPosition()" and "setPosition()" methods or an array) + * @return bool + */ + private static function isSortable($item) + { + return is_array($item) + || + ( + is_object($item) + && + Reflection::hasMethod($item, 'getPosition') + && + Reflection::hasMethod($item, 'setPosition') + ); + } + + /** + * Returns information if given item is sorted (position has been set) + * + * @param mixed $item An item to verify (object who has "getPosition()" and "setPosition()" methods or an array) + * @return bool + */ + private static function isSorted($item) + { + /* + * Given item is not sortable? + */ + if (!self::isSortable($item)) { + return false; + } + + /* + * It's an object or it's an array + * and position has been set? + */ + + return + (is_object($item) && null !== $item->getPosition()) + || + (is_array($item) && isset($item[static::POSITION_KEY])); + } } diff --git a/tests/Utilities/Repository/Sortable.php b/tests/Utilities/Repository/Sortable.php new file mode 100644 index 0000000..0e4f2db --- /dev/null +++ b/tests/Utilities/Repository/Sortable.php @@ -0,0 +1,66 @@ + + * @copyright Meritoo.pl + */ +class Sortable +{ + /** + * Position used while sorting + * + * @var int + */ + private $position; + + /** + * Class constructor + * + * @param int $position (optional) Position used while sorting + */ + public function __construct($position = null) + { + $this->position = $position; + } + + /** + * Returns position used while sorting + * + * @return int + */ + public function getPosition() + { + return $this->position; + } + + /** + * Sets position used while sorting + * + * @param int $position Position used while sorting + */ + public function setPosition($position) + { + $this->position = $position; + } + + /** + * Returns representation of object as string + * + * @return string + */ + public function __toString() + { + return sprintf('%s (position: %d)', self::class, $this->getPosition()); + } +} diff --git a/tests/Utilities/RepositoryTest.php b/tests/Utilities/RepositoryTest.php new file mode 100644 index 0000000..3739a30 --- /dev/null +++ b/tests/Utilities/RepositoryTest.php @@ -0,0 +1,603 @@ + + * @copyright Meritoo.pl + */ +class RepositoryTest extends BaseTestCase +{ + public function testConstructor() + { + static::assertHasNoConstructor(Repository::class); + } + + public function testReplenishPositionsWithoutItems() + { + $items = []; + Repository::replenishPositions($items); + + static::assertEquals([], $items); + } + + public function testReplenishPositionsUsingNotSortableObjects() + { + $before = [ + new stdClass(), + new stdClass(), + new stdClass(), + ]; + + $after = [ + new stdClass(), + new stdClass(), + new stdClass(), + ]; + + /* + * Using defaults + */ + Repository::replenishPositions($before); + static::assertEquals($before, $after); + + /* + * Place items at the top + */ + Repository::replenishPositions($before, false); + static::assertEquals($before, $after); + + /* + * Set positions even there is no extreme position (at the end) + */ + Repository::replenishPositions($before, true, true); + static::assertEquals($before, $after); + + /* + * Set positions even there is no extreme position (at the top) + */ + Repository::replenishPositions($before, false, true); + static::assertEquals($before, $after); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @dataProvider provideArraysWithoutExtremePosition + */ + public function testReplenishPositionsUsingArraysWithoutExtremePosition(array $items) + { + Repository::replenishPositions($items); + static::assertEquals($items, $items); + + Repository::replenishPositions($items, false); + static::assertEquals($items, $items); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. + * @param array $expected Items with replenished positions + * + * @dataProvider provideArraysWithoutExtremePosition + */ + public function testReplenishPositionsUsingArraysWithoutExtremePositionForce(array $items, $asLast, array $expected) + { + Repository::replenishPositions($items, $asLast, true); + static::assertEquals($expected, $items); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. + * @param array $expected Items with replenished positions + * + * @dataProvider provideArraysWithExtremePosition + */ + public function testReplenishPositionsUsingArraysWithExtremePositionForce(array $items, $asLast, array $expected) + { + Repository::replenishPositions($items, $asLast, true); + static::assertEquals($expected, $items); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @dataProvider provideObjectsWithoutExtremePosition + */ + public function testReplenishPositionsUsingObjectsWithoutExtremePosition(array $items) + { + Repository::replenishPositions($items); + static::assertEquals($items, $items); + + Repository::replenishPositions($items, false); + static::assertEquals($items, $items); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. + * @param array $expected Items with replenished positions + * + * @dataProvider provideObjectsWithoutExtremePosition + */ + public function testReplenishPositionsUsingObjectsWithoutExtremePositionForce(array $items, $asLast, array $expected) + { + Repository::replenishPositions($items, $asLast, true); + static::assertEquals($expected, $items); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $asLast If is set to true, items are placed at the end (default behaviour). Otherwise - at top. + * @param array $expected Items with replenished positions + * + * @dataProvider provideObjectsWithExtremePosition + */ + public function testReplenishPositionsUsingObjectsWithExtremePositionForce(array $items, $asLast, array $expected) + { + Repository::replenishPositions($items, $asLast, true); + static::assertEquals($expected, $items); + } + + public function testGetExtremePositionWithoutItems() + { + static::assertNull(Repository::getExtremePosition([])); + static::assertNull(Repository::getExtremePosition([], false)); + } + + /** + * @param array $items Objects who have "getPosition()" and "setPosition()" methods or arrays + * @param bool $max (optional) If is set to true, maximum value is returned. Otherwise - minimum. + * @param int $expected Extreme position (max or min) of given items + * + * @dataProvider provideArraysWithoutExtremePositionToGetExtremePosition + */ + public function testGetExtremePositionUsingArraysWithoutExtremePosition(array $items, $max, $expected) + { + static::assertEquals($expected, Repository::getExtremePosition($items, $max)); + } + + public function testGetExtremePositionUsingObjects() + { + } + + public function testGetEntityOrderedQueryBuilder() + { + } + + /** + * Provides arrays without extreme position used to replenish positions of them + * + * @return Generator + */ + public function provideArraysWithoutExtremePosition() + { + yield[ + [ + [], + [], + ], + true, + [ + [ + Repository::POSITION_KEY => 1, + ], + [ + Repository::POSITION_KEY => 2, + ], + ], + ]; + + yield[ + [ + [], + [], + ], + false, + [ + [ + Repository::POSITION_KEY => -1, + ], + [ + Repository::POSITION_KEY => -2, + ], + ], + ]; + + yield[ + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + ], + ], + true, + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + Repository::POSITION_KEY => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + Repository::POSITION_KEY => 2, + ], + ], + ]; + + yield[ + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + ], + ], + false, + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + Repository::POSITION_KEY => -1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + Repository::POSITION_KEY => -2, + ], + ], + ]; + } + + /** + * Provides arrays with extreme position used to replenish positions of them + * + * @return Generator + */ + public function provideArraysWithExtremePosition() + { + yield[ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [], + ], + true, + [ + [ + Repository::POSITION_KEY => 1, + ], + [ + Repository::POSITION_KEY => 2, + ], + [ + Repository::POSITION_KEY => 3, + ], + ], + ]; + + yield[ + [ + [], + [], + [ + Repository::POSITION_KEY => 1, + ], + ], + true, + [ + [ + Repository::POSITION_KEY => 2, + ], + [ + Repository::POSITION_KEY => 3, + ], + [ + Repository::POSITION_KEY => 1, + ], + ], + ]; + + yield[ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [], + ], + false, + [ + [ + Repository::POSITION_KEY => 1, + ], + [ + Repository::POSITION_KEY => 0, + ], + [ + Repository::POSITION_KEY => -1, + ], + ], + ]; + + yield[ + [ + + [], + [], + [ + Repository::POSITION_KEY => 1, + ], + ], + false, + [ + [ + Repository::POSITION_KEY => 0, + ], + [ + Repository::POSITION_KEY => -1, + ], + [ + Repository::POSITION_KEY => 1, + ], + ], + ]; + } + + /** + * Provides objects without extreme position used to replenish positions of them + * + * @return Generator + */ + public function provideObjectsWithoutExtremePosition() + { + yield[ + [ + new Sortable(), + new Sortable(), + new Sortable(), + ], + true, + [ + new Sortable(1), + new Sortable(2), + new Sortable(3), + ], + ]; + + yield[ + [ + new Sortable(), + new Sortable(), + new Sortable(), + ], + false, + [ + new Sortable(-1), + new Sortable(-2), + new Sortable(-3), + ], + ]; + } + + /** + * Provides objects with extreme position used to replenish positions of them + * + * @return Generator + */ + public function provideObjectsWithExtremePosition() + { + yield[ + [ + new Sortable(1), + new Sortable(), + new Sortable(), + ], + true, + [ + new Sortable(1), + new Sortable(2), + new Sortable(3), + ], + ]; + + yield[ + [ + new Sortable(), + new Sortable(1), + new Sortable(), + ], + true, + [ + new Sortable(2), + new Sortable(1), + new Sortable(3), + ], + ]; + + yield[ + [ + new Sortable(1), + new Sortable(), + new Sortable(), + ], + false, + [ + new Sortable(1), + new Sortable(0), + new Sortable(-1), + ], + ]; + } + + /** + * Provides arrays without extreme position used to get extreme position + * + * @return Generator + */ + public function provideArraysWithoutExtremePositionToGetExtremePosition() + { + yield[ + [], + false, + null, + ]; + + yield[ + [], + true, + null, + ]; + + yield[ + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + ], + ], + true, + null, + ]; + + yield[ + [ + [ + 'lorem' => 'ipsum', + 'dolor', + 'sit' => 1, + ], + [ + 'abc' => 'def', + 'ghi' => null, + 'jkl' => 10, + ], + ], + false, + null, + ]; + } + + /** + * Provides arrays with extreme position used to get extreme position + * + * @return Generator + */ + public function provideArraysWithExtremePositionToGetExtremePosition() + { + yield[ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [], + ], + true, + 1, + ]; + + yield[ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [], + ], + false, + 1, + ]; + + yield[ + [ + [], + [], + [ + Repository::POSITION_KEY => 1, + ], + ], + true, + 1, + ]; + + yield[ + [ + [], + [], + [ + Repository::POSITION_KEY => 1, + ], + ], + false, + 1, + ]; + + yield[ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [ + Repository::POSITION_KEY => 2, + ], + [], + ], + true, + 1, + ]; + + yield[ + [ + [ + Repository::POSITION_KEY => 1, + ], + [], + [ + Repository::POSITION_KEY => 2, + ], + [], + ], + false, + 2, + ]; + } +} From 49638ff1c35563c26191a70ea0aba547565a877d Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 13 Jun 2018 22:21:28 +0200 Subject: [PATCH 51/70] .gitignore > update sections' separators --- .gitignore | 56 +++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index fb17df4..820ce78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,37 @@ -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ # Environment-related parameters -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ .env -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Vendors -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /vendor/ -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Composer -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /composer.lock /composer.phar -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Phing -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /phing/properties -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### PHPUnit -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /phpunit.xml -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### PHP Coding Standards Fixer generated files -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /.php_cs.cache @@ -41,17 +41,17 @@ /build/ -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Generated databases -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /data/tmp *.sql *.sqlite -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Compiled source -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ *.com *.class *.dll @@ -60,21 +60,21 @@ *.so -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Shell scripts -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /*.sh -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### JetBrains -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /.idea -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### NetBeans template -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ nbproject/private/ nbbuild/ dist/ @@ -83,9 +83,9 @@ nbactions.xml .nb-gradle/ -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### OSX template -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ .DS_Store .AppleDouble .LSOverride @@ -112,9 +112,9 @@ Temporary Items .apdisk -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Linux template -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ *~ # temporary files which can be created if a process still has a handle open of a deleted file @@ -127,9 +127,9 @@ Temporary Items .Trash-* -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Windows template -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ # Windows image file caches Thumbs.db ehthumbs.db From 9197682cd230a5c6c2d674d59db62974e8e89ec9 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Wed, 13 Jun 2018 22:55:49 +0200 Subject: [PATCH 52/70] Readme > update paragraphs with Composer, Docker & use 1st level headers --- README.md | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 057ead4..3be9a87 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Common and useful classes, methods, exceptions etc. [![Travis](https://img.shields.io/travis/rust-lang/rust.svg?style=flat-square)](https://travis-ci.org/meritoo/common-library) [![Packagist](https://img.shields.io/packagist/v/meritoo/common-library.svg?style=flat-square)](https://packagist.org/packages/meritoo/common-library) [![StyleCI](https://styleci.io/repos/101790028/shield?branch=master)](https://styleci.io/repos/101790028) [![license](https://img.shields.io/github/license/meritoo/common-library.svg?style=flat-square)](https://github.com/meritoo/common-library) [![GitHub commits](https://img.shields.io/github/commits-since/meritoo/common-library/0.0.1.svg?style=flat-square)](https://github.com/meritoo/common-library) [![Coverage Status](https://coveralls.io/repos/github/meritoo/common-library/badge.svg?branch=master)](https://coveralls.io/github/meritoo/common-library?branch=master) -## Installation +# Installation Run [Composer](https://getcomposer.org) to install this package in your project: @@ -11,18 +11,41 @@ Run [Composer](https://getcomposer.org) to install this package in your project: $ composer require meritoo/common-library ``` -> How to install Composer: https://getcomposer.org/download +> [How to install Composer?](https://getcomposer.org/download) -## Rebuilding project and tests running +# Docker + +Build, create and start Docker's containers by running command: ```bash $ docker-compose up -d +``` + +> [What is Docker?](https://www.docker.com/what-docker) + +# Composer + +Install packages by running command: + +```bash +$ docker-compose run composer install +``` + +Update packages by running command: + +```bash +$ docker-compose run composer update +``` + +# Rebuild project and run tests + +```bash $ docker-compose exec php-cli phing ``` -> What is Docker? https://www.docker.com/what-docker +> [What is Docker?](https://www.docker.com/what-docker) -## Static methods +# Static methods This package contains a lot of class with static methods, so usage is not so complicated. Just run the static method who would you like to use. Example: @@ -33,7 +56,7 @@ $firstElement = Arrays::getFirstElement(['lorem', 'ipsum']); var_dump($firstElement); // string(5) "lorem" ``` -## Base test case with common methods and data providers +# Base test case with common methods and data providers Located here: `Meritoo\Common\Test\Base\BaseTestCase`. Just extend the `BaseTestCase` class and use it like in `Meritoo\Common\Test\Utilities\DateTest` class: @@ -73,7 +96,7 @@ class MimeTypesTest extends BaseTestCase } ``` -## Collection of elements +# Collection of elements Located here: `Meritoo\Common\Collection\Collection`. It's a set of some elements, e.g. objects. It's iterable and countable. Provides very useful methods. Some of them: - `getFirst()` - returns the first element in the collection @@ -86,7 +109,7 @@ Located here: `Meritoo\Common\Collection\Collection`. It's a set of some element Examples of usage below. -#### An empty collection +### An empty collection ```php use Meritoo\Common\Collection\Collection; @@ -95,7 +118,7 @@ $emptyCollection = new Collection(); var_dump($emptyCollection->isEmpty()); // bool(true) ``` -#### Simple collection +### Simple collection ```php use Meritoo\Common\Collection\Collection; From 696cff023c4e3d13411a367a77e9efd85a48cff1 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 14 Jun 2018 11:32:25 +0200 Subject: [PATCH 53/70] Add changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9c19981 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,6 @@ +# Meritoo Common Library +Common and useful classes, methods, exceptions etc. + +## 0.0.19 + +1. Add this changelog From 57a78d12990af2c41a28522d779d01d2dbe42ebe Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 14 Jun 2018 11:32:54 +0200 Subject: [PATCH 54/70] Reorganize documentation & update Readme --- CHANGELOG.md | 1 + README.md | 125 ++------------------------------- docker-compose.yml | 2 +- docs/Base-test-case.md | 50 +++++++++++++ docs/Collection-of-elements.md | 48 +++++++++++++ docs/Development.md | 44 ++++++++++++ docs/Static-methods.md | 21 ++++++ 7 files changed, 172 insertions(+), 119 deletions(-) create mode 100644 docs/Base-test-case.md create mode 100644 docs/Collection-of-elements.md create mode 100644 docs/Development.md create mode 100644 docs/Static-methods.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c19981..7cede3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,3 +4,4 @@ Common and useful classes, methods, exceptions etc. ## 0.0.19 1. Add this changelog +2. Reorganize documentation & update [Readme](README.md) diff --git a/README.md b/README.md index 3be9a87..d74866d 100644 --- a/README.md +++ b/README.md @@ -8,130 +8,19 @@ Common and useful classes, methods, exceptions etc. Run [Composer](https://getcomposer.org) to install this package in your project: ```bash -$ composer require meritoo/common-library +composer require meritoo/common-library ``` > [How to install Composer?](https://getcomposer.org/download) -# Docker +# Usage -Build, create and start Docker's containers by running command: +1. [Base test case (with common methods and data providers)](docs/Base-test-case.md) +2. [Collection of elements](docs/Collection-of-elements.md) +3. [Static methods](docs/Static-methods.md) -```bash -$ docker-compose up -d -``` +# Development -> [What is Docker?](https://www.docker.com/what-docker) - -# Composer - -Install packages by running command: - -```bash -$ docker-compose run composer install -``` - -Update packages by running command: - -```bash -$ docker-compose run composer update -``` - -# Rebuild project and run tests - -```bash -$ docker-compose exec php-cli phing -``` - -> [What is Docker?](https://www.docker.com/what-docker) - -# Static methods - -This package contains a lot of class with static methods, so usage is not so complicated. Just run the static method who would you like to use. Example: - -```php -use Meritoo\Common\Utilities\Arrays; - -$firstElement = Arrays::getFirstElement(['lorem', 'ipsum']); -var_dump($firstElement); // string(5) "lorem" -``` - -# Base test case with common methods and data providers - -Located here: `Meritoo\Common\Test\Base\BaseTestCase`. Just extend the `BaseTestCase` class and use it like in `Meritoo\Common\Test\Utilities\DateTest` class: - -```php -class DateTest extends BaseTestCase -{ - /** - * @param mixed $value Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testGetDateTimeEmptyValue($value) - { - self::assertFalse(Date::getDateTime($value)); - } - - (...) -} -``` - -or in `Meritoo\Common\Test\Utilities\MimeTypesTest` class: - -```php -class MimeTypesTest extends BaseTestCase -{ - (...) - - /** - * @param bool $mimeType The mime type, e.g. "video/mpeg" - * @dataProvider provideBooleanValue - */ - public function testGetExtensionBooleanMimeType($mimeType) - { - self::assertEquals('', MimeTypes::getExtension($mimeType)); - } - - (...) -} -``` - -# Collection of elements - -Located here: `Meritoo\Common\Collection\Collection`. It's a set of some elements, e.g. objects. It's iterable and countable. Provides very useful methods. Some of them: -- `getFirst()` - returns the first element in the collection -- `getLast()` - returns the last element in the collection -- `isEmpty()` - returns information if collection is empty -- `add($element, $index = null)` - adds given element (at the end of collection) -- `addMultiple($elements, $useIndexes = false)` - adds given elements (at the end of collection) -- `prepend($element)` - prepends given element (adds given element at the beginning of collection) -- `remove($element)` - removes given element - -Examples of usage below. - -### An empty collection - -```php -use Meritoo\Common\Collection\Collection; - -$emptyCollection = new Collection(); -var_dump($emptyCollection->isEmpty()); // bool(true) -``` - -### Simple collection - -```php -use Meritoo\Common\Collection\Collection; - -$elements = [ - 'lorem', - 'ipsum', - 123 => 'dolor', - 345 => 'sit', -]; - -$simpleCollection = new Collection($elements); -var_dump($simpleCollection->has('dolor')); // bool(true) -``` +More information [you can find here](docs/Development.md) Enjoy! diff --git a/docker-compose.yml b/docker-compose.yml index e9a45d8..b62f9e1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,6 @@ services: image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php-cli container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-composer working_dir: /project - command: composer + entrypoint: composer volumes: - .:/project diff --git a/docs/Base-test-case.md b/docs/Base-test-case.md new file mode 100644 index 0000000..529b7f1 --- /dev/null +++ b/docs/Base-test-case.md @@ -0,0 +1,50 @@ +# Meritoo Common Library +Common and useful classes, methods, exceptions etc. + +# Base test case (with common methods and data providers) + +Located here: `Meritoo\Common\Test\Base\BaseTestCase`. Just extend the `BaseTestCase` class and use it like in `Meritoo\Common\Test\Utilities\DateTest` class: + +```php +class DateTest extends BaseTestCase +{ + /** + * @param mixed $value Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testGetDateTimeEmptyValue($value) + { + self::assertFalse(Date::getDateTime($value)); + } + + (...) +} +``` + +or in `Meritoo\Common\Test\Utilities\MimeTypesTest` class: + +```php +class MimeTypesTest extends BaseTestCase +{ + (...) + + /** + * @param bool $mimeType The mime type, e.g. "video/mpeg" + * @dataProvider provideBooleanValue + */ + public function testGetExtensionBooleanMimeType($mimeType) + { + self::assertEquals('', MimeTypes::getExtension($mimeType)); + } + + (...) +} +``` + +# More + +1. [**Base test case (with common methods and data providers)**](Base-test-case.md) +2. [Collection of elements](Collection-of-elements.md) +3. [Static methods](Static-methods.md) + +[‹ Back to `Readme`](../README.md) diff --git a/docs/Collection-of-elements.md b/docs/Collection-of-elements.md new file mode 100644 index 0000000..79c57fa --- /dev/null +++ b/docs/Collection-of-elements.md @@ -0,0 +1,48 @@ +# Meritoo Common Library +Common and useful classes, methods, exceptions etc. + +# Collection of elements + +Located here: `Meritoo\Common\Collection\Collection`. It's a set of some elements, e.g. objects. It's iterable and countable. Provides very useful methods. Some of them: +- `getFirst()` - returns the first element in the collection +- `getLast()` - returns the last element in the collection +- `isEmpty()` - returns information if collection is empty +- `add($element, $index = null)` - adds given element (at the end of collection) +- `addMultiple($elements, $useIndexes = false)` - adds given elements (at the end of collection) +- `prepend($element)` - prepends given element (adds given element at the beginning of collection) +- `remove($element)` - removes given element + +Examples of usage below. + +### An empty collection + +```php +use Meritoo\Common\Collection\Collection; + +$emptyCollection = new Collection(); +var_dump($emptyCollection->isEmpty()); // bool(true) +``` + +### Simple collection + +```php +use Meritoo\Common\Collection\Collection; + +$elements = [ + 'lorem', + 'ipsum', + 123 => 'dolor', + 345 => 'sit', +]; + +$simpleCollection = new Collection($elements); +var_dump($simpleCollection->has('dolor')); // bool(true) +``` + +# More + +1. [Base test case (with common methods and data providers)](Base-test-case.md) +2. [**Collection of elements**](Collection-of-elements.md) +3. [Static methods](Static-methods.md) + +[‹ Back to `Readme`](../README.md) diff --git a/docs/Development.md b/docs/Development.md new file mode 100644 index 0000000..35fa88c --- /dev/null +++ b/docs/Development.md @@ -0,0 +1,44 @@ +# Meritoo Common Library +Development-related information + +# Getting started + +### Docker + +Build, create and start Docker's containers by running command: + +```bash +docker-compose up -d +``` + +> [What is Docker?](https://www.docker.com/what-docker) + +### Composer + +Install packages by running command: + +```bash +docker-compose run composer install +``` + +Update packages by running command: + +```bash +docker-compose run composer update +``` + +### Tests + +Rebuild project and run tests by running command: + +```bash +docker-compose exec php-cli phing +``` + +Run tests only by running command: + +```bash +docker-compose exec php-cli phpunit +``` + +[‹ Back to `Readme`](../README.md) diff --git a/docs/Static-methods.md b/docs/Static-methods.md new file mode 100644 index 0000000..5711dd6 --- /dev/null +++ b/docs/Static-methods.md @@ -0,0 +1,21 @@ +# Meritoo Common Library +Common and useful classes, methods, exceptions etc. + +# Static methods + +This package contains a lot of class with static methods, so usage is not so complicated. Just run the static method who would you like to use. Example: + +```php +use Meritoo\Common\Utilities\Arrays; + +$firstElement = Arrays::getFirstElement(['lorem', 'ipsum']); +var_dump($firstElement); // string(5) "lorem" +``` + +# More + +1. [Base test case (with common methods and data providers)](Base-test-case.md) +2. [Collection of elements](Collection-of-elements.md) +3. [**Static methods**](Static-methods.md) + +[‹ Back to `Readme`](../README.md) From fb24bc2ff136883074b0139a57351e54d7673a0b Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 14 Jun 2018 11:50:45 +0200 Subject: [PATCH 55/70] Docker > use project-related binaries globally --- CHANGELOG.md | 1 + docker/config/Dockerfile | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cede3e..b08450d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,4 @@ Common and useful classes, methods, exceptions etc. 1. Add this changelog 2. Reorganize documentation & update [Readme](README.md) +3. Docker > use project-related binaries globally diff --git a/docker/config/Dockerfile b/docker/config/Dockerfile index 9a015cd..f581f9c 100644 --- a/docker/config/Dockerfile +++ b/docker/config/Dockerfile @@ -121,5 +121,9 @@ RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ # RUN sed -i 's/^# export/export/g; \ s/^# alias/alias/g;' ~/.bashrc \ - && echo "\n"'export PATH=/project/vendor/bin:$PATH'"\n" >> ~/.bashrc \ && echo 'COLUMNS=200'"\n" >> ~/.bashrc + +# +# Use project-related binaries globally +# +ENV PATH="/project/vendor/bin:${PATH}" From 3726a26e4732974a04e518b4414547fcc5a6e46c Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 14 Jun 2018 21:32:18 +0200 Subject: [PATCH 56/70] Reorganize documentation & update Readme --- docs/Development.md | 58 ++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/docs/Development.md b/docs/Development.md index 35fa88c..d9adbd3 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -1,33 +1,63 @@ # Meritoo Common Library Development-related information +# Requirements + +* [Docker](https://www.docker.com) +* Your favourite IDE :) + # Getting started -### Docker +1. Build, create and start Docker's containers by running command: -Build, create and start Docker's containers by running command: + ```bash + docker-compose up -d + ``` -```bash -docker-compose up -d -``` +2. Install packages by running command: + + ```bash + docker-compose run composer install + ``` > [What is Docker?](https://www.docker.com/what-docker) -### Composer +# Tests -Install packages by running command: +### Prerequisites + +Install required packages by running command: `docker-compose run composer install`. + +### Running tests + +#### Simply & quick, without code coverage + +Tests are running using Docker and `php-cli` service defined in `docker-compose.yml`. Example: ```bash -docker-compose run composer install +docker-compose exec php-cli phpunit --no-coverage ``` -Update packages by running command: +You can also run them in container. In this case you have to run 2 commands: +1. Enter container: + + ```bash + docker-compose exec php-cli bash + ``` + +2. Run tests: + + ```bash + phpunit --no-coverage + ``` + +#### With code coverage ```bash -docker-compose run composer update +docker-compose exec php-cli phpunit ``` -### Tests +# Other Rebuild project and run tests by running command: @@ -35,10 +65,4 @@ Rebuild project and run tests by running command: docker-compose exec php-cli phing ``` -Run tests only by running command: - -```bash -docker-compose exec php-cli phpunit -``` - [‹ Back to `Readme`](../README.md) From 4c534394d982d7ee3dcaa3b64243ca3c718d1764 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 14 Jun 2018 21:35:50 +0200 Subject: [PATCH 57/70] Docker > Dockerfile > add "WORKDIR" (instead of "working_dir" in docker-compose.yml) --- docker-compose.yml | 2 -- docker/config/Dockerfile | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b62f9e1..25cf8b9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,6 @@ services: php-cli: image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php-cli container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-php-cli - working_dir: /project entrypoint: php command: -S 0.0.0.0:9999 build: @@ -16,7 +15,6 @@ services: composer: image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php-cli container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-composer - working_dir: /project entrypoint: composer volumes: - .:/project diff --git a/docker/config/Dockerfile b/docker/config/Dockerfile index f581f9c..989e520 100644 --- a/docker/config/Dockerfile +++ b/docker/config/Dockerfile @@ -127,3 +127,5 @@ RUN sed -i 's/^# export/export/g; \ # Use project-related binaries globally # ENV PATH="/project/vendor/bin:${PATH}" + +WORKDIR /project From e9da0cf35165f0fc09f0b0f09c971b61421dee4f Mon Sep 17 00:00:00 2001 From: Meritoo Date: Thu, 14 Jun 2018 22:28:53 +0200 Subject: [PATCH 58/70] Reorganize documentation & update Readme --- docs/Development.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/Development.md b/docs/Development.md index d9adbd3..4bc2c84 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -22,6 +22,40 @@ Development-related information > [What is Docker?](https://www.docker.com/what-docker) +# Composer + +Available as `composer` service. You can run any Composer's command using the `composer` service: + +```bash +docker-compose run composer +``` + +Examples below. + +##### Install packages + +```bash +docker-compose run composer install +``` + +##### Update packages + +```bash +docker-compose run composer update +``` + +##### Add package + +```bash +docker-compose run composer require / +``` + +##### Remove package + +```bash +docker-compose run composer remove / +``` + # Tests ### Prerequisites From 43945a872152294b6672aeaa5351056e7ccb4618 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 15 Jun 2018 22:54:00 +0200 Subject: [PATCH 59/70] Composer > do not require symfony/http-foundation package Miscellaneous > remove getCurlResponseWithHeaders() method --- composer.json | 3 +- src/Utilities/Miscellaneous.php | 141 -------------------------- tests/Utilities/MiscellaneousTest.php | 39 ------- 3 files changed, 1 insertion(+), 182 deletions(-) diff --git a/composer.json b/composer.json index 10278cf..d1fc9df 100644 --- a/composer.json +++ b/composer.json @@ -13,8 +13,7 @@ "require": { "php": ">=5.5.9", "doctrine/orm": "^2.5", - "gedmo/doctrine-extensions": "^2.4", - "symfony/http-foundation": "^3.3" + "gedmo/doctrine-extensions": "^2.4" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.2", diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index 2146a29..da612e4 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -11,7 +11,6 @@ namespace Meritoo\Common\Utilities; use Gedmo\Sluggable\Util\Urlizer; use Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException; use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; -use Symfony\Component\HttpFoundation\Cookie; use Transliterator; /** @@ -1205,146 +1204,6 @@ class Miscellaneous return $value; } - /** - * Returns a CURL response with parsed HTTP headers as array with "headers", "cookies" and "content" keys - * - * The headers and cookies are parsed and returned as an array, and an array of Cookie objects. Returned array looks - * like this example: - * - * [ - * 'headers' => [ - * 'Content-Type' => 'text/html; charset=UTF-8', - * ... - * ], - * 'cookies' => [ - * new Symfony\Component\HttpFoundation\Cookie(), - * new Symfony\Component\HttpFoundation\Cookie(), - * ... - * ], - * 'content' => '...' - * ] - * - * - * If you want to attach HTTP headers into response content by CURL you need to set "CURLOPT_HEADER" option - * to "true". To read exact length of HTTP headers from CURL you can use "curl_getinfo()" function - * and read "CURLINFO_HEADER_SIZE" option. - * - * @param string $response Full content of response, including HTTP headers - * @param int $headerSize Length of HTTP headers in content - * @return array - */ - public static function getCurlResponseWithHeaders($response, $headerSize) - { - $headers = []; - $cookies = []; - - $headerContent = ''; - $content = ''; - - if (0 < $headerSize) { - $headerContent = mb_substr($response, 0, $headerSize); - $content = mb_substr($response, $headerSize); - } - - /* - * Let's transform headers content into two arrays: headers and cookies - */ - if (!empty($headerContent)) { - foreach (explode("\r\n", $headerContent) as $i => $line) { - /* - * First line is only HTTP status and is unneeded so skip it - */ - if (0 === $i) { - continue; - } - - if (Regex::contains($line, ':')) { - list($key, $value) = explode(': ', $line); - - /* - * If the header is a "set-cookie" let's save it to "cookies" array - */ - if ('Set-Cookie' === $key) { - $cookieParameters = explode(';', $value); - - $name = ''; - $value = ''; - $expire = 0; - $path = '/'; - $domain = null; - $secure = false; - $httpOnly = true; - - foreach ($cookieParameters as $j => $parameter) { - $param = explode('=', $parameter); - - /* - * First parameter will be always a cookie name and it's value. It is not needed to run - * further actions for them, so save the values and move to next parameter. - */ - if (0 === $j) { - $name = trim($param[0]); - $value = trim($param[1]); - continue; - } - - /* - * Now there would be the rest of cookie parameters, names of params are sent different way so - * I need to lowercase the names and remove unneeded spaces. - */ - $paramName = mb_strtolower(trim($param[0])); - $paramValue = true; - - /* - * Some parameters don't have value e.g. "secure", but the value for them if they're specified - * is "true". Otherwise - just read a value for parameter if exists. - */ - if (array_key_exists(1, $param)) { - $paramValue = trim($param[1]); - } - - switch ($paramName) { - case 'expires': - $expire = $paramValue; - break; - case 'path': - $path = $paramValue; - break; - case 'domain': - $domain = $paramValue; - break; - case 'secure': - $secure = $paramValue; - break; - case 'httponly': - $httpOnly = $paramValue; - break; - } - } - - /* - * Create new Cookie object and add it to "cookies" array. - * I must skip to next header as cookies shouldn't be saved in "headers" array. - */ - $cookies[] = new Cookie($name, $value, $expire, $path, $domain, $secure, $httpOnly); - continue; - } - - /* - * Save response header which is not a cookie - */ - $headers[$key] = $value; - } - } - } - - return [ - 'headers' => $headers, - 'cookies' => $cookies, - 'content' => $content, - ]; - } - /** * Adds missing the "0" characters to given number until given length is reached * diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index db3145d..6145ac1 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -770,21 +770,6 @@ class MiscellaneousTest extends BaseTestCase self::assertNotEmpty(Miscellaneous::getProjectRootPath()); } - /** - * @param int $headerSize Length of HTTP headers in content - * @dataProvider provideHeaderSizeForEmptyCurlResponse - */ - public function testGetCurlResponseWithHeadersUsingEmptyResponse($headerSize) - { - $expected = [ - 'headers' => [], - 'cookies' => [], - 'content' => '', - ]; - - self::assertEquals($expected, Miscellaneous::getCurlResponseWithHeaders('', $headerSize)); - } - /** * Provides string to convert characters to latin characters and not lower cased and not human-readable * @@ -1195,30 +1180,6 @@ class MiscellaneousTest extends BaseTestCase ]; } - /** - * Provides length/size of HTTP headers for an empty response - * - * @return Generator - */ - public function provideHeaderSizeForEmptyCurlResponse() - { - yield[ - -10, - ]; - - yield[ - -1, - ]; - - yield[ - 0, - ]; - - yield[ - 10, - ]; - } - /** * {@inheritdoc} */ From 155c091a3e9c9db28c6032de4a18763fb69ee226 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 15 Jun 2018 23:00:29 +0200 Subject: [PATCH 60/70] StyleCI > update configuration --- .styleci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.styleci.yml b/.styleci.yml index e594180..b0f42d8 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -2,7 +2,8 @@ preset: symfony disabled: - phpdoc_annotation_without_dot + - phpdoc_summary - cast_spaces - concat_without_spaces - - blank_line_before_return - trim_array_spaces + - array_indentation From ffe34eb9cf1d4d16e0357359463f655b4e209541 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Fri, 15 Jun 2018 23:06:47 +0200 Subject: [PATCH 61/70] StyleCI > update configuration --- .styleci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.styleci.yml b/.styleci.yml index b0f42d8..ee9083c 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,4 +1,4 @@ -preset: symfony +preset: recommended disabled: - phpdoc_annotation_without_dot From b1ddc6d561062639a6a744811165e80c99806e0a Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 10:04:14 +0200 Subject: [PATCH 62/70] .env.dist > enter default values (for easier .env creation) --- .env.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.dist b/.env.dist index 50e9ce0..4c093b4 100644 --- a/.env.dist +++ b/.env.dist @@ -5,8 +5,8 @@ # # All containers # -DOCKER_CONTAINER_OWNER=__ENTER__OWNER__NAME__ -DOCKER_CONTAINER_PROJECT=__ENTER__PROJECT__NAME__ +DOCKER_CONTAINER_OWNER=meritoo +DOCKER_CONTAINER_PROJECT=common-library # # PHP configuration: From be8b4a3498a2221ee7121284a4872850c575768d Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 14:10:57 +0200 Subject: [PATCH 63/70] Arrays > remove unnecessary code --- src/Utilities/Arrays.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index c01a9d8..cb254f8 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -48,23 +48,6 @@ class Arrays if (is_array($value)) { $effect .= self::values2string($value, $arrayColumnKey, $separator); - /* - * Previous version. Doesn't work with array containing arrays, e.g.: - * array( - * 1 => array( - * 'item1', - * 'item2' - * ), - * 2 => array( - * 'item3', - * 'item4' - * ) - * ) - * - if(isset($value[$arrayColumnKey])){ - $effect .= $value[$arrayColumnKey]; - } - */ } else { if (empty($arrayColumnKey)) { $effect .= $value; From c443ef22d7213a44fcf448eba390f888bf300044 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 14:12:07 +0200 Subject: [PATCH 64/70] .gitignore > PHP Coding Standards Fixer > ignore custom settings --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 820ce78..8f1b748 100644 --- a/.gitignore +++ b/.gitignore @@ -30,8 +30,9 @@ # ------------------------------------------------------------------------------ -### PHP Coding Standards Fixer generated files +### PHP Coding Standards Fixer # ------------------------------------------------------------------------------ +/.php_cs /.php_cs.cache From c99a099c317a9937a0745a587c09b5eb145057d9 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 14:15:35 +0200 Subject: [PATCH 65/70] StyleCI & PHP Coding Standards Fixer > update configuration --- .php_cs.dist | 26 ++++++++++++-------------- .styleci.yml | 16 +++++++++++----- CHANGELOG.md | 3 ++- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 4e1c7bd..fe6e788 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -1,13 +1,6 @@ notPath('/DependencyInjection\/Configuration\.php/') - ->notPath('/autoload\.php/') ->in([ __DIR__ . '/src', __DIR__ . '/tests', @@ -15,16 +8,21 @@ $finder = PhpCsFixer\Finder::create() return PhpCsFixer\Config::create() ->setRules([ - '@Symfony' => true, - 'phpdoc_summary' => false, - 'phpdoc_separation' => false, - 'phpdoc_align' => false, - 'cast_spaces' => false, - 'binary_operator_spaces' => [ + '@Symfony' => true, + 'binary_operator_spaces' => [ 'align_double_arrow' => true, ], - 'concat_space' => [ + 'blank_line_before_return' => false, + 'cast_spaces' => false, + // "concat_space" instead of "concat_with_spaces" option used by StyleCI + 'concat_space' => [ 'spacing' => 'one', ], + 'phpdoc_add_missing_param_annotation' => true, + 'phpdoc_align' => false, + 'phpdoc_order' => true, + 'phpdoc_separation' => false, + 'phpdoc_summary' => false, + 'trim_array_spaces' => false, ]) ->setFinder($finder); diff --git a/.styleci.yml b/.styleci.yml index ee9083c..e8497fb 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,9 +1,15 @@ -preset: recommended +preset: symfony + +enabled: + - binary_operator_spaces + - concat_with_spaces + - phpdoc_add_missing_param_annotation + - phpdoc_order disabled: - - phpdoc_annotation_without_dot - - phpdoc_summary + - blank_line_before_return - cast_spaces - - concat_without_spaces + - phpdoc_align + - phpdoc_separation + - phpdoc_summary - trim_array_spaces - - array_indentation diff --git a/CHANGELOG.md b/CHANGELOG.md index b08450d..e566c8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,4 +5,5 @@ Common and useful classes, methods, exceptions etc. 1. Add this changelog 2. Reorganize documentation & update [Readme](README.md) -3. Docker > use project-related binaries globally +3. Docker: use project-related binaries globally +4. StyleCI & PHP Coding Standards Fixer: update configuration From ae3e82e23368237a372e8ff84312bb2c29829425 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 14:17:35 +0200 Subject: [PATCH 66/70] Documentation > Docker > add paragraph for PHP Coding Standards Fixer --- CHANGELOG.md | 1 + docs/Development.md | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e566c8e..c6658b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,3 +7,4 @@ Common and useful classes, methods, exceptions etc. 2. Reorganize documentation & update [Readme](README.md) 3. Docker: use project-related binaries globally 4. StyleCI & PHP Coding Standards Fixer: update configuration +5. Documentation > Docker > add paragraph for PHP Coding Standards Fixer diff --git a/docs/Development.md b/docs/Development.md index 4bc2c84..545b3dd 100644 --- a/docs/Development.md +++ b/docs/Development.md @@ -56,6 +56,22 @@ docker-compose run composer require / docker-compose run composer remove / ``` +# Coding Standards Fixer + +Fix coding standard by running command: + +```bash +docker-compose exec php-cli php-cs-fixer fix +``` + +Omit cache and run the Fixer from scratch by running command: + +```bash +docker-compose exec php-cli rm .php_cs.cache && docker-compose exec php-cli php-cs-fixer fix +``` + +> [Want more?](https://cs.sensiolabs.org) + # Tests ### Prerequisites From 0f37edfc9beece3c11f7475471236cc77c08cff4 Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 14:31:04 +0200 Subject: [PATCH 67/70] Coding standard > fix automatically --- CHANGELOG.md | 1 + src/Utilities/Bundle.php | 6 +-- src/Utilities/Date.php | 13 ++--- src/Utilities/MimeTypes.php | 3 +- src/Utilities/Miscellaneous.php | 3 +- src/Utilities/QueryBuilderUtility.php | 2 +- src/Utilities/Reflection.php | 47 +++++++------------ src/Utilities/Regex.php | 3 +- .../Base/UnknownTypeExceptionTest.php | 3 +- tests/Utilities/RepositoryTest.php | 1 - 10 files changed, 29 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6658b2..919a155 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,3 +8,4 @@ Common and useful classes, methods, exceptions etc. 3. Docker: use project-related binaries globally 4. StyleCI & PHP Coding Standards Fixer: update configuration 5. Documentation > Docker > add paragraph for PHP Coding Standards Fixer +6. Coding standard > fix automatically diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index af79c27..29c146c 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -24,9 +24,8 @@ class Bundle * @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template" * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" * @param string $extension (optional) Extension of the view / template (default: "html.twig") - * @return string|null - * * @throws IncorrectBundleNameException + * @return string|null */ public static function getBundleViewPath($viewPath, $bundleName, $extension = 'html.twig') { @@ -65,9 +64,8 @@ class Bundle * Returns short name of bundle (without "Bundle") * * @param string $fullBundleName Full name of the bundle, e.g. "MyExtraBundle" - * @return string|null - * * @throws IncorrectBundleNameException + * @return string|null */ public static function getShortBundleName($fullBundleName) { diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index c19c530..210b7f5 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -68,9 +68,8 @@ class Date * The dates are returned in an array with indexes 'start' and 'end'. * * @param int $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. - * @return null|DatePeriod - * * @throws Exception + * @return null|DatePeriod */ public static function getDatesForPeriod($period) { @@ -221,8 +220,8 @@ class Date /** * Returns current day of week * - * @return int * @throws UnknownDatePartTypeException + * @return int */ public static function getCurrentDayOfWeek() { @@ -243,8 +242,8 @@ class Date * @param int $month The month value * @param int $day The day value * - * @return int * @throws UnknownDatePartTypeException + * @return int */ public static function getDayOfWeek($year, $month, $day) { @@ -488,9 +487,8 @@ class Date * @param string $intervalTemplate (optional) Template used to build date interval. It should contain "%d" as the * placeholder which is replaced with a number that represents each iteration. * Default: interval for days. - * @return array - * * @throws Exception + * @return array */ public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD') { @@ -535,9 +533,8 @@ class Date * @param int $end (optional) End of random partition * @param string $intervalTemplate (optional) Template used to build date interval. The placeholder is replaced * with next, iterated value. - * @return DateTime - * * @throws Exception + * @return DateTime */ public static function getRandomDate(DateTime $startDate = null, $start = 1, $end = 100, $intervalTemplate = 'P%sD') { diff --git a/src/Utilities/MimeTypes.php b/src/Utilities/MimeTypes.php index 9951d1a..0c15394 100644 --- a/src/Utilities/MimeTypes.php +++ b/src/Utilities/MimeTypes.php @@ -759,9 +759,8 @@ class MimeTypes * Returns mime type of given file * * @param string $filePath Path of the file to check - * @return string - * * @throws \RuntimeException + * @return string */ public static function getMimeType($filePath) { diff --git a/src/Utilities/Miscellaneous.php b/src/Utilities/Miscellaneous.php index da612e4..b77222d 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -1312,10 +1312,9 @@ class Miscellaneous * Returns inverted value of color for given color * * @param string $color Hexadecimal value of color to invert (with or without hash), e.g. "dd244c" or "#22a5fe" - * @return string - * * @throws IncorrectColorHexLengthException * @throws InvalidColorHexValueException + * @return string */ public static function getInvertedColor($color) { diff --git a/src/Utilities/QueryBuilderUtility.php b/src/Utilities/QueryBuilderUtility.php index 037a9bd..8485b05 100644 --- a/src/Utilities/QueryBuilderUtility.php +++ b/src/Utilities/QueryBuilderUtility.php @@ -158,8 +158,8 @@ class QueryBuilderUtility * @param array|ArrayCollection $entities The entities to delete * @param bool $flushDeleted (optional) If is set to true, flushes the deleted objects (default * behaviour). Otherwise - not. - * @return bool * @throws OptimisticLockException + * @return bool */ public static function deleteEntities(EntityManager $entityManager, $entities, $flushDeleted = true) { diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 849a879..7d969cf 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -34,9 +34,8 @@ class Reflection * @param object|string $class The object or name of object's class * @param bool $withoutInheritance (optional) If is set to true, only methods for given class are returned. * Otherwise - all methods, with inherited methods too. - * @return array - * * @throws ReflectionException + * @return array */ public static function getMethods($class, $withoutInheritance = false) { @@ -66,9 +65,8 @@ class Reflection * Returns constants of given class / object * * @param object|string $class The object or name of object's class - * @return array - * * @throws ReflectionException + * @return array */ public static function getConstants($class) { @@ -82,9 +80,8 @@ class Reflection * Constants whose values are integers are considered only. * * @param object|string $class The object or name of object's class - * @return int|null - * * @throws ReflectionException + * @return int|null */ public static function getMaxNumberConstant($class) { @@ -110,9 +107,8 @@ class Reflection * * @param object|string $class The object or name of object's class * @param string $method Name of the method to find - * @return bool - * * @throws ReflectionException + * @return bool */ public static function hasMethod($class, $method) { @@ -126,9 +122,8 @@ class Reflection * * @param object|string $class The object or name of object's class * @param string $property Name of the property to find - * @return bool - * * @throws ReflectionException + * @return bool */ public static function hasProperty($class, $property) { @@ -142,9 +137,8 @@ class Reflection * * @param object|string $class The object or name of object's class * @param string $constant Name of the constant to find - * @return bool - * * @throws ReflectionException + * @return bool */ public static function hasConstant($class, $constant) { @@ -158,9 +152,8 @@ class Reflection * * @param object|string $class The object or name of object's class * @param string $constant Name of the constant that contains a value - * @return mixed - * * @throws ReflectionException + * @return mixed */ public static function getConstantValue($class, $constant) { @@ -182,9 +175,8 @@ class Reflection * dot-separated, e.g. "invoice.user.email". * @param bool $force (optional) If is set to true, try to retrieve value even if the object doesn't have * property. Otherwise - not. - * @return mixed - * * @throws ReflectionException + * @return mixed */ public static function getPropertyValue($object, $property, $force = false) { @@ -300,9 +292,8 @@ class Reflection * @param string $property Name of the property that contains a value * @param bool $force (optional) If is set to true, try to retrieve value even if the * object does not have property. Otherwise - not. - * @return array - * * @throws ReflectionException + * @return array */ public static function getPropertyValues($objects, $property, $force = false) { @@ -461,9 +452,8 @@ class Reflection * constants. By default all properties are returned. * @param bool $includeParents (optional) If is set to true, properties of parent classes are * included (recursively). Otherwise - not. - * @return array|ReflectionProperty - * * @throws ReflectionException + * @return array|ReflectionProperty */ public static function getProperties($source, $filter = null, $includeParents = false) { @@ -496,9 +486,8 @@ class Reflection * Returns a parent class or false if there is no parent class * * @param array|object|string $source An array of objects, namespaces, object or namespace - * @return ReflectionClass|bool - * * @throws ReflectionException + * @return ReflectionClass|bool */ public static function getParentClass($source) { @@ -514,8 +503,8 @@ class Reflection * * @param array|object|string $class Class who child classes should be returned. An array of objects, strings, * object or string. - * @return array|null * @throws CannotResolveClassNameException + * @return array|null */ public static function getChildClasses($class) { @@ -569,11 +558,10 @@ class Reflection * * @param array|object|string $parentClass Class who child class should be returned. An array of objects, * namespaces, object or namespace. - * @return mixed - * * @throws CannotResolveClassNameException * @throws MissingChildClassesException * @throws TooManyChildClassesException + * @return mixed */ public static function getOneChildClass($parentClass) { @@ -605,9 +593,8 @@ class Reflection * @param string $property Name of the property * @param int $filter (optional) Filter of properties. Uses ReflectionProperty class constants. * By default all properties are allowed / processed. - * @return null|ReflectionProperty - * * @throws ReflectionException + * @return null|ReflectionProperty */ public static function getProperty($class, $property, $filter = null) { @@ -633,10 +620,9 @@ class Reflection * @param array|string $trait An array of strings or string * @param bool $verifyParents If is set to true, parent classes are verified if they use given * trait. Otherwise - not. - * @return bool|null - * * @throws CannotResolveClassNameException * @throws ReflectionException + * @return bool|null */ public static function usesTrait($class, $trait, $verifyParents = false) { @@ -678,9 +664,8 @@ class Reflection * If given class does not extend another, returns null. * * @param array|object|string $class An array of objects, namespaces, object or namespace - * @return string|null - * * @throws ReflectionException + * @return string|null */ public static function getParentClassName($class) { diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 638552e..cdec276 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -766,10 +766,9 @@ class Regex * @param string $color Color to verify * @param bool $throwException (optional) If is set to true, throws an exception if given color is invalid * (default behaviour). Otherwise - not. - * @return string|bool - * * @throws IncorrectColorHexLengthException * @throws InvalidColorHexValueException + * @return string|bool */ public static function getValidColorHexValue($color, $throwException = true) { diff --git a/tests/Exception/Base/UnknownTypeExceptionTest.php b/tests/Exception/Base/UnknownTypeExceptionTest.php index 78b8120..07e2da1 100644 --- a/tests/Exception/Base/UnknownTypeExceptionTest.php +++ b/tests/Exception/Base/UnknownTypeExceptionTest.php @@ -82,9 +82,8 @@ class TestService * Returns translated type (for testing purposes) * * @param string $type Type of something (for testing purposes) - * @return string - * * @throws UnknownTestTypeException + * @return string */ public function getTranslatedType($type) { diff --git a/tests/Utilities/RepositoryTest.php b/tests/Utilities/RepositoryTest.php index 3739a30..4a942bf 100644 --- a/tests/Utilities/RepositoryTest.php +++ b/tests/Utilities/RepositoryTest.php @@ -353,7 +353,6 @@ class RepositoryTest extends BaseTestCase yield[ [ - [], [], [ From fc7df571e28d63b9097d0f2753c19c2af4117c2f Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 14:34:00 +0200 Subject: [PATCH 68/70] StyleCI configuration > fix bug "The provided fixer 'binary_operator_spaces' cannot be enabled again because it was already enabled" --- .styleci.yml | 1 - CHANGELOG.md | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.styleci.yml b/.styleci.yml index e8497fb..01cf726 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,7 +1,6 @@ preset: symfony enabled: - - binary_operator_spaces - concat_with_spaces - phpdoc_add_missing_param_annotation - phpdoc_order diff --git a/CHANGELOG.md b/CHANGELOG.md index 919a155..d4b49ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,3 +9,4 @@ Common and useful classes, methods, exceptions etc. 4. StyleCI & PHP Coding Standards Fixer: update configuration 5. Documentation > Docker > add paragraph for PHP Coding Standards Fixer 6. Coding standard > fix automatically +7. StyleCI configuration > fix bug "The provided fixer 'binary_operator_spaces' cannot be enabled again because it was already enabled" From f4c12661b4224ca5041c9e15a1c486656631213e Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 14:36:33 +0200 Subject: [PATCH 69/70] StyleCI configuration > fix bug "The provided fixer 'concat_with_spaces' cannot be enabled at the same time as 'concat_without_spaces'" --- .php_cs.dist | 2 +- .styleci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index fe6e788..3b03a36 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -14,7 +14,7 @@ return PhpCsFixer\Config::create() ], 'blank_line_before_return' => false, 'cast_spaces' => false, - // "concat_space" instead of "concat_with_spaces" option used by StyleCI + // "concat_space" instead of "concat_without_spaces" option used by StyleCI 'concat_space' => [ 'spacing' => 'one', ], diff --git a/.styleci.yml b/.styleci.yml index 01cf726..4d03130 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,13 +1,13 @@ preset: symfony enabled: - - concat_with_spaces - phpdoc_add_missing_param_annotation - phpdoc_order disabled: - blank_line_before_return - cast_spaces + - concat_without_spaces - phpdoc_align - phpdoc_separation - phpdoc_summary From 107480d01b8ec0a0061caaeabc02ef6cac3e363d Mon Sep 17 00:00:00 2001 From: Meritoo Date: Sat, 16 Jun 2018 14:43:16 +0200 Subject: [PATCH 70/70] StyleCI > disable & remove --- .php_cs.dist | 1 - .styleci.yml | 14 -------------- CHANGELOG.md | 1 + README.md | 2 +- 4 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 .styleci.yml diff --git a/.php_cs.dist b/.php_cs.dist index 3b03a36..d2f2f3c 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -14,7 +14,6 @@ return PhpCsFixer\Config::create() ], 'blank_line_before_return' => false, 'cast_spaces' => false, - // "concat_space" instead of "concat_without_spaces" option used by StyleCI 'concat_space' => [ 'spacing' => 'one', ], diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 4d03130..0000000 --- a/.styleci.yml +++ /dev/null @@ -1,14 +0,0 @@ -preset: symfony - -enabled: - - phpdoc_add_missing_param_annotation - - phpdoc_order - -disabled: - - blank_line_before_return - - cast_spaces - - concat_without_spaces - - phpdoc_align - - phpdoc_separation - - phpdoc_summary - - trim_array_spaces diff --git a/CHANGELOG.md b/CHANGELOG.md index d4b49ec..589e02f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,4 @@ Common and useful classes, methods, exceptions etc. 5. Documentation > Docker > add paragraph for PHP Coding Standards Fixer 6. Coding standard > fix automatically 7. StyleCI configuration > fix bug "The provided fixer 'binary_operator_spaces' cannot be enabled again because it was already enabled" +8. StyleCI > disable & remove diff --git a/README.md b/README.md index d74866d..382b117 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Meritoo Common Library Common and useful classes, methods, exceptions etc. -[![Travis](https://img.shields.io/travis/rust-lang/rust.svg?style=flat-square)](https://travis-ci.org/meritoo/common-library) [![Packagist](https://img.shields.io/packagist/v/meritoo/common-library.svg?style=flat-square)](https://packagist.org/packages/meritoo/common-library) [![StyleCI](https://styleci.io/repos/101790028/shield?branch=master)](https://styleci.io/repos/101790028) [![license](https://img.shields.io/github/license/meritoo/common-library.svg?style=flat-square)](https://github.com/meritoo/common-library) [![GitHub commits](https://img.shields.io/github/commits-since/meritoo/common-library/0.0.1.svg?style=flat-square)](https://github.com/meritoo/common-library) [![Coverage Status](https://coveralls.io/repos/github/meritoo/common-library/badge.svg?branch=master)](https://coveralls.io/github/meritoo/common-library?branch=master) +[![Travis](https://img.shields.io/travis/rust-lang/rust.svg?style=flat-square)](https://travis-ci.org/meritoo/common-library) [![Packagist](https://img.shields.io/packagist/v/meritoo/common-library.svg?style=flat-square)](https://packagist.org/packages/meritoo/common-library) [![license](https://img.shields.io/github/license/meritoo/common-library.svg?style=flat-square)](https://github.com/meritoo/common-library) [![GitHub commits](https://img.shields.io/github/commits-since/meritoo/common-library/0.0.1.svg?style=flat-square)](https://github.com/meritoo/common-library) [![Coverage Status](https://coveralls.io/repos/github/meritoo/common-library/badge.svg?branch=master)](https://coveralls.io/github/meritoo/common-library?branch=master) # Installation