diff --git a/.docker/config/Dockerfile b/.docker/config/Dockerfile deleted file mode 100644 index 13802c4..0000000 --- a/.docker/config/Dockerfile +++ /dev/null @@ -1,64 +0,0 @@ -FROM php:5.5-cli - -# -# Tools & libraries -# -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/* - -# -# PHP extensions -# -RUN docker-php-ext-install \ - zip \ - intl \ - mbstring - -# -# PHP configuration: -# - default configuration -# - timezone -# -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 - -# -# Phing -# -RUN pear channel-discover pear.phing.info \ - && pear install [--alldeps] phing/phing - -# -# 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;" \ - && 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/* - -# -# 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 diff --git a/.env b/.env deleted file mode 100644 index c6eb126..0000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -TIMEZONE=Europe/Warsaw diff --git a/.env.dist b/.env.dist new file mode 100644 index 0000000..4c093b4 --- /dev/null +++ b/.env.dist @@ -0,0 +1,15 @@ +# ----------------------------------------------------------------------------- +### Docker +# ----------------------------------------------------------------------------- + +# +# All containers +# +DOCKER_CONTAINER_OWNER=meritoo +DOCKER_CONTAINER_PROJECT=common-library + +# +# PHP configuration: +# - timezone +# +TIMEZONE=Europe/Warsaw diff --git a/.gitignore b/.gitignore index 0bd0569..8f1b748 100644 --- a/.gitignore +++ b/.gitignore @@ -1,51 +1,58 @@ -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ +# Environment-related parameters +# ------------------------------------------------------------------------------ +.env + + +# ------------------------------------------------------------------------------ ### Vendors -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /vendor/ -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Composer -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /composer.lock /composer.phar -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Phing -# ---------------------------------------------------------------------------------------------------------------------- -/.phing/properties +# ------------------------------------------------------------------------------ +/phing/properties -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### PHPUnit -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /phpunit.xml -# ---------------------------------------------------------------------------------------------------------------------- -### PHP Coding Standards Fixer generated files -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ +### PHP Coding Standards Fixer +# ------------------------------------------------------------------------------ +/.php_cs /.php_cs.cache -# ---------------------------------------------------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- ### Build files -# ---------------------------------------------------------------------------------------------------------------------- -/.build/ +# ----------------------------------------------------------------------------- +/build/ -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Generated databases -# ---------------------------------------------------------------------------------------------------------------------- -/.data/tmp +# ------------------------------------------------------------------------------ +/data/tmp *.sql *.sqlite -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Compiled source -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ *.com *.class *.dll @@ -54,23 +61,22 @@ *.so -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Shell scripts -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /*.sh -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### JetBrains -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ /.idea -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### NetBeans template -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ nbproject/private/ -build/ nbbuild/ dist/ nbdist/ @@ -78,9 +84,9 @@ nbactions.xml .nb-gradle/ -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### OSX template -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ .DS_Store .AppleDouble .LSOverride @@ -107,9 +113,9 @@ Temporary Items .apdisk -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Linux template -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ *~ # temporary files which can be created if a process still has a handle open of a deleted file @@ -122,9 +128,9 @@ Temporary Items .Trash-* -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ ### Windows template -# ---------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ # Windows image file caches Thumbs.db ehthumbs.db diff --git a/.php_cs.dist b/.php_cs.dist index 4e1c7bd..d2f2f3c 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,20 @@ $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' => [ '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 deleted file mode 100644 index e594180..0000000 --- a/.styleci.yml +++ /dev/null @@ -1,8 +0,0 @@ -preset: symfony - -disabled: - - phpdoc_annotation_without_dot - - cast_spaces - - concat_without_spaces - - blank_line_before_return - - trim_array_spaces diff --git a/.travis.yml b/.travis.yml index 5cc2936..eff6130 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,14 @@ php: - 5.6 - 7.0 - 7.1 + - 7.2 + +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 +- travis_wait 30 composer install script: - php ./vendor/bin/phpunit diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..65d5b3c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,49 @@ +# Meritoo Common Library + +Common and useful classes, methods, exceptions etc. + +# 0.1.3 + +1. Tests > refactoring & minor improvements +2. Utilities > CssSelector > useful methods related to CSS selectors +3. Utilities > Bootstrap4CssSelector > useful methods related to CSS selectors and the Bootstrap4 (front-end component library) + +# 0.1.2 + +1. Documentation > Value Objects +2. Docker > improve performance +3. Utilities > Reflection > setPropertyValue() method > sets value of given property + +# 0.1.1 + +1. TravisCI > run using PHP 7.2 too +2. ValueObject > class Version > represents version of software +3. Move version of this package to `VERSION` file (from `composer.json` file) + +# 0.1.0 + +1. Composer > support/require PHP 5.6+ (instead of 5.5.9+) +2. Docker > rename `php-cli` service to `php` +3. Exceptions > create instance of exception using static `create()` method (instead of constructor) +4. Documentation > Exceptions + +# 0.0.21 + +1. Composer > require ext-pcre +2. Arrays > minor refactoring +3. Update @author and @copyright in classes' descriptions + +# 0.0.20 + +1. Collection > add() method > treat empty string as not provided index (same as null) + +# 0.0.19 + +1. Add this changelog +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 +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 3530a72..ab106f4 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # 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 +# Installation In your `composer.json` add address of repository into `repositories` section: @@ -20,107 +21,21 @@ In your `composer.json` add address of repository into `repositories` section: Run [Composer](https://getcomposer.org) to install this package in your project: ```bash -$ composer require wiosna-dev/common-library +composer require wiosna-dev/common-library ``` -> How to install Composer: https://getcomposer.org/download +> [How to install Composer?](https://getcomposer.org/download) -## Rebuilding project and tests running +# Usage -```bash -$ docker-compose up -d -$ docker-compose exec php-cli phing -``` +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. [Exceptions](docs/Static-methods.md) +4. [Static methods](docs/Static-methods.md) +5. [Value Objects](docs/Value-Objects.md) -> What is Docker? https://www.docker.com/what-docker +# Development -## 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/VERSION b/VERSION new file mode 100644 index 0000000..b1e80bb --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.3 diff --git a/build.xml b/build.xml index fccc179..d65367b 100644 --- a/build.xml +++ b/build.xml @@ -2,12 +2,12 @@ - + - + - + @@ -18,24 +18,24 @@ - + - + - + - + - + @@ -21,9 +21,9 @@ depends="app:composer, app:vendors, app:checkout" description="Prepares app to build." /> - - - + + + @@ -42,7 +42,14 @@ + + + + + + + @@ -68,6 +75,8 @@ + + diff --git a/.phing/properties.dist b/phing/properties.dist similarity index 79% rename from .phing/properties.dist rename to phing/properties.dist index db05a3a..dc0463c 100644 --- a/.phing/properties.dist +++ b/phing/properties.dist @@ -31,7 +31,7 @@ assets.installWithSymlink = true # The cache:clear command should always be called with the --no-warmup option. Warmup should be done via the cache:warmup command. # https://github.com/symfony/symfony/blob/master/UPGRADE-3.3.md#frameworkbundle # -# Krzysztof Niziol +# Meritoo # 2017-06-06 # cache.clearWithWarmup = false @@ -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 dir.reports.coverage = ${dir.reports}/phpunit_coverage @@ -81,7 +81,7 @@ dir.reports.coverage = ${dir.reports}/phpunit_coverage # Disabled, because unnecessary right now # phpdocumentor/phpdocumentor cannot be installed via Composer # -# Krzysztof Niziol +# Meritoo # 2017-02-22 # #dir.docs = ${dir.build}/docs @@ -91,40 +91,15 @@ dir.reports.coverage = ${dir.reports}/phpunit_coverage # Data directories # -------------------------------------------------------------------------------- -dir.data.tests = ${dir.data}/tests dir.data.temporary = ${dir.data}/tmp # -------------------------------------------------------------------------------- # Testing # -------------------------------------------------------------------------------- -# Test database path +# Path of the framework used to run unit tests # -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) -# -phpUnit.path = ./vendor/bin/phpunit +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 similarity index 62% rename from .phing/tests.xml rename to phing/tests.xml index 4567626..edd288b 100644 --- a/.phing/tests.xml +++ b/phing/tests.xml @@ -4,19 +4,19 @@ The AutoloaderTask is required to load binaries installed by Composer. The "autoloaderpath" attribute of this task is not required, because it's default value is: vendor/autoload.php. - Krzysztof Niziol + Meritoo 2017-02-23 --> - + - + - + @@ -48,7 +48,7 @@ a) phpdocumentor/phpdocumentor v2.9.0 requires symfony/validator ~2.2 b) symfony/validator ~2.2 causes to remove symfony/symfony 3.* - Krzysztof Niziol + Meritoo 2017-02-22 --> @@ -73,7 +73,7 @@ a) phpdocumentor/phpdocumentor v2.9.0 requires symfony/validator ~2.2 b) symfony/validator ~2.2 causes to remove symfony/symfony 3.* - Krzysztof Niziol + Meritoo 2017-02-22 --> @@ -87,7 +87,7 @@ @@ -103,8 +103,8 @@ - + @@ -113,7 +113,7 @@ a) phpdocumentor/phpdocumentor v2.9.0 requires symfony/validator ~2.2 b) symfony/validator ~2.2 causes to remove symfony/symfony 3.* - Krzysztof Niziol + Meritoo 2017-02-22 @@ -142,7 +142,7 @@ via Composer the Symfony2 standard is not included / available in this package. In this case the PHP Coding Standards Fixer (http://cs.sensiolabs.org) is used. - Krzysztof Niziol + Meritoo 2017-02-22 --> @@ -166,7 +166,7 @@ - - - - - - - - - - - - - - - - - - + - - - - - - - + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index fd0219d..b6d38e5 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,34 @@ - + + + + ./tests/ @@ -30,6 +48,6 @@ - + diff --git a/src/Collection/Collection.php b/src/Collection/Collection.php index 75770c2..ed27103 100644 --- a/src/Collection/Collection.php +++ b/src/Collection/Collection.php @@ -18,8 +18,8 @@ use Meritoo\Common\Utilities\Arrays; * Collection of elements. * It's a set of some elements, e.g. objects. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Collection implements Countable, ArrayAccess, IteratorAggregate { @@ -109,7 +109,7 @@ class Collection implements Countable, ArrayAccess, IteratorAggregate */ public function add($element, $index = null) { - if (null === $index) { + if (null === $index || '' === $index) { $this->elements[] = $element; } else { $this->elements[$index] = $element; diff --git a/src/Exception/Base/UnknownTypeException.php b/src/Exception/Base/UnknownTypeException.php index 0a4c5e9..ea860ca 100644 --- a/src/Exception/Base/UnknownTypeException.php +++ b/src/Exception/Base/UnknownTypeException.php @@ -15,27 +15,28 @@ use Meritoo\Common\Utilities\Arrays; /** * An exception used while type of something is unknown * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ abstract class UnknownTypeException extends Exception { /** - * Class constructor + * Creates exception * * @param string|int $unknownType The unknown type of something (value of constant) * @param BaseType $typeInstance An instance of class that contains type of the something * @param string $typeName Name of the something + * @return UnknownTypeException */ - public function __construct($unknownType, BaseType $typeInstance, $typeName) + public static function create($unknownType, BaseType $typeInstance, $typeName) { - $allTypes = $typeInstance->getAll(); - $types = Arrays::values2string($allTypes, '', ', '); - $template = 'The \'%s\' type of %s is unknown. Probably doesn\'t exist or there is a typo. You should use one' . ' of these types: %s.'; + $allTypes = $typeInstance->getAll(); + $types = Arrays::values2string($allTypes, '', ', '); $message = sprintf(sprintf($template, $unknownType, $typeName, $types)); - parent::__construct($message); + + return new static($message); } } diff --git a/src/Exception/Bundle/IncorrectBundleNameException.php b/src/Exception/Bundle/IncorrectBundleNameException.php new file mode 100644 index 0000000..2c34199 --- /dev/null +++ b/src/Exception/Bundle/IncorrectBundleNameException.php @@ -0,0 +1,36 @@ + + * @copyright Meritoo + */ +class IncorrectBundleNameException extends Exception +{ + /** + * Creates exception + * + * @param string $bundleName Incorrect name of bundle + * @return IncorrectBundleNameException + */ + public static function create($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); + + return new static($message); + } +} diff --git a/src/Exception/Date/UnknownDatePartTypeException.php b/src/Exception/Date/UnknownDatePartTypeException.php deleted file mode 100644 index d25a610..0000000 --- a/src/Exception/Date/UnknownDatePartTypeException.php +++ /dev/null @@ -1,32 +0,0 @@ - - * @copyright Meritoo.pl - */ -class UnknownDatePartTypeException extends UnknownTypeException -{ - /** - * Class constructor - * - * @param string $unknownDatePart Type of date part, e.g. "year". One of DatePartType class constants. - * @param string $value Incorrect value - */ - public function __construct($unknownDatePart, $value) - { - parent::__construct($unknownDatePart, new DatePartType(), sprintf('date part (with value %s)', $value)); - } -} diff --git a/src/Exception/File/EmptyFileException.php b/src/Exception/File/EmptyFileException.php index 14734d7..4ff9441 100644 --- a/src/Exception/File/EmptyFileException.php +++ b/src/Exception/File/EmptyFileException.php @@ -11,21 +11,22 @@ namespace Meritoo\Common\Exception\File; /** * An exception used while file with given path is empty (has no content) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class EmptyFileException extends \Exception { /** - * Class constructor + * Creates exception * * @param string $emptyFilePath Path of the empty file + * @return EmptyFileException */ - public function __construct($emptyFilePath) + public static function create($emptyFilePath) { $template = 'File with path \'%s\' is empty (has no content). Did you provide path of proper file?'; $message = sprintf($template, $emptyFilePath); - parent::__construct($message); + return new static($message); } } diff --git a/src/Exception/File/EmptyFilePathException.php b/src/Exception/File/EmptyFilePathException.php index 5f80e6b..33333f5 100644 --- a/src/Exception/File/EmptyFilePathException.php +++ b/src/Exception/File/EmptyFilePathException.php @@ -11,16 +11,16 @@ namespace Meritoo\Common\Exception\File; /** * An exception used while path of given file is empty * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class EmptyFilePathException extends \Exception { /** - * Class constructor + * Creates exception */ - public function __construct() + public static function create() { - parent::__construct('Path of the file is empty. Did you provide path of proper file?'); + return new static('Path of the file is empty. Did you provide path of proper file?'); } } diff --git a/src/Exception/File/NotExistingFileException.php b/src/Exception/File/NotExistingFileException.php index 51c6fa3..c64a8f8 100644 --- a/src/Exception/File/NotExistingFileException.php +++ b/src/Exception/File/NotExistingFileException.php @@ -11,21 +11,22 @@ namespace Meritoo\Common\Exception\File; /** * An exception used while file with given path does not exist * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class NotExistingFileException extends \Exception { /** - * Class constructor + * Creates exception * * @param string $notExistingFilePath Path of not existing (or not readable) file + * @return NotExistingFileException */ - public function __construct($notExistingFilePath) + public static function create($notExistingFilePath) { $template = 'File with path \'%s\' does not exist (or is not readable). Did you provide path of proper file?'; $message = sprintf($template, $notExistingFilePath); - parent::__construct($message); + return new static($message); } } diff --git a/src/Exception/Method/DisabledMethodException.php b/src/Exception/Method/DisabledMethodException.php index ca98911..fd0ac7b 100644 --- a/src/Exception/Method/DisabledMethodException.php +++ b/src/Exception/Method/DisabledMethodException.php @@ -13,18 +13,19 @@ use Exception; /** * An exception used while method cannot be called, because is disabled * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class DisabledMethodException extends Exception { /** - * Class constructor + * Creates exception * * @param string $disabledMethod Name of the disabled method * @param string $alternativeMethod (optional) Name of the alternative method + * @return DisabledMethodException */ - public function __construct($disabledMethod, $alternativeMethod = '') + public static function create($disabledMethod, $alternativeMethod = '') { $template = 'Method %s() cannot be called, because is disabled.'; @@ -33,6 +34,7 @@ class DisabledMethodException extends Exception } $message = sprintf($template, $disabledMethod, $alternativeMethod); - parent::__construct($message); + + return new static($message); } } diff --git a/src/Exception/Reflection/CannotResolveClassNameException.php b/src/Exception/Reflection/CannotResolveClassNameException.php index 21708a2..dee9dde 100644 --- a/src/Exception/Reflection/CannotResolveClassNameException.php +++ b/src/Exception/Reflection/CannotResolveClassNameException.php @@ -13,20 +13,21 @@ use Exception; /** * An exception used while name of class or trait cannot be resolved * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class CannotResolveClassNameException extends Exception { /** - * Class constructor + * Creates exception * * @param array|object|string $source Source of the class's / trait's name. It can be an array of objects, * namespaces, object or namespace. * @param bool $forClass (optional) If is set to true, message of this exception for class is * prepared. Otherwise - for trait. + * @return CannotResolveClassNameException */ - public function __construct($source, $forClass = true) + public static function create($source, $forClass = true) { $forWho = 'trait'; $value = ''; @@ -42,6 +43,6 @@ class CannotResolveClassNameException extends Exception $template = 'Name of %s from given \'%s\'%s cannot be resolved. Is there everything ok?'; $message = sprintf($template, $forWho, gettype($source), $value); - parent::__construct($message); + return new static($message); } } diff --git a/src/Exception/Reflection/MissingChildClassesException.php b/src/Exception/Reflection/MissingChildClassesException.php index 73c13b6..27183ff 100644 --- a/src/Exception/Reflection/MissingChildClassesException.php +++ b/src/Exception/Reflection/MissingChildClassesException.php @@ -14,18 +14,19 @@ use Meritoo\Common\Utilities\Reflection; /** * An exception used while given class has no child classes * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class MissingChildClassesException extends Exception { /** - * Class constructor + * Creates exception * * @param array|object|string $parentClass Class that hasn't child classes, but it should. An array of objects, * strings, object or string. + * @return MissingChildClassesException */ - public function __construct($parentClass) + public static function create($parentClass) { $template = 'The \'%s\' class requires one child class at least who will extend her (maybe is an abstract' . ' class), but the child classes are missing. Did you forget to extend this class?'; @@ -33,6 +34,6 @@ class MissingChildClassesException extends Exception $parentClassName = Reflection::getClassName($parentClass); $message = sprintf($template, $parentClassName); - parent::__construct($message); + return new static($message); } } diff --git a/src/Exception/Reflection/NotExistingPropertyException.php b/src/Exception/Reflection/NotExistingPropertyException.php new file mode 100644 index 0000000..4b7484f --- /dev/null +++ b/src/Exception/Reflection/NotExistingPropertyException.php @@ -0,0 +1,33 @@ + + * @copyright Meritoo + */ +class NotExistingPropertyException extends \Exception +{ + /** + * Creates exception + * + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * @return NotExistingPropertyException + */ + public static function create($object, $property) + { + $template = 'Property \'%s\' does not exist in instance of class \'%s\'. Did you use proper name of property?'; + $message = sprintf($template, $property, get_class($object)); + + return new static($message); + } +} diff --git a/src/Exception/Reflection/TooManyChildClassesException.php b/src/Exception/Reflection/TooManyChildClassesException.php index b5a4f13..f06dab2 100644 --- a/src/Exception/Reflection/TooManyChildClassesException.php +++ b/src/Exception/Reflection/TooManyChildClassesException.php @@ -14,19 +14,20 @@ use Meritoo\Common\Utilities\Reflection; /** * An exception used while given class has more than one child class * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class TooManyChildClassesException extends Exception { /** - * Class constructor + * Creates exception * * @param array|object|string $parentClass Class that has more than one child class, but it shouldn't. An array * of objects, strings, object or string. * @param array $childClasses Child classes + * @return TooManyChildClassesException */ - public function __construct($parentClass, array $childClasses) + public static function create($parentClass, array $childClasses) { $template = "The '%s' class requires one child class at most who will extend her, but more than one child" . " class was found:\n- %s\n\nWhy did you create more than one classes that extend '%s' class?"; @@ -34,6 +35,6 @@ class TooManyChildClassesException extends Exception $parentClassName = Reflection::getClassName($parentClass); $message = sprintf($template, $parentClassName, implode("\n- ", $childClasses), $parentClassName); - parent::__construct($message); + return new static($message); } } diff --git a/src/Exception/Regex/IncorrectColorHexLengthException.php b/src/Exception/Regex/IncorrectColorHexLengthException.php index 89ee485..86af0a3 100644 --- a/src/Exception/Regex/IncorrectColorHexLengthException.php +++ b/src/Exception/Regex/IncorrectColorHexLengthException.php @@ -11,22 +11,24 @@ namespace Meritoo\Common\Exception\Regex; /** * An exception used while length of given hexadecimal value of color is incorrect * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class IncorrectColorHexLengthException extends \Exception { /** - * Class constructor + * Creates exception * * @param string $color Incorrect hexadecimal value of color + * @return IncorrectColorHexLengthException */ - public function __construct($color) + public static function create($color) { $template = 'Length of hexadecimal value of color \'%s\' is incorrect. It\'s %d, but it should be 3 or 6.' . ' Is there everything ok?'; $message = sprintf($template, $color, strlen($color)); - parent::__construct($message); + + return new static($message); } } diff --git a/src/Exception/Regex/InvalidColorHexValueException.php b/src/Exception/Regex/InvalidColorHexValueException.php index f17771a..69b1682 100644 --- a/src/Exception/Regex/InvalidColorHexValueException.php +++ b/src/Exception/Regex/InvalidColorHexValueException.php @@ -11,19 +11,21 @@ namespace Meritoo\Common\Exception\Regex; /** * An exception used while given hexadecimal value of color is invalid * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class InvalidColorHexValueException extends \Exception { /** - * Class constructor + * Creates exception * * @param string $color Invalid hexadecimal value of color + * @return InvalidColorHexValueException */ - public function __construct($color) + public static function create($color) { $message = sprintf('Hexadecimal value of color \'%s\' is invalid. Is there everything ok?', $color); - parent::__construct($message); + + return new static($message); } } diff --git a/src/Exception/Regex/InvalidHtmlAttributesException.php b/src/Exception/Regex/InvalidHtmlAttributesException.php new file mode 100644 index 0000000..cac3480 --- /dev/null +++ b/src/Exception/Regex/InvalidHtmlAttributesException.php @@ -0,0 +1,31 @@ + + * @copyright Meritoo + */ +class InvalidHtmlAttributesException extends \Exception +{ + /** + * Creates exception + * + * @param string $htmlAttributes Invalid html attributes + * @return InvalidHtmlAttributesException + */ + public static function create($htmlAttributes) + { + $message = sprintf('HTML attributes \'%s\' are invalid. Is there everything ok?', $htmlAttributes); + + return new static($message); + } +} diff --git a/src/Exception/Regex/InvalidUrlException.php b/src/Exception/Regex/InvalidUrlException.php index ba658e7..080fcf7 100644 --- a/src/Exception/Regex/InvalidUrlException.php +++ b/src/Exception/Regex/InvalidUrlException.php @@ -1,23 +1,31 @@ - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class InvalidUrlException extends \Exception { /** - * Class constructor + * Creates exception * * @param string $url Invalid url + * @return InvalidUrlException */ - public function __construct($url) + public static function create($url) { $message = sprintf('Url \'%s\' is invalid. Is there everything ok?', $url); - parent::__construct($message); + + return new static($message); } } diff --git a/src/Exception/Type/UnknownDatePartTypeException.php b/src/Exception/Type/UnknownDatePartTypeException.php new file mode 100644 index 0000000..8155a50 --- /dev/null +++ b/src/Exception/Type/UnknownDatePartTypeException.php @@ -0,0 +1,36 @@ + + * @copyright Meritoo + */ +class UnknownDatePartTypeException extends UnknownTypeException +{ + /** + * Creates exception + * + * @param string $unknownDatePart Unknown type of date part + * @param string $value Incorrect value + * @return UnknownDatePartTypeException + */ + public static function createException($unknownDatePart, $value) + { + /* @var UnknownDatePartTypeException $exception */ + $exception = parent::create($unknownDatePart, new DatePartType(), sprintf('date part (with value %s)', $value)); + + return $exception; + } +} diff --git a/src/Exception/Type/UnknownOopVisibilityTypeException.php b/src/Exception/Type/UnknownOopVisibilityTypeException.php index 4ac7165..f8eb21d 100644 --- a/src/Exception/Type/UnknownOopVisibilityTypeException.php +++ b/src/Exception/Type/UnknownOopVisibilityTypeException.php @@ -1,5 +1,11 @@ - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class UnknownOopVisibilityTypeException extends UnknownTypeException { /** - * {@inheritdoc} + * Creates exception + * + * @param string $unknownType Unknown visibility of a property, a method or (as of PHP 7.1.0) a constant + * @return UnknownOopVisibilityTypeException */ - public function __construct($unknownType) + public static function createException($unknownType) { - parent::__construct($unknownType, new OopVisibilityType(), 'OOP-related visibility'); + /* @var UnknownOopVisibilityTypeException $exception */ + $exception = parent::create($unknownType, new OopVisibilityType(), 'OOP-related visibility'); + + return $exception; } } diff --git a/src/Test/Base/BaseTestCase.php b/src/Test/Base/BaseTestCase.php index 0246dad..5f5bb2a 100644 --- a/src/Test/Base/BaseTestCase.php +++ b/src/Test/Base/BaseTestCase.php @@ -14,8 +14,8 @@ use PHPUnit\Framework\TestCase; /** * Base test case with common methods and data providers * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ abstract class BaseTestCase extends TestCase { diff --git a/src/Test/Base/BaseTypeTestCase.php b/src/Test/Base/BaseTypeTestCase.php index 80caa4a..caba26c 100644 --- a/src/Test/Base/BaseTypeTestCase.php +++ b/src/Test/Base/BaseTypeTestCase.php @@ -13,8 +13,8 @@ use Meritoo\Common\Traits\Test\Base\BaseTypeTestCaseTrait; /** * Base test case for the type of something * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ abstract class BaseTypeTestCase extends BaseTestCase { diff --git a/src/Traits/CssSelector/FormCssSelector.php b/src/Traits/CssSelector/FormCssSelector.php new file mode 100644 index 0000000..964ce71 --- /dev/null +++ b/src/Traits/CssSelector/FormCssSelector.php @@ -0,0 +1,110 @@ + + * @copyright Meritoo + */ +trait FormCssSelector +{ + /** + * Returns selector of form based on its name + * + * @param string $formName Name of form (value of the "name" attribute) + * @return string + */ + public static function getFormByNameSelector($formName) + { + $formName = trim($formName); + + if (empty($formName)) { + return ''; + } + + return sprintf('form[name="%s"]', $formName); + } + + /** + * Returns selector of the input field based on its name + * + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldName Name of field (value of the "name" attribute) + * @return string + */ + public static function getInputByNameSelector($formName, $fieldName) + { + $formSelector = static::getFormByNameSelector($formName); + $fieldName = trim($fieldName); + + if (empty($formSelector) || empty($fieldName)) { + return ''; + } + + return sprintf('%s input[name="%s"]', $formSelector, $fieldName); + } + + /** + * Returns selector of the input field based on its ID + * + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldId ID of field (value of the "id" attribute) + * @return string + */ + public static function getInputByIdSelector($formName, $fieldId) + { + $formSelector = static::getFormByNameSelector($formName); + $fieldId = trim($fieldId); + + if (empty($formSelector) || empty($fieldId)) { + return ''; + } + + return sprintf('%s input#%s', $formSelector, $fieldId); + } + + /** + * Returns selector of label + * + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldId ID of field (value of the "id" attribute) + * @return string + */ + public static function getLabelSelector($formName, $fieldId) + { + $formSelector = static::getFormByNameSelector($formName); + $fieldId = trim($fieldId); + + if (empty($formSelector) || empty($fieldId)) { + return ''; + } + + return sprintf('%s label[for="%s"]', $formSelector, $fieldId); + } + + /** + * Returns selector of field-set using index/position of the field-set + * + * @param string $formName Name of form (value of the "name" attribute) + * @param int $fieldSetIndex Index/Position of the field-set + * @return string + */ + public static function getFieldSetByIndexSelector($formName, $fieldSetIndex) + { + $formSelector = static::getFormByNameSelector($formName); + + if (empty($formSelector) || 0 > $fieldSetIndex) { + return ''; + } + + return sprintf('%s fieldset:nth-of-type(%d)', $formSelector, $fieldSetIndex); + } +} diff --git a/src/Traits/Test/Base/BaseTestCaseTrait.php b/src/Traits/Test/Base/BaseTestCaseTrait.php index 6f3f2e5..2ca9539 100644 --- a/src/Traits/Test/Base/BaseTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTestCaseTrait.php @@ -14,14 +14,16 @@ 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 * Created on 2017-11-02 * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ trait BaseTestCaseTrait { @@ -30,7 +32,7 @@ trait BaseTestCaseTrait * * @var string */ - private static $testsDataDirPath = '.data/tests'; + private static $testsDataDirPath = 'data/tests'; /** * Provides an empty value @@ -47,6 +49,20 @@ trait BaseTestCaseTrait yield[[]]; } + /** + * Provides an empty scalar value + * + * @return Generator + */ + public function provideEmptyScalarValue() + { + yield['']; + yield[' ']; + yield[null]; + yield[0]; + yield[false]; + } + /** * Provides boolean value * @@ -103,9 +119,29 @@ 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. + * 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 @@ -137,6 +173,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 @@ -193,6 +230,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( @@ -214,6 +252,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/Traits/Test/Base/BaseTypeTestCaseTrait.php b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php index 460bb5d..5633c8d 100644 --- a/src/Traits/Test/Base/BaseTypeTestCaseTrait.php +++ b/src/Traits/Test/Base/BaseTypeTestCaseTrait.php @@ -14,8 +14,8 @@ use Meritoo\Common\Type\Base\BaseType; /** * Trait for the base test case for the type of something * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ trait BaseTypeTestCaseTrait { diff --git a/src/Type/Base/BaseType.php b/src/Type/Base/BaseType.php index 56f6a19..73ec524 100644 --- a/src/Type/Base/BaseType.php +++ b/src/Type/Base/BaseType.php @@ -14,8 +14,8 @@ use Meritoo\Common\Utilities\Reflection; * Base / abstract type of something, e.g. type of button, order, date etc. * Child class should contain constants - each of them represent one type. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ abstract class BaseType { diff --git a/src/Type/DatePartType.php b/src/Type/DatePartType.php index 5467a4d..dfa91c4 100644 --- a/src/Type/DatePartType.php +++ b/src/Type/DatePartType.php @@ -13,8 +13,8 @@ use Meritoo\Common\Type\Base\BaseType; /** * Type of date part, e.g. "year" * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class DatePartType extends BaseType { diff --git a/src/Utilities/DatePeriod.php b/src/Type/DatePeriod.php similarity index 89% rename from src/Utilities/DatePeriod.php rename to src/Type/DatePeriod.php index 3a87d73..abfe4db 100644 --- a/src/Utilities/DatePeriod.php +++ b/src/Type/DatePeriod.php @@ -6,18 +6,20 @@ * file that was distributed with this source code. */ -namespace Meritoo\Common\Utilities; +namespace Meritoo\Common\Type; use DateTime; +use Meritoo\Common\Type\Base\BaseType; +use Meritoo\Common\Utilities\Date; /** * A date's period. * Contains start and end date of the period. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ -class DatePeriod +class DatePeriod extends BaseType { /** * The period constant: last month @@ -108,17 +110,6 @@ class DatePeriod $this->endDate = $endDate; } - /** - * Returns information if given period is correct - * - * @param int $period The period to verify - * @return bool - */ - public static function isCorrectPeriod($period) - { - return in_array($period, Reflection::getConstants(__CLASS__)); - } - /** * Returns formatted one of the period's date: start date or end date * diff --git a/src/Type/OopVisibilityType.php b/src/Type/OopVisibilityType.php index 59ede6d..1929710 100644 --- a/src/Type/OopVisibilityType.php +++ b/src/Type/OopVisibilityType.php @@ -7,8 +7,8 @@ use Meritoo\Common\Type\Base\BaseType; /** * The visibility of a property, a method or (as of PHP 7.1.0) a constant * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo * * @see http://php.net/manual/en/language.oop5.visibility.php */ diff --git a/src/Utilities/Arrays.php b/src/Utilities/Arrays.php index bdfe20b..dca7434 100644 --- a/src/Utilities/Arrays.php +++ b/src/Utilities/Arrays.php @@ -11,8 +11,8 @@ namespace Meritoo\Common\Utilities; /** * Useful arrays methods * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Arrays { @@ -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; @@ -530,6 +513,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 +613,10 @@ class Arrays */ public static function setKeysAsValues(array $array, $ignoreDuplicatedValues = true) { + /* + * No elements? + * Nothing to do + */ if (empty($array)) { return []; } @@ -682,7 +673,7 @@ class Arrays return null; } - $effect = $array; + $effect = &$array; ksort($effect, $sortFlags); foreach ($effect as &$value) { @@ -831,60 +822,66 @@ class Arrays */ public static function getLastElementsPaths(array $array, $separator = '.', $parentPath = '', $stopIfMatchedBy = '') { + /* + * No elements? + * Nothing to do + */ + if (empty($array)) { + return []; + } + + if (!empty($stopIfMatchedBy)) { + $stopIfMatchedBy = self::makeArray($stopIfMatchedBy); + } + $paths = []; - if (!empty($array)) { - if (!empty($stopIfMatchedBy)) { - $stopIfMatchedBy = self::makeArray($stopIfMatchedBy); + foreach ($array as $key => $value) { + $path = $key; + $stopRecursion = false; + + /* + * If the path of parent element is delivered, + * I have to use it and build longer path + */ + if (!empty($parentPath)) { + $pathTemplate = '%s%s%s'; + $path = sprintf($pathTemplate, $parentPath, $separator, $key); } - foreach ($array as $key => $value) { - $path = $key; - $stopRecursion = false; + /* + * Check if the key or current path matches one of patterns at which the process should be stopped, + * the recursive not used. It means that I have to pass current value and stop processing of the + * array (don't go to the next step). + */ + if (!empty($stopIfMatchedBy)) { + foreach ($stopIfMatchedBy as $rawPattern) { + $pattern = sprintf('|%s|', $rawPattern); - /* - * If the path of parent element is delivered, - * I have to use it and build longer path - */ - if (!empty($parentPath)) { - $pathTemplate = '%s%s%s'; - $path = sprintf($pathTemplate, $parentPath, $separator, $key); - } - - /* - * Check if the key or current path matches one of patterns at which the process should be stopped, - * the recursive not used. It means that I have to pass current value and stop processing of the - * array (don't go to the next step). - */ - if (!empty($stopIfMatchedBy)) { - foreach ($stopIfMatchedBy as $rawPattern) { - $pattern = sprintf('|%s|', $rawPattern); - - if (preg_match($pattern, $key) || preg_match($pattern, $path)) { - $stopRecursion = true; - break; - } + if (preg_match($pattern, $key) || preg_match($pattern, $path)) { + $stopRecursion = true; + break; } } + } - /* - * The value is passed to the returned array if: - * - it's not an array - * or - * - the process is stopped, recursive is not used - */ - if (!is_array($value) || (is_array($value) && empty($value)) || $stopRecursion) { - $paths[$path] = $value; - continue; - } + /* + * The value is passed to the returned array if: + * - it's not an array + * or + * - the process is stopped, recursive is not used + */ + if (!is_array($value) || (is_array($value) && empty($value)) || $stopRecursion) { + $paths[$path] = $value; + continue; + } - /* - * Let's iterate through the next level, using recursive - */ - if (is_array($value)) { - $recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy); - $paths += $recursivePaths; - } + /* + * Let's iterate through the next level, using recursive + */ + if (is_array($value)) { + $recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy); + $paths += $recursivePaths; } } @@ -1083,6 +1080,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/Bootstrap4CssSelector.php b/src/Utilities/Bootstrap4CssSelector.php new file mode 100644 index 0000000..6933274 --- /dev/null +++ b/src/Utilities/Bootstrap4CssSelector.php @@ -0,0 +1,85 @@ + + * @copyright Meritoo + */ +class Bootstrap4CssSelector +{ + /** + * Returns selector of container with field's validation error + * + * @return string + */ + public static function getFieldErrorContainerSelector() + { + return '.invalid-feedback .form-error-message'; + } + + /** + * Returns selector of field's validation error + * + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldId ID of field (value of the "id" attribute) + * @return string + */ + public static function getFieldErrorSelector($formName, $fieldId) + { + $labelSelector = CssSelector::getLabelSelector($formName, $fieldId); + + if (empty($labelSelector)) { + return ''; + } + + $errorContainerSelector = static::getFieldErrorContainerSelector(); + + return sprintf('%s %s', $labelSelector, $errorContainerSelector); + } + + /** + * Returns selector of radio-button's validation error + * + * @param string $formName Name of form (value of the "name" attribute) + * @param int $fieldSetIndex Index/Position of the field-set + * @return string + */ + public static function getRadioButtonErrorSelector($formName, $fieldSetIndex) + { + $fieldSetSelector = CssSelector::getFieldSetByIndexSelector($formName, $fieldSetIndex); + + if (empty($fieldSetSelector)) { + return ''; + } + + $errorContainerSelector = static::getFieldErrorContainerSelector(); + + return sprintf('%s legend.col-form-label %s', $fieldSetSelector, $errorContainerSelector); + } + + /** + * Returns selector of field's group + * + * @param string $formName Name of form (value of the "name" attribute) + * @return string + */ + public static function getFieldGroupSelector($formName) + { + $formSelector = CssSelector::getFormByNameSelector($formName); + + if (empty($formSelector)) { + return ''; + } + + return sprintf('%s .form-group', $formSelector); + } +} diff --git a/src/Utilities/Bundle.php b/src/Utilities/Bundle.php index 12e31cd..105d8d9 100644 --- a/src/Utilities/Bundle.php +++ b/src/Utilities/Bundle.php @@ -8,20 +8,23 @@ namespace Meritoo\Common\Utilities; +use Meritoo\Common\Exception\Bundle\IncorrectBundleNameException; + /** * Useful methods for bundle * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ 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 Name of the bundle, e.g. "MyExtraBundle" - * @param string $extension (optional) Extension of the view / template + * @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle" + * @param string $extension (optional) Extension of the view / template (default: "html.twig") + * @throws IncorrectBundleNameException * @return string|null */ public static function getBundleViewPath($viewPath, $bundleName, $extension = 'html.twig') @@ -34,6 +37,13 @@ class Bundle return null; } + /* + * Given name of bundle is invalid? + */ + if (!Regex::isValidBundleName($bundleName)) { + throw IncorrectBundleNameException::create($bundleName); + } + /* * Path of the view / template doesn't end with given extension? */ @@ -41,6 +51,39 @@ 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" + * @throws IncorrectBundleNameException + * @return string|null + */ + 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/Composer.php b/src/Utilities/Composer.php index 86ff4da..28e91c7 100644 --- a/src/Utilities/Composer.php +++ b/src/Utilities/Composer.php @@ -13,8 +13,8 @@ use stdClass; /** * Useful Composer-related methods (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Composer { diff --git a/src/Utilities/CssSelector.php b/src/Utilities/CssSelector.php new file mode 100644 index 0000000..3051aa5 --- /dev/null +++ b/src/Utilities/CssSelector.php @@ -0,0 +1,22 @@ + + * @copyright Meritoo + */ +class CssSelector +{ + use FormCssSelector; +} diff --git a/src/Utilities/Date.php b/src/Utilities/Date.php index 8964691..40b76db 100644 --- a/src/Utilities/Date.php +++ b/src/Utilities/Date.php @@ -10,14 +10,16 @@ namespace Meritoo\Common\Utilities; use DateInterval; use DateTime; -use Meritoo\Common\Exception\Date\UnknownDatePartTypeException; +use Exception; +use Meritoo\Common\Exception\Type\UnknownDatePartTypeException; use Meritoo\Common\Type\DatePartType; +use Meritoo\Common\Type\DatePeriod; /** * Useful date methods * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Date { @@ -66,97 +68,110 @@ 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 DatePeriod + * @throws Exception + * @return null|DatePeriod */ public static function getDatesForPeriod($period) { - $datePeriod = null; - - if (DatePeriod::isCorrectPeriod($period)) { - $dateStart = null; - $dateEnd = null; - - switch ($period) { - case DatePeriod::LAST_WEEK: - $thisWeekStart = new DateTime('this week'); - - $dateStart = clone $thisWeekStart; - $dateEnd = clone $thisWeekStart; - - $dateStart->sub(new DateInterval('P7D')); - $dateEnd->sub(new DateInterval('P1D')); - - break; - case DatePeriod::THIS_WEEK: - $dateStart = new DateTime('this week'); - - $dateEnd = clone $dateStart; - $dateEnd->add(new DateInterval('P6D')); - - break; - case DatePeriod::NEXT_WEEK: - $dateStart = new DateTime('this week'); - $dateStart->add(new DateInterval('P7D')); - - $dateEnd = clone $dateStart; - $dateEnd->add(new DateInterval('P6D')); - - break; - case DatePeriod::LAST_MONTH: - $dateStart = new DateTime('first day of last month'); - $dateEnd = new DateTime('last day of last month'); - - break; - case DatePeriod::THIS_MONTH: - $lastMonth = self::getDatesForPeriod(DatePeriod::LAST_MONTH); - $nextMonth = self::getDatesForPeriod(DatePeriod::NEXT_MONTH); - - $dateStart = $lastMonth->getEndDate(); - $dateStart->add(new DateInterval('P1D')); - - $dateEnd = $nextMonth->getStartDate(); - $dateEnd->sub(new DateInterval('P1D')); - - break; - case DatePeriod::NEXT_MONTH: - $dateStart = new DateTime('first day of next month'); - $dateEnd = new DateTime('last day of next month'); - - break; - case DatePeriod::LAST_YEAR: - case DatePeriod::THIS_YEAR: - case DatePeriod::NEXT_YEAR: - $dateStart = new DateTime(); - $dateEnd = new DateTime(); - - if (DatePeriod::LAST_YEAR == $period || DatePeriod::NEXT_YEAR == $period) { - $yearDifference = 1; - - if (DatePeriod::LAST_YEAR == $period) { - $yearDifference *= -1; - } - - $modifyString = sprintf('%s year', $yearDifference); - $dateStart->modify($modifyString); - $dateEnd->modify($modifyString); - } - - $year = $dateStart->format('Y'); - $dateStart->setDate($year, 1, 1); - $dateEnd->setDate($year, 12, 31); - - break; - } - - if (null !== $dateStart && null !== $dateEnd) { - $dateStart->setTime(0, 0, 0); - $dateEnd->setTime(23, 59, 59); - - $datePeriod = new DatePeriod($dateStart, $dateEnd); - } + /* + * Type of period is incorrect? + * Nothing to do + */ + if (!(new DatePeriod())->isCorrectType($period)) { + return null; } - return $datePeriod; + $dateStart = null; + $dateEnd = null; + + switch ($period) { + case DatePeriod::LAST_WEEK: + $thisWeekStart = new DateTime('this week'); + + $dateStart = clone $thisWeekStart; + $dateEnd = clone $thisWeekStart; + + $dateStart->sub(new DateInterval('P7D')); + $dateEnd->sub(new DateInterval('P1D')); + + break; + case DatePeriod::THIS_WEEK: + $dateStart = new DateTime('this week'); + + $dateEnd = clone $dateStart; + $dateEnd->add(new DateInterval('P6D')); + + break; + case DatePeriod::NEXT_WEEK: + $dateStart = new DateTime('this week'); + $dateStart->add(new DateInterval('P7D')); + + $dateEnd = clone $dateStart; + $dateEnd->add(new DateInterval('P6D')); + + break; + case DatePeriod::LAST_MONTH: + $dateStart = new DateTime('first day of last month'); + $dateEnd = new DateTime('last day of last month'); + + break; + case DatePeriod::THIS_MONTH: + $lastMonth = self::getDatesForPeriod(DatePeriod::LAST_MONTH); + $nextMonth = self::getDatesForPeriod(DatePeriod::NEXT_MONTH); + + if (null !== $lastMonth) { + $dateStart = $lastMonth->getEndDate(); + $dateStart->add(new DateInterval('P1D')); + } + + if (null !== $nextMonth) { + $dateEnd = $nextMonth->getStartDate(); + $dateEnd->sub(new DateInterval('P1D')); + } + + break; + case DatePeriod::NEXT_MONTH: + $dateStart = new DateTime('first day of next month'); + $dateEnd = new DateTime('last day of next month'); + + break; + case DatePeriod::LAST_YEAR: + case DatePeriod::THIS_YEAR: + case DatePeriod::NEXT_YEAR: + $dateStart = new DateTime(); + $dateEnd = new DateTime(); + + if (DatePeriod::LAST_YEAR === $period || DatePeriod::NEXT_YEAR === $period) { + $yearDifference = 1; + + if (DatePeriod::LAST_YEAR === $period) { + $yearDifference *= -1; + } + + $modifyString = sprintf('%s year', $yearDifference); + $dateStart->modify($modifyString); + $dateEnd->modify($modifyString); + } + + $year = $dateStart->format('Y'); + $dateStart->setDate($year, 1, 1); + $dateEnd->setDate($year, 12, 31); + + break; + } + + /* + * Start or end date is unknown? + * Nothing to do + */ + if (null === $dateStart || null === $dateEnd) { + return null; + } + + $dateStart->setTime(0, 0, 0); + $dateEnd->setTime(23, 59, 59); + + return new DatePeriod($dateStart, $dateEnd); } /** @@ -230,8 +245,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) { @@ -243,21 +258,21 @@ class Date * Oops, incorrect year */ if ($year <= 0) { - throw new UnknownDatePartTypeException(DatePartType::YEAR, $year); + throw UnknownDatePartTypeException::createException(DatePartType::YEAR, $year); } /* * Oops, incorrect month */ if ($month < 1 || $month > 12) { - throw new UnknownDatePartTypeException(DatePartType::MONTH, $month); + throw UnknownDatePartTypeException::createException(DatePartType::MONTH, $month); } /* * Oops, incorrect day */ if ($day < 1 || $day > 31) { - throw new UnknownDatePartTypeException(DatePartType::DAY, $day); + throw UnknownDatePartTypeException::createException(DatePartType::DAY, $day); } if ($month < 3) { @@ -356,11 +371,11 @@ class Date return null; } - $dateStart = self::getDateTime($dateStart, true); - $dateEnd = self::getDateTime($dateEnd, true); + $start = self::getDateTime($dateStart, true); + $end = self::getDateTime($dateEnd, true); $difference = []; - $dateDiff = $dateEnd->getTimestamp() - $dateStart->getTimestamp(); + $dateDiff = $end->getTimestamp() - $start->getTimestamp(); $daysInSeconds = 0; $hoursInSeconds = 0; @@ -378,39 +393,39 @@ class Date self::DATE_DIFFERENCE_UNIT_MINUTES, ]; - if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_YEARS == $differenceUnit) { - $diff = $dateEnd->diff($dateStart); + if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) { + $diff = $end->diff($start); /* * Difference between dates in years should be returned only? */ - if (self::DATE_DIFFERENCE_UNIT_YEARS == $differenceUnit) { + if (self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) { return $diff->y; } $difference[self::DATE_DIFFERENCE_UNIT_YEARS] = $diff->y; } - if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MONTHS == $differenceUnit) { - $diff = $dateEnd->diff($dateStart); + if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) { + $diff = $end->diff($start); /* * Difference between dates in months should be returned only? */ - if (self::DATE_DIFFERENCE_UNIT_MONTHS == $differenceUnit) { + if (self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) { return $diff->m; } $difference[self::DATE_DIFFERENCE_UNIT_MONTHS] = $diff->m; } - if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits)) { + if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) { $days = (int)floor($dateDiff / $daySeconds); /* * Difference between dates in days should be returned only? */ - if (self::DATE_DIFFERENCE_UNIT_DAYS == $differenceUnit) { + if (self::DATE_DIFFERENCE_UNIT_DAYS === $differenceUnit) { return $days; } @@ -427,13 +442,13 @@ class Date $daysInSeconds = $days * $daySeconds; } - if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits)) { + if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) { $hours = (int)floor(($dateDiff - $daysInSeconds) / $hourSeconds); /* * Difference between dates in hours should be returned only? */ - if (self::DATE_DIFFERENCE_UNIT_HOURS == $differenceUnit) { + if (self::DATE_DIFFERENCE_UNIT_HOURS === $differenceUnit) { return $hours; } @@ -450,13 +465,13 @@ class Date $hoursInSeconds = $hours * $hourSeconds; } - if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MINUTES == $differenceUnit) { + if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) { $minutes = (int)floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60); /* * Difference between dates in minutes should be returned only? */ - if (self::DATE_DIFFERENCE_UNIT_MINUTES == $differenceUnit) { + if (self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) { return $minutes; } @@ -475,6 +490,7 @@ 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. + * @throws Exception * @return array */ public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD') @@ -520,6 +536,7 @@ 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. + * @throws Exception * @return DateTime */ public static function getRandomDate(DateTime $startDate = null, $start = 1, $end = 100, $intervalTemplate = 'P%sD') @@ -540,7 +557,7 @@ class Date } $randomDate = clone $startDate; - $randomInterval = new DateInterval(sprintf($intervalTemplate, rand($start, $end))); + $randomInterval = new DateInterval(sprintf($intervalTemplate, mt_rand($start, $end))); return $randomDate->add($randomInterval); } @@ -623,7 +640,7 @@ class Date * So, I have to refuse those special compound formats if they are not explicitly declared as * compound (2nd argument of this method, set to false by default) */ - if (in_array($value, $specialFormats)) { + if (in_array($value, $specialFormats, true)) { return false; } } @@ -648,7 +665,7 @@ class Date */ $dateString = (new DateTime())->format($value); - if ($dateString != $value) { + if ($dateString !== (string)$value) { return new DateTime($dateString); } } catch (\Exception $exception) { @@ -692,7 +709,7 @@ class Date * Formatted date it's the format who is validated? * The format is invalid */ - if ($formatted == $format) { + if ($formatted === $format) { return false; } diff --git a/src/Utilities/GeneratorUtility.php b/src/Utilities/GeneratorUtility.php index 8783fdc..8378858 100644 --- a/src/Utilities/GeneratorUtility.php +++ b/src/Utilities/GeneratorUtility.php @@ -13,8 +13,8 @@ use Generator; /** * Useful methods for the Generator class (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class GeneratorUtility { diff --git a/src/Utilities/Locale.php b/src/Utilities/Locale.php index 5ae1157..ae7abc6 100644 --- a/src/Utilities/Locale.php +++ b/src/Utilities/Locale.php @@ -11,8 +11,8 @@ namespace Meritoo\Common\Utilities; /** * Useful locale methods * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Locale { @@ -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,29 @@ class Locale } $localeLongForm = self::getLongForm($languageCode, $countryCode); - setlocale($category, $localeLongForm); - return true; + 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'); } /** diff --git a/src/Utilities/MimeTypes.php b/src/Utilities/MimeTypes.php index 9951d1a..f046012 100644 --- a/src/Utilities/MimeTypes.php +++ b/src/Utilities/MimeTypes.php @@ -11,8 +11,8 @@ namespace Meritoo\Common\Utilities; /** * Useful methods for mime types of files * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class MimeTypes { @@ -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 9fc924b..57ae076 100644 --- a/src/Utilities/Miscellaneous.php +++ b/src/Utilities/Miscellaneous.php @@ -9,14 +9,13 @@ namespace Meritoo\Common\Utilities; use Gedmo\Sluggable\Util\Urlizer; -use Symfony\Component\HttpFoundation\Cookie; use Transliterator; /** * Miscellaneous methods (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Miscellaneous { @@ -61,15 +60,15 @@ class Miscellaneous $startFileName = mb_substr($startFileName, 1); } - $directoryContent = scandir($directoryPath); + $directoryContent = scandir($directoryPath, SCANDIR_SORT_ASCENDING); if (!empty($directoryContent)) { foreach ($directoryContent as $fileName) { - if ('.' != $fileName && '..' != $fileName) { + if ('.' !== $fileName && '..' !== $fileName) { $content = null; if (!empty($startFileName) && !$startFileFound) { - if ($fileName == $startFileName) { + if ($fileName === $startFileName) { $startFileFound = true; } @@ -83,18 +82,18 @@ class Miscellaneous if (null !== $content) { $files[$fileName] = $content; - if (!empty($maxFilesCount)) { + if (null !== $maxFilesCount) { $count += Arrays::getNonArrayElementsCount($content); } } else { $files[] = $fileName; - if (!empty($maxFilesCount)) { + if (null !== $maxFilesCount) { ++$count; } } - if (!empty($maxFilesCount) && $count >= $maxFilesCount) { + if (null !== $maxFilesCount && $count >= $maxFilesCount) { break; } } @@ -159,11 +158,17 @@ class Miscellaneous */ public static function includeFileExtension($fileName, $extension) { - if (self::getFileExtension($fileName, true) != strtolower($extension)) { - return sprintf('%s.%s', $fileName, $extension); + $fileExtension = self::getFileExtension($fileName, true); + + /* + * File has given extension? + * Nothing to do + */ + if ($fileExtension === strtolower($extension)) { + return $fileName; } - return $fileName; + return sprintf('%s.%s', $fileName, $extension); } /** @@ -228,31 +233,28 @@ class Miscellaneous /* * Let's clear name of file * - * Attention. The name without extension may be cleared / urlized only - * to avoid incorrect name by replacing "." with "-". + * Attention. + * The name without extension may be cleared / urlized only to avoid incorrect name by replacing "." with "-". */ $withoutExtension = Urlizer::urlize($withoutExtension); /* * Now I have to complete the template used to build / generate unique name */ - $template = '%s-%s'; // file's name and unique key - - if ($objectId > 0) { - $template .= '-%s'; // object ID - } - - $template .= '.%s'; // file's extension + $template = '%s-%s.%s'; // [file's name]-[unique key].[file's extension] /* * Add some uniqueness */ - $unique = uniqid(mt_rand(), true); + $unique = self::getUniqueString(mt_rand()); /* * Finally build and return the unique name */ + if ($objectId > 0) { + $template = '%s-%s-%s.%s'; // [file's name]-[unique key]-[object ID].[file's extension] + return sprintf($template, $withoutExtension, $unique, $objectId, $extension); } @@ -332,7 +334,7 @@ class Miscellaneous { $phpModulesArray = get_loaded_extensions(); - return in_array($phpModuleName, $phpModulesArray); + return in_array($phpModuleName, $phpModulesArray, false); } /** @@ -460,7 +462,7 @@ class Miscellaneous * Value to find is neither a string nor an array OR it's an empty string? * Nothing to do */ - if ((!$searchIsString && !$searchIsArray) || ($searchIsString && 0 == strlen($search))) { + if ((!$searchIsString && !$searchIsArray) || ($searchIsString && '' === $search)) { return $effect; } @@ -485,7 +487,7 @@ class Miscellaneous * Second step: replace with regular expressions. * Attention. Searched and replacement value should be the same type: strings or arrays. */ - if ($effect == $subject && ($bothAreStrings || $bothAreArrays)) { + if ($effect === $subject && ($bothAreStrings || $bothAreArrays)) { if ($quoteStrings && $replacementIsString) { $replacement = '\'' . $replacement . '\''; } @@ -503,7 +505,7 @@ class Miscellaneous * Third step: complex replace of the replacement defined as an array. * It may be useful when you want to search for a one string and replace the string with multiple values. */ - if ($effect == $subject && $searchIsString && $replacementIsArray) { + if ($effect === $subject && $searchIsString && $replacementIsArray) { $subjectIsArray = is_array($subject); $effect = ''; @@ -588,7 +590,12 @@ class Miscellaneous */ public static function getOperatingSystemNameServer() { - return php_uname('s'); + return PHP_OS; + + /* + * Previous version: + * return php_uname('s'); + */ } /** @@ -626,10 +633,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( @@ -680,7 +687,8 @@ class Miscellaneous $spacePosition = mb_strrpos($lineWithAberration, ' ', 0, $encoding); - if ($spacePosition > 0) { + if (false !== $spacePosition && 0 < $spacePosition) { + /* @var int $spacePosition */ $perLine = $spacePosition; $insertSeparator = true; } @@ -716,21 +724,29 @@ 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); } - foreach (scandir($directoryPath) as $item) { - if ('.' == $item || '..' == $item) { + foreach (scandir($directoryPath, SCANDIR_SORT_ASCENDING) as $item) { + if ('.' === $item || '..' === $item) { continue; } @@ -739,6 +755,9 @@ class Miscellaneous } } + /* + * Directory should be removed too? + */ if (!$contentOnly) { return rmdir($directoryPath); } @@ -776,7 +795,7 @@ class Miscellaneous foreach ($members as $key => $value) { $value = mb_strtolower($value); - if (0 == $key) { + if (0 === $key) { $effect .= self::lowercaseFirst($value); } else { $effect .= self::uppercaseFirst($value); @@ -797,10 +816,6 @@ class Miscellaneous * - null (default): nothing is done with the string * - true: the rest of string is lowercased * - false: the rest of string is uppercased - * - * Some explanation: - * Function lcfirst() is available for PHP >= 5.30, so I wrote my own function that lowercases first character of - * the string. */ public static function lowercaseFirst($text, $restLowercase = null) { @@ -816,16 +831,7 @@ class Miscellaneous $effect = mb_strtoupper($effect); } - if (function_exists('lcfirst')) { - $effect = lcfirst($effect); - } else { - $first = mb_strtolower($effect[0]); - $rest = mb_substr($effect, 1); - - $effect = $first . $rest; - } - - return $effect; + return lcfirst($effect); } /** @@ -854,16 +860,7 @@ class Miscellaneous $effect = mb_strtoupper($effect); } - if (function_exists('ucfirst')) { - $effect = ucfirst($effect); - } else { - $first = mb_strtoupper($effect[0]); - $rest = mb_substr($effect, 1); - - $effect = $first . $rest; - } - - return $effect; + return ucfirst($effect); } /** @@ -904,9 +901,9 @@ class Miscellaneous 'TB', 'PB', ]; - $index = floor(log($sizeInBytes, 1024)); - $size = round($sizeInBytes / pow(1024, $index), 2); + $index = floor(log($sizeInBytes, 1024)); + $size = round($sizeInBytes / (1024 ** $index), 2); $unit = $units[(int)$index]; return sprintf('%s %s', $size, $unit); @@ -1182,148 +1179,12 @@ class Miscellaneous if (null !== $globalSource && isset($globalSource[$variableName])) { $value = $globalSource[$variableName]; - - if (!ini_get('magic_quotes_gpc')) { - $value = addslashes($value); - } } } 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 the full content of response, including HTTP headers - * @param int $headerSize The 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 = []; - - /* - * 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 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 * @@ -1363,7 +1224,7 @@ class Miscellaneous continue; } - $text = $text . '0'; + $text .= '0'; } return $text; @@ -1418,8 +1279,8 @@ class Miscellaneous if ($asHexadecimal) { $hexadecimal = dechex($colorComponent); - if (1 == strlen($hexadecimal)) { - return sprintf('0%s', $hexadecimal, $hexadecimal); + if (1 === strlen($hexadecimal)) { + return sprintf('0%s', $hexadecimal); } return $hexadecimal; @@ -1446,14 +1307,14 @@ class Miscellaneous * Verify and get valid value of color. * An exception will be thrown if the value is not a color. */ - $color = Regex::getValidColorHexValue($color); + $validColor = Regex::getValidColorHexValue($color); /* * Grab color's components */ - $red = hexdec(substr($color, 0, 2)); - $green = hexdec(substr($color, 2, 2)); - $blue = hexdec(substr($color, 4, 2)); + $red = hexdec(substr($validColor, 0, 2)); + $green = hexdec(substr($validColor, 2, 2)); + $blue = hexdec(substr($validColor, 4, 2)); /* * Calculate inverted color's components diff --git a/src/Utilities/QueryBuilderUtility.php b/src/Utilities/QueryBuilderUtility.php index b645a82..fd912aa 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; @@ -17,8 +18,8 @@ use Doctrine\ORM\QueryBuilder; /** * Useful methods for query builder (the Doctrine's QueryBuilder class) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class QueryBuilderUtility { @@ -33,6 +34,10 @@ class QueryBuilderUtility { $aliases = $queryBuilder->getRootAliases(); + /* + * No aliases? + * Nothing to do + */ if (empty($aliases)) { return null; } @@ -42,7 +47,8 @@ class QueryBuilderUtility /** * Returns alias of given property joined in given query builder - * If the join does not exist, null is returned. + * + * If there are no joins or the join does not exist, null is returned. * It's also information if given property is already joined in given query builder. * * @param QueryBuilder $queryBuilder The query builder to verify @@ -53,6 +59,10 @@ class QueryBuilderUtility { $joins = $queryBuilder->getDQLPart('join'); + /* + * No joins? + * Nothing to do + */ if (empty($joins)) { return null; } @@ -99,33 +109,43 @@ class QueryBuilderUtility */ public static function setCriteria(QueryBuilder $queryBuilder, array $criteria = [], $alias = '') { - if (!empty($criteria)) { - if (empty($alias)) { - $alias = self::getRootAlias($queryBuilder); - } + /* + * No criteria used in WHERE clause? + * Nothing to do + */ + if (empty($criteria)) { + return $queryBuilder; + } - foreach ($criteria as $column => $value) { - $compareOperator = '='; + /* + * No alias provided? + * Let's use root alias + */ + if (empty($alias)) { + $alias = self::getRootAlias($queryBuilder); + } - if (is_array($value) && !empty($value)) { - if (2 == count($value)) { - $compareOperator = $value[1]; - } + foreach ($criteria as $column => $value) { + $compareOperator = '='; - $value = $value[0]; + if (is_array($value) && !empty($value)) { + if (2 == count($value)) { + $compareOperator = $value[1]; } - $predicate = sprintf('%s.%s %s :%s', $alias, $column, $compareOperator, $column); - - if (null === $value) { - $predicate = $queryBuilder->expr()->isNull(sprintf('%s.%s', $alias, $column)); - unset($criteria[$column]); - } else { - $queryBuilder->setParameter($column, $value); - } - - $queryBuilder = $queryBuilder->andWhere($predicate); + $value = $value[0]; } + + $predicate = sprintf('%s.%s %s :%s', $alias, $column, $compareOperator, $column); + + if (null === $value) { + $predicate = $queryBuilder->expr()->isNull(sprintf('%s.%s', $alias, $column)); + unset($criteria[$column]); + } else { + $queryBuilder->setParameter($column, $value); + } + + $queryBuilder = $queryBuilder->andWhere($predicate); } return $queryBuilder; @@ -136,14 +156,15 @@ 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. + * @throws OptimisticLockException * @return bool */ public static function deleteEntities(EntityManager $entityManager, $entities, $flushDeleted = true) { /* - * No entities found? + * No entities provided? * Nothing to do */ if (empty($entities)) { @@ -169,24 +190,30 @@ class QueryBuilderUtility * Attention. Existing parameters will be overridden. * * @param QueryBuilder $queryBuilder The query builder - * @param array|ArrayCollection $parameters Parameters to add. Collection of instances of - * Doctrine\ORM\Query\Parameter class or an array with key-value pairs. + * @param array|ArrayCollection $parameters Parameters to add. Collection of Doctrine\ORM\Query\Parameter + * instances or an array with key-value pairs. * @return QueryBuilder */ public static function addParameters(QueryBuilder $queryBuilder, $parameters) { - if (!empty($parameters)) { - foreach ($parameters as $key => $parameter) { - $name = $key; - $value = $parameter; + /* + * No parameters? + * Nothing to do + */ + if (empty($parameters)) { + return $queryBuilder; + } - if ($parameter instanceof Parameter) { - $name = $parameter->getName(); - $value = $parameter->getValue(); - } + foreach ($parameters as $key => $parameter) { + $name = $key; + $value = $parameter; - $queryBuilder->setParameter($name, $value); + if ($parameter instanceof Parameter) { + $name = $parameter->getName(); + $value = $parameter->getValue(); } + + $queryBuilder->setParameter($name, $value); } return $queryBuilder; diff --git a/src/Utilities/Reflection.php b/src/Utilities/Reflection.php index 4e94900..b03a0bd 100644 --- a/src/Utilities/Reflection.php +++ b/src/Utilities/Reflection.php @@ -13,18 +13,14 @@ use Doctrine\Common\Util\Inflector; use Meritoo\Common\Collection\Collection; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; +use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; use Meritoo\Common\Exception\Reflection\TooManyChildClassesException; -use ReflectionClass; -use ReflectionException; -use ReflectionMethod; -use ReflectionObject; -use ReflectionProperty; /** * Useful reflection methods * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Reflection { @@ -40,14 +36,14 @@ class Reflection { $effect = []; - $reflection = new ReflectionClass($class); + $reflection = new \ReflectionClass($class); $methods = $reflection->getMethods(); if (!empty($methods)) { $className = self::getClassName($class); foreach ($methods as $method) { - if ($method instanceof ReflectionMethod) { + if ($method instanceof \ReflectionMethod) { if ($withoutInheritance && $className !== $method->class) { continue; } @@ -68,14 +64,14 @@ class Reflection */ public static function getConstants($class) { - $reflection = new ReflectionClass($class); + $reflection = new \ReflectionClass($class); return $reflection->getConstants(); } /** - * Returns maximum constant from all constants of given class / object. - * Values of constants should be integers. + * Returns maximum integer value of constant of given class / object. + * Constants whose values are integers are considered only. * * @param object|string $class The object or name of object's class * @return int|null @@ -108,7 +104,7 @@ class Reflection */ public static function hasMethod($class, $method) { - $reflection = new ReflectionClass($class); + $reflection = new \ReflectionClass($class); return $reflection->hasMethod($method); } @@ -122,7 +118,7 @@ class Reflection */ public static function hasProperty($class, $property) { - $reflection = new ReflectionClass($class); + $reflection = new \ReflectionClass($class); return $reflection->hasProperty($property); } @@ -136,7 +132,7 @@ class Reflection */ public static function hasConstant($class, $constant) { - $reflection = new ReflectionClass($class); + $reflection = new \ReflectionClass($class); return $reflection->hasConstant($constant); } @@ -150,7 +146,7 @@ class Reflection */ public static function getConstantValue($class, $constant) { - $reflection = new ReflectionClass($class); + $reflection = new \ReflectionClass($class); if (self::hasConstant($class, $constant)) { return $reflection->getConstant($constant); @@ -189,16 +185,16 @@ class Reflection * Let's dig more and get proper value * * Required to avoid bug: - * ReflectionObject::__construct() expects parameter 1 to be object, null given + * \ReflectionObject::__construct() expects parameter 1 to be object, null given * (...) - * 4. at ReflectionObject->__construct (null) + * 4. at \ReflectionObject->__construct (null) * 5. at Reflection ::getPropertyValue (null, 'name', true) * 6. at ListService->getItemValue (object(Deal), 'project.name', '0') * * while using "project.name" as property - $project has $name property ($project exists in the Deal class) * and the $project equals null * - * Krzysztof Niziol + * Meritoo * 2016-11-07 */ if (null !== $object) { @@ -216,17 +212,17 @@ class Reflection * Use \ReflectionObject class */ try { - $reflectionProperty = new ReflectionProperty($className, $property); + $reflectionProperty = new \ReflectionProperty($className, $property); $value = $reflectionProperty->getValue($object); - } catch (ReflectionException $exception) { + } catch (\ReflectionException $exception) { /* * 2nd try: * Look for the get / has / is methods */ - $class = new ReflectionObject($object); + $class = new \ReflectionObject($object); $valueFound = false; - if ($class->hasProperty($property) || $force) { + if ($force || $class->hasProperty($property)) { $property = Inflector::classify($property); $getterPrefixes = [ @@ -239,7 +235,7 @@ class Reflection $getterName = sprintf('%s%s', $prefix, $property); if ($class->hasMethod($getterName)) { - $method = new ReflectionMethod($object, $getterName); + $method = new \ReflectionMethod($object, $getterName); /* * Getter is not accessible publicly? @@ -386,13 +382,13 @@ class Reflection { $fullClassName = self::getClassName($source); - if (empty($fullClassName)) { + if (null === $fullClassName || '' === $fullClassName) { return ''; } $className = self::getClassName($source, true); - if ($className == $fullClassName) { + if ($className === $fullClassName) { return $className; } @@ -411,7 +407,7 @@ class Reflection $className = self::getClassName($source); $interfaces = class_implements($className); - return in_array($interface, $interfaces); + return in_array($interface, $interfaces, true); } /** @@ -428,8 +424,8 @@ class Reflection $parents = class_parents($childClassName); - if (is_array($parents)) { - return in_array($parentClassName, $parents); + if (is_array($parents) && 0 < count($parents)) { + return in_array($parentClassName, $parents, true); } return false; @@ -439,22 +435,22 @@ class Reflection * Returns given object properties * * @param array|object|string $source An array of objects, namespaces, object or namespace - * @param int $filter (optional) Filter of properties. Uses ReflectionProperty class + * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class * 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 + * @return array|\ReflectionProperty */ public static function getProperties($source, $filter = null, $includeParents = false) { $className = self::getClassName($source); - $reflection = new ReflectionClass($className); + $reflection = new \ReflectionClass($className); if (null === $filter) { - $filter = ReflectionProperty::IS_PRIVATE - + ReflectionProperty::IS_PROTECTED - + ReflectionProperty::IS_PUBLIC - + ReflectionProperty::IS_STATIC; + $filter = \ReflectionProperty::IS_PRIVATE + + \ReflectionProperty::IS_PROTECTED + + \ReflectionProperty::IS_PUBLIC + + \ReflectionProperty::IS_STATIC; } $properties = $reflection->getProperties($filter); @@ -476,12 +472,12 @@ 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 + * @return \ReflectionClass|bool */ public static function getParentClass($source) { $className = self::getClassName($source); - $reflection = new ReflectionClass($className); + $reflection = new \ReflectionClass($className); return $reflection->getParentClass(); } @@ -492,8 +488,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) { @@ -513,7 +509,7 @@ class Reflection * Oops, cannot resolve class */ if (null === $className) { - throw new CannotResolveClassNameException($class); + throw CannotResolveClassNameException::create($class); } $childClasses = []; @@ -530,7 +526,7 @@ class Reflection */ $realClass = ClassUtils::getRealClass($oneClass); - if (in_array($realClass, $childClasses)) { + if (in_array($realClass, $childClasses, true)) { continue; } @@ -547,10 +543,9 @@ 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 MissingChildClassesException * @throws TooManyChildClassesException + * @return mixed */ public static function getOneChildClass($parentClass) { @@ -561,7 +556,7 @@ class Reflection * Oops, the base / parent class hasn't child class */ if (empty($childClasses)) { - throw new MissingChildClassesException($parentClass); + throw MissingChildClassesException::create($parentClass); } /* @@ -569,20 +564,20 @@ class Reflection * Oops, the base / parent class has too many child classes */ if (count($childClasses) > 1) { - throw new TooManyChildClassesException($parentClass, $childClasses); + throw TooManyChildClassesException::create($parentClass, $childClasses); } return trim($childClasses[0]); } /** - * Returns property, the ReflectionProperty instance, of given object + * Returns property, the \ReflectionProperty instance, of given object * * @param array|object|string $class An array of objects, namespaces, object or namespace * @param string $property Name of the property - * @param int $filter (optional) Filter of properties. Uses ReflectionProperty class constants. + * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class constants. * By default all properties are allowed / processed. - * @return null|ReflectionProperty + * @return null|\ReflectionProperty */ public static function getProperty($class, $property, $filter = null) { @@ -590,9 +585,9 @@ class Reflection $properties = self::getProperties($className, $filter); if (!empty($properties)) { - /* @var $reflectionProperty ReflectionProperty */ + /* @var $reflectionProperty \ReflectionProperty */ foreach ($properties as $reflectionProperty) { - if ($reflectionProperty->getName() == $property) { + if ($reflectionProperty->getName() === $property) { return $reflectionProperty; } } @@ -608,8 +603,8 @@ 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 + * @return bool|null */ public static function usesTrait($class, $trait, $verifyParents = false) { @@ -619,21 +614,21 @@ class Reflection /* * Oops, cannot resolve class */ - if (empty($className)) { - throw new CannotResolveClassNameException($class); + if (null === $className || '' === $className) { + throw CannotResolveClassNameException::create($class); } /* * Oops, cannot resolve trait */ - if (empty($traitName)) { + if (null === $traitName || '' === $traitName) { throw new CannotResolveClassNameException($class, false); } - $reflection = new ReflectionClass($className); + $reflection = new \ReflectionClass($className); $traitsNames = $reflection->getTraitNames(); - $uses = in_array($traitName, $traitsNames); + $uses = in_array($traitName, $traitsNames, true); if (!$uses && $verifyParents) { $parentClassName = self::getParentClassName($className); @@ -656,7 +651,7 @@ class Reflection public static function getParentClassName($class) { $className = self::getClassName($class); - $reflection = new ReflectionClass($className); + $reflection = new \ReflectionClass($className); $parentClass = $reflection->getParentClass(); if (null === $parentClass || false === $parentClass) { @@ -665,4 +660,36 @@ class Reflection return $parentClass->getName(); } + + /** + * Sets value of given property + * + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * @param mixed $value Value of the property + * @throws NotExistingPropertyException + */ + public static function setPropertyValue($object, $property, $value) + { + $reflectionProperty = self::getProperty($object, $property); + + /* + * Oops, property does not exist + */ + if (null === $reflectionProperty) { + throw NotExistingPropertyException::create($object, $property); + } + + $notAccessible = $reflectionProperty->isPrivate() || $reflectionProperty->isProtected(); + + if ($notAccessible) { + $reflectionProperty->setAccessible(true); + } + + $reflectionProperty->setValue($object, $value); + + if ($notAccessible) { + $reflectionProperty->setAccessible(false); + } + } } diff --git a/src/Utilities/Regex.php b/src/Utilities/Regex.php index 85cf1c0..20841bc 100644 --- a/src/Utilities/Regex.php +++ b/src/Utilities/Regex.php @@ -14,8 +14,8 @@ use Meritoo\Common\Exception\Regex\InvalidColorHexValueException; /** * Useful regular expressions methods * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Regex { @@ -25,18 +25,21 @@ 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]+:\/\/)', '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}:\\\.*$/', '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]/', ]; /** @@ -56,43 +59,77 @@ class Regex */ public static function isValidEmail($email) { + /* + * Not a string? + * Nothing to do + */ + if (!is_string($email)) { + return false; + } + $pattern = self::getEmailPattern(); return (bool)preg_match($pattern, $email); } /** - * 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)) { - $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; @@ -108,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); @@ -121,88 +166,108 @@ class Regex */ public static function isValidPhoneNumber($phoneNumber) { + /* + * Not a string? + * Nothing to do + */ + 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]); } } @@ -210,36 +275,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; } } } @@ -676,6 +746,14 @@ class Regex */ public static function isValidMoneyValue($value) { + /* + * Not a scalar value? + * Nothing to do + */ + if (!is_scalar($value)) { + return false; + } + $pattern = self::getMoneyPattern(); return (bool)preg_match($pattern, $value); @@ -688,39 +766,162 @@ 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) { + /* + * 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; + } + + /** + * 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) + { + /* + * Not a string? + * Nothing to do + */ + if (!is_string($bundleName)) { + return false; + } + + $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']; + } + + /** + * 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) + { + /* + * Not a string? + * Nothing to do + */ + 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) + { + /* + * Not a string? + * Nothing to do + */ + if (!is_string($htmlAttributes)) { + return false; + } + + $pattern = self::getHtmlAttributePattern(); + + 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) + { + /* + * Not a string? + * Nothing to do + */ + if (!is_string($value)) { + return false; + } + + $pattern = self::$patterns['binaryValue']; + + return (bool)preg_match($pattern, $value); } } diff --git a/src/Utilities/Repository.php b/src/Utilities/Repository.php index 94a9737..fbc8d12 100644 --- a/src/Utilities/Repository.php +++ b/src/Utilities/Repository.php @@ -14,72 +14,148 @@ use Doctrine\ORM\QueryBuilder; /** * Useful methods for repository * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ 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. Otherwise - at the 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). */ - 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 */ - 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; } } @@ -106,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/src/Utilities/Uri.php b/src/Utilities/Uri.php index 96253b0..bc1ec19 100644 --- a/src/Utilities/Uri.php +++ b/src/Utilities/Uri.php @@ -11,8 +11,8 @@ namespace Meritoo\Common\Utilities; /** * Useful uri methods (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Uri { @@ -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/src/Utilities/Xml.php b/src/Utilities/Xml.php index 5707acf..a6878cd 100644 --- a/src/Utilities/Xml.php +++ b/src/Utilities/Xml.php @@ -15,8 +15,8 @@ use SimpleXMLElement; /** * Useful XML-related methods (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class Xml { diff --git a/src/ValueObject/Version.php b/src/ValueObject/Version.php new file mode 100644 index 0000000..8684da0 --- /dev/null +++ b/src/ValueObject/Version.php @@ -0,0 +1,179 @@ + + * @copyright Meritoo + */ +class Version +{ + /** + * The "major" part. + * Incremented when you make incompatible API changes. + * + * @var int + */ + private $majorPart; + + /** + * The "minor" part. + * Incremented when you add functionality in a backwards-compatible manner. + * + * @var int + */ + private $minorPart; + + /** + * The "patch" part. + * Incremented when you make backwards-compatible bug fixes. + * + * @var int + */ + private $patchPart; + + /** + * Class constructor + * + * @param int $majorPart The "major" part. Incremented when you make incompatible API changes. + * @param int $minorPart The "minor" part. Incremented when you add functionality in a backwards-compatible manner. + * @param int $patchPart The "patch" part. Incremented when you make backwards-compatible bug fixes. + */ + public function __construct($majorPart, $minorPart, $patchPart) + { + $this->majorPart = $majorPart; + $this->minorPart = $minorPart; + $this->patchPart = $patchPart; + } + + /** + * Returns the "major" part. + * Incremented when you make incompatible API changes. + * + * @return int + */ + public function getMajorPart() + { + return $this->majorPart; + } + + /** + * Returns the "minor" part. + * Incremented when you add functionality in a backwards-compatible manner. + * + * @return int + */ + public function getMinorPart() + { + return $this->minorPart; + } + + /** + * Returns the "patch" part. + * Incremented when you make backwards-compatible bug fixes. + * + * @return int + */ + public function getPatchPart() + { + return $this->patchPart; + } + + /** + * Returns string representation of instance of this class + * + * @return string + */ + public function __toString() + { + return sprintf('%d.%d.%d', $this->getMajorPart(), $this->getMinorPart(), $this->getPatchPart()); + } + + /** + * Returns new instance based on given version as string. + * Given version should contain 3 dot-separated integers, 1 per each part ("major", "minor" and "patch"). + * + * Examples: + * "1.0.2"; + * "10.4.0"; + * + * @param string $version The version + * @return Version|null + */ + public static function fromString($version) + { + $version = trim($version); + + /* + * No version provided? + * Nothing to do + */ + if (empty($version)) { + return null; + } + + $matches = []; + $pattern = '/^(\d+)\.(\d+)\.(\d+)$/'; // e.g. "1.0.2" + $matched = preg_match($pattern, $version, $matches); + + /* + * Incorrect version? + * Nothing to do + */ + if (0 === $matched || false === $matched) { + return null; + } + + $majorPart = (int)$matches[1]; + $minorPart = (int)$matches[2]; + $patchPart = (int)$matches[3]; + + return new static($majorPart, $minorPart, $patchPart); + } + + /** + * Returns new instance based on given version as array. + * Given version should contain 3 integers, 1 per each part ("major", "minor" and "patch"). + * + * Examples: + * [1, 0, 2]; + * [10, 4, 0]; + * + * @param array $version The version + * @return Version|null + */ + public static function fromArray(array $version) + { + /* + * No version provided? + * Nothing to do + */ + if (empty($version)) { + return null; + } + + $count = count($version); + + /* + * Incorrect version? + * Nothing to do + */ + if (3 !== $count) { + return null; + } + + $majorPart = (int)$version[0]; + $minorPart = (int)$version[1]; + $patchPart = (int)$version[2]; + + return new static($majorPart, $minorPart, $patchPart); + } +} diff --git a/tests/Collection/CollectionTest.php b/tests/Collection/CollectionTest.php index 60a4479..26a40ff 100644 --- a/tests/Collection/CollectionTest.php +++ b/tests/Collection/CollectionTest.php @@ -9,6 +9,7 @@ namespace Meritoo\Common\Test\Collection; use ArrayIterator; +use Generator; use Meritoo\Common\Collection\Collection; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\OopVisibilityType; @@ -16,8 +17,8 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of the collection of elements * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class CollectionTest extends BaseTestCase { @@ -129,22 +130,39 @@ class CollectionTest extends BaseTestCase static::assertInstanceOf(ArrayIterator::class, $this->simpleCollection->getIterator()); } - public function testAdd() + /** + * @param mixed $element The element to add + * @param int $expectedCount Expected count of elements in collection + * @param int $expectedIndex Expected index of added element in collection + * @param Collection $collection The collection + * + * @dataProvider provideElementToAdd + */ + public function testAddWithoutIndex($element, $expectedCount, $expectedIndex, Collection $collection) { - $this->emptyCollection->add('test1'); + $collection->add($element); - static::assertTrue($this->emptyCollection->has('test1')); - static::assertEquals(1, $this->emptyCollection->count()); - static::assertEquals('test1', $this->emptyCollection[0]); + static::assertTrue($collection->has($element)); + static::assertEquals($expectedCount, $collection->count()); + static::assertEquals($element, $collection[$expectedIndex]); } - public function testAddWithIndex() + /** + * @param mixed $element The element to add + * @param mixed $index Index of element to add + * @param int $expectedCount Expected count of elements in collection + * @param int $expectedIndex Expected index of added element in collection + * @param Collection $collection The collection + * + * @dataProvider provideElementToAddWithIndex + */ + public function testAddWithIndex($element, $index, $expectedCount, $expectedIndex, Collection $collection) { - $this->emptyCollection->add('test2', 1234); + $collection->add($element, $index); - static::assertTrue($this->emptyCollection->has('test2')); - static::assertEquals(1, $this->emptyCollection->count()); - static::assertEquals('test2', $this->emptyCollection[1234]); + static::assertTrue($collection->has($element)); + static::assertEquals($expectedCount, $collection->count()); + static::assertEquals($element, $collection[$expectedIndex]); } public function testAddMultipleUsingEmptyArray() @@ -309,6 +327,87 @@ class CollectionTest extends BaseTestCase static::assertMethodVisibilityAndArguments(Collection::class, 'exists', OopVisibilityType::IS_PRIVATE, 1, 1); } + /** + * Provides element to add to collection + * + * @return Generator + */ + public function provideElementToAdd() + { + $collection = new Collection(); + + yield[ + 'test1', + 1, + 0, + $collection, + ]; + + yield[ + 'test2', + 2, + 1, + $collection, + ]; + + yield[ + 'test3', + 3, + 2, + $collection, + ]; + } + + /** + * Provides element with index to add to collection + * + * @return Generator + */ + public function provideElementToAddWithIndex() + { + $collection = new Collection(); + + yield[ + 'test1', + 'aa', + 1, + 'aa', + $collection, + ]; + + yield[ + 'test2', + 'oo', + 2, + 'oo', + $collection, + ]; + + yield[ + 'test3', + null, + 3, + 0, + $collection, + ]; + + yield[ + 'test4', + '', + 4, + 1, + $collection, + ]; + + yield[ + 'test5', + 'vv', + 5, + 'vv', + $collection, + ]; + } + /** * {@inheritdoc} */ diff --git a/tests/Exception/Base/UnknownTypeExceptionTest.php b/tests/Exception/Base/UnknownTypeExceptionTest.php index 78b8120..c453db6 100644 --- a/tests/Exception/Base/UnknownTypeExceptionTest.php +++ b/tests/Exception/Base/UnknownTypeExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of the exception used while type of something is unknown * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class UnknownTypeExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(UnknownTestTypeException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + static::assertConstructorVisibilityAndArguments(UnknownTestTypeException::class, OopVisibilityType::IS_PUBLIC, 3); } public function testWithoutException() @@ -41,8 +41,8 @@ class UnknownTypeExceptionTest extends BaseTestCase /** * Type of something (for testing purposes) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class TestType extends BaseType { @@ -54,27 +54,31 @@ class TestType extends BaseType /** * An exception used while type of something is unknown (for testing purposes) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class UnknownTestTypeException extends UnknownTypeException { /** - * Class constructor + * Creates exception * - * @param int|string $unknownType The unknown type of something (for testing purposes) + * @param string $unknownType The unknown type of something (for testing purposes) + * @return UnknownTestTypeException */ - public function __construct($unknownType) + public static function createException($unknownType) { - parent::__construct($unknownType, new TestType(), 'type of something used for testing'); + /* @var UnknownTestTypeException $exception */ + $exception = parent::create($unknownType, new TestType(), 'type of something used for testing'); + + return $exception; } } /** * Service used together with type of something (for testing purposes) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class TestService { @@ -82,9 +86,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/Exception/Date/UnknownDatePartTypeExceptionTest.php b/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php index a318406..745c481 100644 --- a/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php +++ b/tests/Exception/Date/UnknownDatePartTypeExceptionTest.php @@ -9,7 +9,7 @@ namespace Meritoo\Common\Test\Exception\Date; use Generator; -use Meritoo\Common\Exception\Date\UnknownDatePartTypeException; +use Meritoo\Common\Exception\Type\UnknownDatePartTypeException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Type\DatePartType; use Meritoo\Common\Type\OopVisibilityType; @@ -17,14 +17,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while type of date part, e.g. "year", is unknown * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class UnknownDatePartTypeExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(UnknownDatePartTypeException::class, OopVisibilityType::IS_PUBLIC, 2, 2); + static::assertConstructorVisibilityAndArguments(UnknownDatePartTypeException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -34,9 +34,9 @@ class UnknownDatePartTypeExceptionTest extends BaseTestCase * * @dataProvider provideDatePartAndValue */ - public function testConstructorMessage($unknownDatePart, $value, $expectedMessage) + public function testMessage($unknownDatePart, $value, $expectedMessage) { - $exception = new UnknownDatePartTypeException($unknownDatePart, $value); + $exception = UnknownDatePartTypeException::createException($unknownDatePart, $value); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/File/EmptyFileExceptionTest.php b/tests/Exception/File/EmptyFileExceptionTest.php index 506592e..88aae84 100644 --- a/tests/Exception/File/EmptyFileExceptionTest.php +++ b/tests/Exception/File/EmptyFileExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while file with given path is empty (has no content) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class EmptyFileExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(EmptyFileException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + static::assertConstructorVisibilityAndArguments(EmptyFileException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -32,9 +32,9 @@ class EmptyFileExceptionTest extends BaseTestCase * * @dataProvider providePathOfFile */ - public function testConstructorMessage($emptyFilePath, $expectedMessage) + public function testMessage($emptyFilePath, $expectedMessage) { - $exception = new EmptyFileException($emptyFilePath); + $exception = EmptyFileException::create($emptyFilePath); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/File/EmptyFilePathExceptionTest.php b/tests/Exception/File/EmptyFilePathExceptionTest.php index 084831b..93cd7ee 100644 --- a/tests/Exception/File/EmptyFilePathExceptionTest.php +++ b/tests/Exception/File/EmptyFilePathExceptionTest.php @@ -15,19 +15,19 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while path of given file is empty * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class EmptyFilePathExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(EmptyFilePathException::class, OopVisibilityType::IS_PUBLIC); + static::assertConstructorVisibilityAndArguments(EmptyFilePathException::class, OopVisibilityType::IS_PUBLIC, 3); } public function testConstructorMessage() { - $exception = new EmptyFilePathException(); + $exception = EmptyFilePathException::create(); static::assertEquals('Path of the file is empty. Did you provide path of proper file?', $exception->getMessage()); } } diff --git a/tests/Exception/File/NotExistingFileExceptionTest.php b/tests/Exception/File/NotExistingFileExceptionTest.php index 3361395..21d7999 100644 --- a/tests/Exception/File/NotExistingFileExceptionTest.php +++ b/tests/Exception/File/NotExistingFileExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while file with given path does not exist * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class NotExistingFileExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(NotExistingFileException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + static::assertConstructorVisibilityAndArguments(NotExistingFileException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -34,7 +34,7 @@ class NotExistingFileExceptionTest extends BaseTestCase */ public function testConstructorMessage($notExistingFilePath, $expectedMessage) { - $exception = new NotExistingFileException($notExistingFilePath); + $exception = NotExistingFileException::create($notExistingFilePath); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/Method/DisabledMethodExceptionTest.php b/tests/Exception/Method/DisabledMethodExceptionTest.php index 06e6e67..81854ce 100644 --- a/tests/Exception/Method/DisabledMethodExceptionTest.php +++ b/tests/Exception/Method/DisabledMethodExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while method cannot be called, because is disabled * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class DisabledMethodExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(DisabledMethodException::class, OopVisibilityType::IS_PUBLIC, 2, 1); + static::assertConstructorVisibilityAndArguments(DisabledMethodException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -36,7 +36,7 @@ class DisabledMethodExceptionTest extends BaseTestCase */ public function testConstructorMessage($disabledMethod, $alternativeMethod, $expectedMessage) { - $exception = new DisabledMethodException($disabledMethod, $alternativeMethod); + $exception = DisabledMethodException::create($disabledMethod, $alternativeMethod); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php index c0e2629..880f09e 100644 --- a/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php +++ b/tests/Exception/Reflection/CannotResolveClassNameExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while name of class or trait cannot be resolved * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class CannotResolveClassNameExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(CannotResolveClassNameException::class, OopVisibilityType::IS_PUBLIC, 2, 1); + static::assertConstructorVisibilityAndArguments(CannotResolveClassNameException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -37,7 +37,7 @@ class CannotResolveClassNameExceptionTest extends BaseTestCase */ public function testConstructorMessage($source, $forClass, $expectedMessage) { - $exception = new CannotResolveClassNameException($source, $forClass); + $exception = CannotResolveClassNameException::create($source, $forClass); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/Reflection/MissingChildClassesExceptionTest.php b/tests/Exception/Reflection/MissingChildClassesExceptionTest.php index dfff334..3ec9f3a 100644 --- a/tests/Exception/Reflection/MissingChildClassesExceptionTest.php +++ b/tests/Exception/Reflection/MissingChildClassesExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while given class has no child classes * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class MissingChildClassesExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(MissingChildClassesException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + static::assertConstructorVisibilityAndArguments(MissingChildClassesException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -35,7 +35,7 @@ class MissingChildClassesExceptionTest extends BaseTestCase */ public function testConstructorMessage($parentClass, $expectedMessage) { - $exception = new MissingChildClassesException($parentClass); + $exception = MissingChildClassesException::create($parentClass); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php b/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php index f49d691..3360c4c 100644 --- a/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php +++ b/tests/Exception/Reflection/TooManyChildClassesExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while given class has more than one child class * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class TooManyChildClassesExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(TooManyChildClassesException::class, OopVisibilityType::IS_PUBLIC, 2, 2); + static::assertConstructorVisibilityAndArguments(TooManyChildClassesException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -36,7 +36,7 @@ class TooManyChildClassesExceptionTest extends BaseTestCase */ public function testConstructorMessage($parentClass, array $childClasses, $expectedMessage) { - $exception = new TooManyChildClassesException($parentClass, $childClasses); + $exception = TooManyChildClassesException::create($parentClass, $childClasses); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php b/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php index 9cbd34f..1200995 100644 --- a/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php +++ b/tests/Exception/Regex/IncorrectColorHexLengthExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while length of given hexadecimal value of color is incorrect * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class IncorrectColorHexLengthExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(IncorrectColorHexLengthException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + static::assertConstructorVisibilityAndArguments(IncorrectColorHexLengthException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -34,7 +34,7 @@ class IncorrectColorHexLengthExceptionTest extends BaseTestCase */ public function testConstructorMessage($color, $expectedMessage) { - $exception = new IncorrectColorHexLengthException($color); + $exception = IncorrectColorHexLengthException::create($color); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php b/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php index 7376676..6153f0d 100644 --- a/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php +++ b/tests/Exception/Regex/InvalidColorHexValueExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while given hexadecimal value of color is invalid * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class InvalidColorHexValueExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(InvalidColorHexValueException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + static::assertConstructorVisibilityAndArguments(InvalidColorHexValueException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -34,7 +34,7 @@ class InvalidColorHexValueExceptionTest extends BaseTestCase */ public function testConstructorMessage($color, $expectedMessage) { - $exception = new InvalidColorHexValueException($color); + $exception = InvalidColorHexValueException::create($color); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php b/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php new file mode 100644 index 0000000..f343830 --- /dev/null +++ b/tests/Exception/Regex/InvalidHtmlAttributesExceptionTest.php @@ -0,0 +1,65 @@ + + * @copyright Meritoo + */ +class InvalidHtmlAttributesExceptionTest extends BaseTestCase +{ + public function testConstructorVisibilityAndArguments() + { + static::assertConstructorVisibilityAndArguments(InvalidHtmlAttributesException::class, OopVisibilityType::IS_PUBLIC, 3); + } + + /** + * @param string $htmlAttributes Invalid html attributes + * @param string $expectedMessage Expected exception's message + * + * @dataProvider provideHtmlAttributes + */ + public function testConstructorMessage($htmlAttributes, $expectedMessage) + { + $exception = InvalidHtmlAttributesException::create($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'), + ]; + } +} diff --git a/tests/Exception/Regex/InvalidUrlExceptionTest.php b/tests/Exception/Regex/InvalidUrlExceptionTest.php index 735bae3..1670aca 100644 --- a/tests/Exception/Regex/InvalidUrlExceptionTest.php +++ b/tests/Exception/Regex/InvalidUrlExceptionTest.php @@ -16,14 +16,14 @@ use Meritoo\Common\Type\OopVisibilityType; /** * Test case of an exception used while url is invalid * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class InvalidUrlExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(InvalidUrlException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + static::assertConstructorVisibilityAndArguments(InvalidUrlException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -34,7 +34,7 @@ class InvalidUrlExceptionTest extends BaseTestCase */ public function testConstructorMessage($url, $expectedMessage) { - $exception = new InvalidUrlException($url); + $exception = InvalidUrlException::create($url); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php b/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php index b522263..e958a97 100644 --- a/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php +++ b/tests/Exception/Type/UnknownOopVisibilityTypeExceptionTest.php @@ -17,14 +17,14 @@ use Meritoo\Common\Type\OopVisibilityType; * Test case of an exception used while the visibility of a property, a method or (as of PHP 7.1.0) a constant is * unknown * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase { public function testConstructorVisibilityAndArguments() { - static::assertConstructorVisibilityAndArguments(UnknownOopVisibilityTypeException::class, OopVisibilityType::IS_PUBLIC, 1, 1); + static::assertConstructorVisibilityAndArguments(UnknownOopVisibilityTypeException::class, OopVisibilityType::IS_PUBLIC, 3); } /** @@ -35,7 +35,7 @@ class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase */ public function testConstructorMessage($unknownType, $expectedMessage) { - $exception = new UnknownOopVisibilityTypeException($unknownType); + $exception = UnknownOopVisibilityTypeException::createException($unknownType); static::assertEquals($expectedMessage, $exception->getMessage()); } diff --git a/tests/Test/Base/BaseTestCaseTest.php b/tests/Test/Base/BaseTestCaseTest.php index 0a72083..1136686 100644 --- a/tests/Test/Base/BaseTestCaseTest.php +++ b/tests/Test/Base/BaseTestCaseTest.php @@ -17,8 +17,8 @@ use Meritoo\Common\Utilities\GeneratorUtility; /** * Test case of the base test case with common methods and data providers * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class BaseTestCaseTest extends BaseTestCase { @@ -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); } @@ -168,8 +168,8 @@ class BaseTestCaseTest extends BaseTestCase /** * Simple test case * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class SimpleTestCase extends BaseTestCase { diff --git a/tests/Type/Base/BaseTypeTest.php b/tests/Type/Base/BaseTypeTest.php index 0f7399a..1b9b962 100644 --- a/tests/Type/Base/BaseTypeTest.php +++ b/tests/Type/Base/BaseTypeTest.php @@ -15,8 +15,8 @@ use Meritoo\Common\Type\Base\BaseType; /** * Test case of the base / abstract type of something * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class BaseTypeTest extends BaseTestCase { @@ -184,8 +184,8 @@ class BaseTypeTest extends BaseTestCase /** * Empty type of something used for testing * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class TestEmptyType extends BaseType { @@ -194,8 +194,8 @@ class TestEmptyType extends BaseType /** * Type of something used for testing * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class TestType extends BaseType { diff --git a/tests/Type/DatePartTypeTest.php b/tests/Type/DatePartTypeTest.php index 126c5ef..541aa15 100644 --- a/tests/Type/DatePartTypeTest.php +++ b/tests/Type/DatePartTypeTest.php @@ -14,8 +14,8 @@ use Meritoo\Common\Type\DatePartType; /** * Test case of the type of date part, e.g. "year" * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class DatePartTypeTest extends BaseTypeTestCase { diff --git a/tests/Utilities/DatePeriodTest.php b/tests/Type/DatePeriodTest.php similarity index 76% rename from tests/Utilities/DatePeriodTest.php rename to tests/Type/DatePeriodTest.php index ba5a06b..fc6557f 100644 --- a/tests/Utilities/DatePeriodTest.php +++ b/tests/Type/DatePeriodTest.php @@ -6,21 +6,21 @@ * file that was distributed with this source code. */ -namespace Meritoo\Common\Test\Utilities; +namespace Meritoo\Common\Test\Type; use DateTime; use Generator; -use Meritoo\Common\Test\Base\BaseTestCase; +use Meritoo\Common\Test\Base\BaseTypeTestCase; +use Meritoo\Common\Type\DatePeriod; use Meritoo\Common\Type\OopVisibilityType; -use Meritoo\Common\Utilities\DatePeriod; /** * Test case of date's period * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ -class DatePeriodTest extends BaseTestCase +class DatePeriodTest extends BaseTypeTestCase { public function testConstructorVisibilityAndArguments() { @@ -58,33 +58,6 @@ class DatePeriodTest extends BaseTestCase self::assertEquals($endDate, $period->getEndDate()); } - /** - * @param mixed $period Empty value, e.g. "" - * @dataProvider provideEmptyValue - */ - public function testIsCorrectPeriodEmptyPeriod($period) - { - self::assertFalse(DatePeriod::isCorrectPeriod($period)); - } - - /** - * @param int $period Incorrect period to verify - * @dataProvider provideIncorrectPeriod - */ - public function testIsCorrectPeriodIncorrectPeriod($period) - { - self::assertFalse(DatePeriod::isCorrectPeriod($period)); - } - - /** - * @param int $period The period to verify - * @dataProvider providePeriod - */ - public function testIsCorrectPeriod($period) - { - self::assertTrue(DatePeriod::isCorrectPeriod($period)); - } - /** * @param DatePeriod $period The date period to verify * @param string $format Format used to format the date @@ -142,36 +115,6 @@ class DatePeriodTest extends BaseTestCase ]; } - /** - * Provides incorrect period - * - * @return Generator - */ - public function provideIncorrectPeriod() - { - yield[-1]; - yield[0]; - yield[10]; - } - - /** - * Provides period to verify - * - * @return Generator - */ - public function providePeriod() - { - yield[DatePeriod::LAST_WEEK]; - yield[DatePeriod::THIS_WEEK]; - yield[DatePeriod::NEXT_WEEK]; - yield[DatePeriod::LAST_MONTH]; - yield[DatePeriod::THIS_MONTH]; - yield[DatePeriod::NEXT_MONTH]; - yield[DatePeriod::LAST_YEAR]; - yield[DatePeriod::THIS_YEAR]; - yield[DatePeriod::NEXT_YEAR]; - } - /** * Provides period and incorrect format of date to verify * @@ -270,4 +213,68 @@ class DatePeriodTest extends BaseTestCase '2002-02-02 00:00', ]; } + + /** + * Returns all expected types of the tested type + * + * @return array + */ + protected function getAllExpectedTypes() + { + return [ + 'LAST_MONTH' => DatePeriod::LAST_MONTH, + 'LAST_WEEK' => DatePeriod::LAST_WEEK, + 'LAST_YEAR' => DatePeriod::LAST_YEAR, + 'NEXT_MONTH' => DatePeriod::NEXT_MONTH, + 'NEXT_WEEK' => DatePeriod::NEXT_WEEK, + 'NEXT_YEAR' => DatePeriod::NEXT_YEAR, + 'THIS_MONTH' => DatePeriod::THIS_MONTH, + 'THIS_WEEK' => DatePeriod::THIS_WEEK, + 'THIS_YEAR' => DatePeriod::THIS_YEAR, + ]; + } + + /** + * {@inheritdoc} + */ + protected function getTestedTypeInstance() + { + return new DatePeriod(); + } + + /** + * {@inheritdoc} + */ + public function provideTypeToVerify() + { + yield[ + '', + false, + ]; + + yield[ + -1, + false, + ]; + + yield[ + true, + false, + ]; + + yield[ + DatePeriod::LAST_MONTH, + true, + ]; + + yield[ + DatePeriod::NEXT_WEEK, + true, + ]; + + yield[ + DatePeriod::THIS_YEAR, + true, + ]; + } } diff --git a/tests/Utilities/ArraysTest.php b/tests/Utilities/ArraysTest.php index 72985d6..d43da0d 100644 --- a/tests/Utilities/ArraysTest.php +++ b/tests/Utilities/ArraysTest.php @@ -14,8 +14,8 @@ use Meritoo\Common\Utilities\Arrays; /** * Test case of the useful arrays methods * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class ArraysTest extends BaseTestCase { @@ -517,7 +517,12 @@ letsTest[2] = value_2;'; self::assertTrue(Arrays::areKeysInArray($keys17, $this->complexArray, false)); } - public function testGetLastElementsPaths() + public function testGetLastElementsPathsUsingEmptyArray() + { + self::assertSame([], Arrays::getLastElementsPaths([])); + } + + public function testGetLastElementsPathsUsingDefaults() { /* * Using default separator and other default arguments @@ -536,7 +541,10 @@ letsTest[2] = value_2;'; ]; self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray)); + } + public function testGetLastElementsPathsUsingCustomSeparator() + { /* * Using custom separator */ @@ -555,204 +563,20 @@ letsTest[2] = value_2;'; ]; self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray, $separator)); + } - /* - * Special exception: do not use, stop recursive on the "diam" key - */ - $expected = [ - 'lorem.ipsum.dolor' => 'sit', - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit.nullam' => 'donec', - 'sit.aliquet.vitae.ligula' => 'quis', - 'sit.0' => 'elit', - 'amet.0' => 'iaculis', - 'amet.1' => 'primis', - 'lorem.ipsum.diam' => [ - 'non' => 'egestas', - ], - ]; - - $stopIfMatchedBy = 'diam'; - self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray, '.', '', $stopIfMatchedBy)); - - /* - * Stop building of paths on these keys: - * - "diam" - * - "aliquet" - */ - $expected = [ - 'lorem . ipsum . dolor' => 'sit', - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit . nullam' => 'donec', - 'sit . 0' => 'elit', - 'amet . 0' => 'iaculis', - 'amet . 1' => 'primis', - 'lorem . ipsum . diam' => [ - 'non' => 'egestas', - ], - 'sit . aliquet' => [ - 'vitae' => [ - 'ligula' => 'quis', - ], - ], - ]; - - $stopIfMatchedBy = [ - 'diam', - 'aliquet', - ]; - - self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray, ' . ', '', $stopIfMatchedBy)); - - $expected = [ - 'ipsum > quis > vestibulum > porta-1' => [ - 'turpis', - 'urna', - ], - 'ipsum > quis > vestibulum > porta-2' => [ - 'tortor' => [ - 'in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - ], - ], - 'ipsum > quis > vestibulum > porta-3' => [ - 1, - 2, - 3, - ], - 'primis > 0' => [ - 'in', - 'faucibus', - 'orci', - ], - 'primis > 1' => [ - 'luctus', - 'et', - 'ultrices', - ], - ]; - - /* - * Stop building of paths on more sophisticated keys - */ - $stopIfMatchedBy = [ - 'porta\-\d+', - '^\d+$', - ]; - - self::assertEquals($expected, Arrays::getLastElementsPaths($this->superComplexArray, ' > ', '', $stopIfMatchedBy)); - - /* - * Stop building of paths on these: - * - keys - * and - * - paths (verify paths too) - */ - $expected = [ - 'lorem > ipsum > dolor' => 'sit', - 'consectetur' => 'adipiscing', - 'mollis' => 1234, - 2 => [], - 'sit > nullam' => 'donec', - 'sit > 0' => 'elit', - 'amet > 0' => 'iaculis', - 'amet > 1' => 'primis', - 'lorem > ipsum > diam' => [ - 'non' => 'egestas', - ], - 'sit > aliquet > vitae' => [ - 'ligula' => 'quis', - ], - ]; - - $stopIfMatchedBy = [ - 'diam', - 'sit > aliquet > vitae', - ]; - - self::assertEquals($expected, Arrays::getLastElementsPaths($this->complexArray, ' > ', '', $stopIfMatchedBy)); - - /* - * Stop building of paths on these paths (verify paths only) - */ - $expected = [ - 'ipsum > quis > vestibulum > porta-1' => [ - 'turpis', - 'urna', - ], - 'ipsum > quis > vestibulum > porta-2 > tortor' => [ - 'in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - ], - 'ipsum > quis > vestibulum > porta-3 > 0' => 1, - 'ipsum > quis > vestibulum > porta-3 > 1' => 2, - 'ipsum > quis > vestibulum > porta-3 > 2' => 3, - 'primis > 0 > 0' => 'in', - 'primis > 0 > 1' => 'faucibus', - 'primis > 0 > 2' => 'orci', - 'primis > 1' => [ - 'luctus', - 'et', - 'ultrices', - ], - ]; - - $stopIfMatchedBy = [ - 'ipsum > quis > vestibulum > porta-1', - 'ipsum > quis > vestibulum > porta-2 > tortor', - 'primis > 1', - ]; - - self::assertEquals($expected, Arrays::getLastElementsPaths($this->superComplexArray, ' > ', '', $stopIfMatchedBy)); - - /* - * Stop building of paths if path contains any of these part (verify part of paths only) - */ - $expected = [ - 'ipsum > quis > vestibulum > porta-1' => [ - 'turpis', - 'urna', - ], - 'ipsum > quis > vestibulum > porta-2 > tortor > in' => [ - 'dui', - 'dolor' => [ - 'aliquam', - ], - ], - 'ipsum > quis > vestibulum > porta-3 > 0' => 1, - 'ipsum > quis > vestibulum > porta-3 > 1' => 2, - 'ipsum > quis > vestibulum > porta-3 > 2' => 3, - 'primis > 0' => [ - 'in', - 'faucibus', - 'orci', - ], - 'primis > 1' => [ - 'luctus', - 'et', - 'ultrices', - ], - ]; - - $stopIfMatchedBy = [ - 'vestibulum > porta-1', - 'tortor > in', - '[a-z]+ > \d+', - ]; - - self::assertEquals($expected, Arrays::getLastElementsPaths($this->superComplexArray, ' > ', '', $stopIfMatchedBy)); + /** + * @param string|array $stopIfMatchedBy Patterns of keys or paths that matched will stop the process of path + * building and including children of those keys or paths (recursive will + * not be used for keys in lower level of given array) + * @param string $separator Separator used in resultant strings. Default: ".". + * @param array $expected Expected array + * + * @dataProvider provideStopIfMatchedByForGetLastElementsPaths + */ + public function testGetLastElementsPathsUsingStopIfMatchedBy($stopIfMatchedBy, $separator, array $expected) + { + self::assertEquals($expected, Arrays::getLastElementsPaths($this->superComplexArray, $separator, '', $stopIfMatchedBy)); } public function testAreAllKeysMatchedByPattern() @@ -1760,6 +1584,229 @@ letsTest[2] = value_2;'; ]; } + /** + * Provides patterns of keys or paths that matched will stop the process and the expected array for the + * getLastElementsPaths() method + * + * @return \Generator + */ + public function provideStopIfMatchedByForGetLastElementsPaths() + { + /* + * Special exception: do not use, stop recursive on the "diam" key + */ + yield[ + 'diam', + '.', + [ + 'ipsum.quis.vestibulum.porta-1.0' => 'turpis', + 'ipsum.quis.vestibulum.porta-1.1' => 'urna', + 'ipsum.quis.vestibulum.porta-2.tortor.in.0' => 'dui', + 'ipsum.quis.vestibulum.porta-2.tortor.in.dolor.0' => 'aliquam', + 'ipsum.quis.vestibulum.porta-3.0' => 1, + 'ipsum.quis.vestibulum.porta-3.1' => 2, + 'ipsum.quis.vestibulum.porta-3.2' => 3, + 'primis.0.0' => 'in', + 'primis.0.1' => 'faucibus', + 'primis.0.2' => 'orci', + 'primis.1.0' => 'luctus', + 'primis.1.1' => 'et', + 'primis.1.2' => 'ultrices', + ], + ]; + + /* + * Stop building of paths on these keys: + * - "tortor" + * - "primis" + */ + yield[ + [ + 'tortor', + 'primis', + ], + ' . ', + [ + 'ipsum . quis . vestibulum . porta-1 . 0' => 'turpis', + 'ipsum . quis . vestibulum . porta-1 . 1' => 'urna', + 'ipsum . quis . vestibulum . porta-2 . tortor' => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + 'ipsum . quis . vestibulum . porta-3 . 0' => 1, + 'ipsum . quis . vestibulum . porta-3 . 1' => 2, + 'ipsum . quis . vestibulum . porta-3 . 2' => 3, + 'primis' => [ + [ + 'in', + 'faucibus', + 'orci', + ], + [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ], + ]; + + /* + * Stop building of paths on more sophisticated keys + */ + yield[ + [ + 'porta\-\d+', + '^\d+$', + ], + ' > ', + [ + 'ipsum > quis > vestibulum > porta-1' => [ + 'turpis', + 'urna', + ], + 'ipsum > quis > vestibulum > porta-2' => [ + 'tortor' => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + ], + 'ipsum > quis > vestibulum > porta-3' => [ + 1, + 2, + 3, + ], + 'primis > 0' => [ + 'in', + 'faucibus', + 'orci', + ], + 'primis > 1' => [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ]; + + /* + * Stop building of paths on these: + * - keys + * and + * - paths (verify paths too) + */ + yield[ + [ + 'porta-1', + 'porta-2 > tortor > in', + ], + ' > ', + [ + 'ipsum > quis > vestibulum > porta-1' => [ + 'turpis', + 'urna', + ], + 'ipsum > quis > vestibulum > porta-2 > tortor > in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + 'ipsum > quis > vestibulum > porta-3 > 0' => 1, + 'ipsum > quis > vestibulum > porta-3 > 1' => 2, + 'ipsum > quis > vestibulum > porta-3 > 2' => 3, + 'primis > 0 > 0' => 'in', + 'primis > 0 > 1' => 'faucibus', + 'primis > 0 > 2' => 'orci', + 'primis > 1 > 0' => 'luctus', + 'primis > 1 > 1' => 'et', + 'primis > 1 > 2' => 'ultrices', + ], + ]; + + /* + * Stop building of paths on these paths (verify paths only) + */ + yield[ + [ + 'ipsum > quis > vestibulum > porta-1', + 'ipsum > quis > vestibulum > porta-2 > tortor', + 'primis > 1', + ], + ' > ', + [ + 'ipsum > quis > vestibulum > porta-1' => [ + 'turpis', + 'urna', + ], + 'ipsum > quis > vestibulum > porta-2 > tortor' => [ + 'in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + ], + 'ipsum > quis > vestibulum > porta-3 > 0' => 1, + 'ipsum > quis > vestibulum > porta-3 > 1' => 2, + 'ipsum > quis > vestibulum > porta-3 > 2' => 3, + 'primis > 0 > 0' => 'in', + 'primis > 0 > 1' => 'faucibus', + 'primis > 0 > 2' => 'orci', + 'primis > 1' => [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ]; + + /* + * Stop building of paths if path contains any of these part (verify part of paths only) + */ + yield[ + [ + 'vestibulum > porta-1', + 'tortor > in', + '[a-z]+ > \d+', + ], + ' > ', + [ + 'ipsum > quis > vestibulum > porta-1' => [ + 'turpis', + 'urna', + ], + 'ipsum > quis > vestibulum > porta-2 > tortor > in' => [ + 'dui', + 'dolor' => [ + 'aliquam', + ], + ], + 'ipsum > quis > vestibulum > porta-3 > 0' => 1, + 'ipsum > quis > vestibulum > porta-3 > 1' => 2, + 'ipsum > quis > vestibulum > porta-3 > 2' => 3, + 'primis > 0' => [ + 'in', + 'faucibus', + 'orci', + ], + 'primis > 1' => [ + 'luctus', + 'et', + 'ultrices', + ], + ], + ]; + } + /** * {@inheritdoc} */ @@ -1877,10 +1924,12 @@ letsTest[2] = value_2;'; { parent::tearDown(); - unset($this->simpleArray); - unset($this->simpleArrayWithKeys); - unset($this->twoDimensionsArray); - unset($this->complexArray); - unset($this->superComplexArray); + unset( + $this->simpleArray, + $this->simpleArrayWithKeys, + $this->twoDimensionsArray, + $this->complexArray, + $this->superComplexArray + ); } } diff --git a/tests/Utilities/Bootstrap4CssSelectorTest.php b/tests/Utilities/Bootstrap4CssSelectorTest.php new file mode 100644 index 0000000..c2aa462 --- /dev/null +++ b/tests/Utilities/Bootstrap4CssSelectorTest.php @@ -0,0 +1,185 @@ + + * @copyright Meritoo + */ +class Bootstrap4CssSelectorTest extends BaseTestCase +{ + public function testConstructor() + { + static::assertHasNoConstructor(Bootstrap4CssSelector::class); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetRadioButtonErrorSelectorUsingEmptyFormName($emptyValue) + { + $fieldSetIndex = 1; + static::assertSame('', Bootstrap4CssSelector::getRadioButtonErrorSelector($emptyValue, $fieldSetIndex)); + } + + public function testGetRadioButtonErrorSelectorUsingNegativeFieldSetIndex() + { + static::assertSame('', Bootstrap4CssSelector::getRadioButtonErrorSelector('test-test', -1)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param int $fieldSetIndex Index/Position of the field-set + * @param string $expected Expected selector + * + * @dataProvider provideFormNameFieldSetIndexAndSelector + */ + public function testGetRadioButtonErrorSelector($formName, $fieldSetIndex, $expected) + { + static::assertSame($expected, Bootstrap4CssSelector::getRadioButtonErrorSelector($formName, $fieldSetIndex)); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetFieldErrorSelectorUsingEmptyFormName($emptyValue) + { + $fieldName = 'test'; + static::assertSame('', Bootstrap4CssSelector::getFieldErrorSelector($emptyValue, $fieldName)); + } + + /** + * @param string $emptyValue Name of field (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetFieldErrorSelectorUsingEmptyFieldName($emptyValue) + { + $formName = 'test'; + static::assertSame('', Bootstrap4CssSelector::getFieldErrorSelector($formName, $emptyValue)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldName Name of field (value of the "name" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameFieldNameAndSelector + */ + public function testGetFieldErrorSelector($formName, $fieldName, $expected) + { + static::assertSame($expected, Bootstrap4CssSelector::getFieldErrorSelector($formName, $fieldName)); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetFieldGroupSelectorUsingEmptyFormName($emptyValue) + { + static::assertSame('', Bootstrap4CssSelector::getFieldGroupSelector($emptyValue)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameAndSelector + */ + public function testGetFieldGroupSelector($formName, $expected) + { + static::assertSame($expected, Bootstrap4CssSelector::getFieldGroupSelector($formName)); + } + + public function testGetFieldErrorContainerSelector() + { + static::assertSame('.invalid-feedback .form-error-message', Bootstrap4CssSelector::getFieldErrorContainerSelector()); + } + + /** + * Provides name of form, index/position of the field-set and expected selector + * + * @return \Generator + */ + public function provideFormNameFieldSetIndexAndSelector() + { + yield[ + 'test', + 0, + 'form[name="test"] fieldset:nth-of-type(0) legend.col-form-label .invalid-feedback .form-error-message', + ]; + + yield[ + 'test-123-test-456', + 1, + 'form[name="test-123-test-456"] fieldset:nth-of-type(1) legend.col-form-label .invalid-feedback .form-error-message', + ]; + + yield[ + 'test_something_098_different', + 1245, + 'form[name="test_something_098_different"] fieldset:nth-of-type(1245) legend.col-form-label .invalid-feedback .form-error-message', + ]; + } + + /** + * Provides name of form, name of field and expected selector + * + * @return \Generator + */ + public function provideFormNameFieldNameAndSelector() + { + yield[ + 'test', + 'test', + 'form[name="test"] label[for="test"] .invalid-feedback .form-error-message', + ]; + + yield[ + 'test-123-test-456', + 'great-000-field', + 'form[name="test-123-test-456"] label[for="great-000-field"] .invalid-feedback .form-error-message', + ]; + + yield[ + 'test_something_098_different', + 'this-is-the-123789-field', + 'form[name="test_something_098_different"] label[for="this-is-the-123789-field"] .invalid-feedback .form-error-message', + ]; + } + + /** + * Provides name of form and expected selector + * + * @return \Generator + */ + public function provideFormNameAndSelector() + { + yield[ + 'test', + 'form[name="test"] .form-group', + ]; + + yield[ + 'test-123-test-456', + 'form[name="test-123-test-456"] .form-group', + ]; + + yield[ + 'test_something_098_different', + 'form[name="test_something_098_different"] .form-group', + ]; + } +} diff --git a/tests/Utilities/BundleTest.php b/tests/Utilities/BundleTest.php index f7af8b1..a8fe474 100644 --- a/tests/Utilities/BundleTest.php +++ b/tests/Utilities/BundleTest.php @@ -8,14 +8,16 @@ namespace Meritoo\Common\Test\Utilities; +use Generator; +use Meritoo\Common\Exception\Bundle\IncorrectBundleNameException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Bundle; /** * Test case of the useful methods for bundle * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class BundleTest extends BaseTestCase { @@ -24,22 +26,227 @@ 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" + * + * @throws IncorrectBundleNameException + * @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" + * + * @dataProvider provideViewPathAndIncorrectBundleName + */ + public function testGetBundleViewPathUsingIncorrectBundleName($viewPath, $bundleName) { - self::assertEquals('Lorem:Ipsum.html.twig', Bundle::getBundleViewPath('Ipsum', 'Lorem')); - self::assertEquals('LobortisTincidunt:FusceElementum.html.twig', Bundle::getBundleViewPath('FusceElementum', 'LobortisTincidunt')); + $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); } - 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 $expected Expected path to view / template + * + * @throws IncorrectBundleNameException + * @dataProvider provideViewPathAndBundle + */ + public function testGetBundleViewPathUsingDefaultExtension($viewPath, $bundleName, $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)); + } + + /** + * @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 + * + * @throws IncorrectBundleNameException + * @dataProvider provideViewPathAndBundleAndExtension + */ + public function testGetBundleViewPathUsingCustomExtension($viewPath, $bundleName, $extension, $expected) + { + 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 + * + * @return Generator + */ + public function provideEmptyViewPathAndBundle() + { + yield[ + '', + '', + ]; + + yield[ + 'test', + '', + ]; + + yield[ + '', + 'test', + ]; + } + + /** + * 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 + * + * @return Generator + */ + public function provideViewPathAndBundle() + { + yield[ + 'User', + 'MyExtraBundle', + '@MyExtra/User.html.twig', + ]; + + yield[ + 'User:Active', + 'MyExtraBundle', + '@MyExtra/User/Active.html.twig', + ]; + + yield[ + 'User:Active', + 'MySuperExtraGorgeousBundle', + '@MySuperExtraGorgeous/User/Active.html.twig', + ]; + } + + /** + * Provides path of the view / template, name of bundle and extension of the view / template + * + * @return Generator + */ + public function provideViewPathAndBundleAndExtension() + { + yield[ + 'User:Active', + 'MyExtraBundle', + '', + null, + ]; + + yield[ + 'User:Active', + 'MyExtraBundle', + '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/ComposerTest.php b/tests/Utilities/ComposerTest.php index 72d5881..b526c5e 100644 --- a/tests/Utilities/ComposerTest.php +++ b/tests/Utilities/ComposerTest.php @@ -15,8 +15,8 @@ use Meritoo\Common\Utilities\Composer; /** * Test case of the useful Composer-related methods * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class ComposerTest extends BaseTestCase { diff --git a/tests/Utilities/CssSelectorTest.php b/tests/Utilities/CssSelectorTest.php new file mode 100644 index 0000000..f85fa53 --- /dev/null +++ b/tests/Utilities/CssSelectorTest.php @@ -0,0 +1,296 @@ + + * @copyright Meritoo + */ +class CssSelectorTest extends BaseTestCase +{ + public function testConstructor() + { + static::assertHasNoConstructor(CssSelector::class); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetFormByNameSelectorUsingEmptyName($emptyValue) + { + static::assertSame('', CssSelector::getFormByNameSelector($emptyValue)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameAndSelector + */ + public function testGetFormByNameSelector($formName, $expected) + { + static::assertSame($expected, CssSelector::getFormByNameSelector($formName)); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetInputByNameSelectorUsingEmptyFormName($emptyValue) + { + $fieldName = 'test-test'; + static::assertSame('', CssSelector::getInputByNameSelector($emptyValue, $fieldName)); + } + + /** + * @param string $emptyValue Name of field (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetInputByNameSelectorUsingEmptyFieldName($emptyValue) + { + $formName = 'test-test'; + static::assertSame('', CssSelector::getInputByNameSelector($formName, $emptyValue)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldName Name of field (value of the "name" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameFieldNameAndSelector + */ + public function testGetInputByNameSelector($formName, $fieldName, $expected) + { + static::assertSame($expected, CssSelector::getInputByNameSelector($formName, $fieldName)); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetInputByIdSelectorUsingEmptyFormName($emptyValue) + { + $fieldId = 'test-test'; + static::assertSame('', CssSelector::getInputByIdSelector($emptyValue, $fieldId)); + } + + /** + * @param string $emptyValue ID of field (value of the "id" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetInputByIdSelectorUsingEmptyFieldName($emptyValue) + { + $formName = 'test-test'; + static::assertSame('', CssSelector::getInputByIdSelector($formName, $emptyValue)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldId ID of field (value of the "id" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameFieldIdAndSelector + */ + public function testGetInputByIdSelector($formName, $fieldId, $expected) + { + static::assertSame($expected, CssSelector::getInputByIdSelector($formName, $fieldId)); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetLabelSelectorUsingEmptyFormName($emptyValue) + { + $fieldId = 'test-test'; + static::assertSame('', CssSelector::getLabelSelector($emptyValue, $fieldId)); + } + + /** + * @param string $emptyValue ID of field (value of the "id" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetLabelSelectorUsingEmptyFieldId($emptyValue) + { + $formName = 'test-test'; + static::assertSame('', CssSelector::getLabelSelector($formName, $emptyValue)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param string $fieldId ID of field (value of the "id" attribute) + * @param string $expected Expected selector + * + * @dataProvider provideFormNameFieldIdAndLabelSelector + */ + public function testGetLabelSelector($formName, $fieldId, $expected) + { + static::assertSame($expected, CssSelector::getLabelSelector($formName, $fieldId)); + } + + /** + * @param string $emptyValue Name of form (value of the "name" attribute) + * @dataProvider provideEmptyScalarValue + */ + public function testGetFieldSetByIndexSelectorUsingEmptyFormName($emptyValue) + { + $fieldSetIndex = 1; + static::assertSame('', CssSelector::getFieldSetByIndexSelector($emptyValue, $fieldSetIndex)); + } + + public function testGetFieldSetByIndexSelectorUsingNegativeFieldSetIndex() + { + static::assertSame('', CssSelector::getFieldSetByIndexSelector('test-test', -1)); + } + + /** + * @param string $formName Name of form (value of the "name" attribute) + * @param int $fieldSetIndex Index/Position of the field-set + * @param string $expected Expected selector + * + * @dataProvider provideFormNameFieldSetIndexAndSelector + */ + public function testGetFieldSetByIndexSelector($formName, $fieldSetIndex, $expected) + { + static::assertSame($expected, CssSelector::getFieldSetByIndexSelector($formName, $fieldSetIndex)); + } + + /** + * Provides name of form and selector of the form + * + * @return \Generator + */ + public function provideFormNameAndSelector() + { + yield[ + 'test', + 'form[name="test"]', + ]; + + yield[ + 'test-123-test-456', + 'form[name="test-123-test-456"]', + ]; + + yield[ + 'test_something_098_different', + 'form[name="test_something_098_different"]', + ]; + } + + /** + * Provides name of form, name of field and expected selector + * + * @return \Generator + */ + public function provideFormNameFieldNameAndSelector() + { + yield[ + 'test', + 'test', + 'form[name="test"] input[name="test"]', + ]; + + yield[ + 'test-123-test-456', + 'great-000-field', + 'form[name="test-123-test-456"] input[name="great-000-field"]', + ]; + + yield[ + 'test_something_098_different', + 'this-is-the-123789-field', + 'form[name="test_something_098_different"] input[name="this-is-the-123789-field"]', + ]; + } + + /** + * Provides name of form, ID of field and expected selector of label + * + * @return \Generator + */ + public function provideFormNameFieldIdAndLabelSelector() + { + yield[ + 'test', + 'test', + 'form[name="test"] label[for="test"]', + ]; + + yield[ + 'test-123-test-456', + 'great-000-field', + 'form[name="test-123-test-456"] label[for="great-000-field"]', + ]; + + yield[ + 'test_something_098_different', + 'this-is-the-123789-field', + 'form[name="test_something_098_different"] label[for="this-is-the-123789-field"]', + ]; + } + + /** + * Provides name of form, index/position of the field-set and expected selector + * + * @return \Generator + */ + public function provideFormNameFieldSetIndexAndSelector() + { + yield[ + 'test', + 0, + 'form[name="test"] fieldset:nth-of-type(0)', + ]; + + yield[ + 'test-123-test-456', + 1, + 'form[name="test-123-test-456"] fieldset:nth-of-type(1)', + ]; + + yield[ + 'test_something_098_different', + 1245, + 'form[name="test_something_098_different"] fieldset:nth-of-type(1245)', + ]; + } + + /** + * Provides name of form, ID of field and expected selector + * + * @return \Generator + */ + public function provideFormNameFieldIdAndSelector() + { + yield[ + 'test', + 'test', + 'form[name="test"] input#test', + ]; + + yield[ + 'test-123-test-456', + 'great-000-field', + 'form[name="test-123-test-456"] input#great-000-field', + ]; + + yield[ + 'test_something_098_different', + 'this-is-the-123789-field', + 'form[name="test_something_098_different"] input#this-is-the-123789-field', + ]; + } +} diff --git a/tests/Utilities/DateTest.php b/tests/Utilities/DateTest.php index f750520..bcf9cd6 100644 --- a/tests/Utilities/DateTest.php +++ b/tests/Utilities/DateTest.php @@ -11,15 +11,16 @@ namespace Meritoo\Common\Test\Utilities; use DateInterval; use DateTime; use Generator; -use Meritoo\Common\Exception\Date\UnknownDatePartTypeException; +use Meritoo\Common\Exception\Type\UnknownDatePartTypeException; use Meritoo\Common\Test\Base\BaseTestCase; +use Meritoo\Common\Type\DatePeriod; use Meritoo\Common\Utilities\Date; /** * Test case of the Date methods (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class DateTest extends BaseTestCase { @@ -506,6 +507,35 @@ class DateTest extends BaseTestCase self::assertTrue($randomDate >= $intervalMinDate && $randomDate <= $intervalMaxDate); } + /** + * @param mixed $period Empty value, e.g. "" + * @dataProvider provideEmptyValue + */ + public function testGetDatesForPeriodUsingEmptyPeriod($period) + { + self::assertNull(Date::getDatesForPeriod($period)); + } + + /** + * @param int $period Incorrect period to verify + * @dataProvider provideIncorrectPeriod + */ + public function testGetDatesForPeriodUsingIncorrectPeriod($period) + { + self::assertNull(Date::getDatesForPeriod($period)); + } + + /** + * @param int $period The period, type of period. One of DatePeriod class constants, e.g. DatePeriod::LAST_WEEK. + * @param DatePeriod $expected Expected start and end date for given period + * + * @dataProvider provideCorrectPeriod + */ + public function testGetDatesForPeriod($period, DatePeriod $expected) + { + self::assertEquals($expected, Date::getDatesForPeriod($period)); + } + /** * Provides incorrect invalidCount of DateTime * @@ -758,4 +788,112 @@ class DateTest extends BaseTestCase 50, ]; } + + /** + * Provides incorrect period + * + * @return Generator + */ + public function provideIncorrectPeriod() + { + yield[-1]; + yield[0]; + yield[10]; + } + + /** + * Provides correct period + * + * @return Generator + */ + public function provideCorrectPeriod() + { + yield[ + DatePeriod::LAST_WEEK, + new DatePeriod( + (new DateTime('this week'))->sub(new DateInterval('P7D'))->setTime(0, 0, 0), + (new DateTime('this week'))->sub(new DateInterval('P1D'))->setTime(23, 59, 59) + ), + ]; + + yield[ + DatePeriod::THIS_WEEK, + new DatePeriod( + (new DateTime('this week'))->setTime(0, 0, 0), + (new DateTime('this week'))->add(new DateInterval('P6D'))->setTime(23, 59, 59) + ), + ]; + + yield[ + DatePeriod::NEXT_WEEK, + new DatePeriod( + (new DateTime('this week'))->add(new DateInterval('P7D'))->setTime(0, 0, 0), + (new DateTime('this week'))->add(new DateInterval('P7D'))->add(new DateInterval('P6D'))->setTime(23, 59, 59) + ), + ]; + + yield[ + DatePeriod::LAST_MONTH, + new DatePeriod( + (new DateTime('first day of last month'))->setTime(0, 0, 0), + (new DateTime('last day of last month'))->setTime(23, 59, 59) + ), + ]; + + yield[ + DatePeriod::THIS_MONTH, + new DatePeriod( + Date::getDatesForPeriod(DatePeriod::LAST_MONTH) + ->getEndDate() + ->add(new DateInterval('P1D')) + ->setTime(0, 0, 0), + Date::getDatesForPeriod(DatePeriod::NEXT_MONTH) + ->getStartDate() + ->sub(new DateInterval('P1D')) + ->setTime(23, 59, 59) + ), + ]; + + yield[ + DatePeriod::NEXT_MONTH, + new DatePeriod( + (new DateTime('first day of next month'))->setTime(0, 0, 0), + (new DateTime('last day of next month'))->setTime(23, 59, 59) + ), + ]; + + $lastYearStart = (new DateTime())->modify('-1 year'); + $lastYearEnd = (new DateTime())->modify('-1 year'); + $year = $lastYearStart->format('Y'); + + yield[ + DatePeriod::LAST_YEAR, + new DatePeriod( + $lastYearStart->setDate($year, 1, 1)->setTime(0, 0, 0), + $lastYearEnd->setDate($year, 12, 31)->setTime(23, 59, 59) + ), + ]; + + $year = (new DateTime())->format('Y'); + + yield[ + DatePeriod::THIS_YEAR, + new DatePeriod( + (new DateTime())->setDate($year, 1, 1)->setTime(0, 0, 0), + (new DateTime())->setDate($year, 12, 31)->setTime(23, 59, 59) + ), + ]; + + $nextYearStart = (new DateTime())->modify('1 year'); + $nextYearEnd = (new DateTime())->modify('1 year'); + $year = $nextYearStart->format('Y'); + + yield[ + DatePeriod::NEXT_YEAR, + new DatePeriod( + $nextYearStart->setDate($year, 1, 1)->setTime(0, 0, 0), + $nextYearEnd->setDate($year, 12, 31)->setTime(23, 59, 59) + ), + ]; + } } diff --git a/tests/Utilities/GeneratorUtilityTest.php b/tests/Utilities/GeneratorUtilityTest.php index 6dbebff..27cf5d7 100644 --- a/tests/Utilities/GeneratorUtilityTest.php +++ b/tests/Utilities/GeneratorUtilityTest.php @@ -14,8 +14,8 @@ use Meritoo\Common\Utilities\GeneratorUtility; /** * Test case of the useful methods for the Generator class * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class GeneratorUtilityTest extends BaseTestCase { diff --git a/tests/Utilities/LocaleTest.php b/tests/Utilities/LocaleTest.php index d3f089c..5ad4d90 100644 --- a/tests/Utilities/LocaleTest.php +++ b/tests/Utilities/LocaleTest.php @@ -11,15 +11,19 @@ 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 * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class LocaleTest extends BaseTestCase { + /** + * @throws ReflectionException + */ public function testConstructor() { static::assertHasNoConstructor(Locale::class); @@ -40,7 +44,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 +60,46 @@ 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)); + } + + /** + * @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 * * @return Generator */ - public function provideLanguageAndCountryCode() + public function provideLanguageEncodingAndCountryCode() { yield[ 'fr', @@ -102,33 +128,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', ]; } } diff --git a/tests/Utilities/MimeTypesTest.php b/tests/Utilities/MimeTypesTest.php index 4452ec2..b51e7f2 100644 --- a/tests/Utilities/MimeTypesTest.php +++ b/tests/Utilities/MimeTypesTest.php @@ -15,8 +15,8 @@ use Meritoo\Common\Utilities\MimeTypes; /** * Test case of the useful methods for mime types of files * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class MimeTypesTest extends BaseTestCase { diff --git a/tests/Utilities/MiscellaneousTest.php b/tests/Utilities/MiscellaneousTest.php index 90cb155..aa54c6a 100644 --- a/tests/Utilities/MiscellaneousTest.php +++ b/tests/Utilities/MiscellaneousTest.php @@ -14,20 +14,25 @@ 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; /** * Test case of the Miscellaneous methods (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class MiscellaneousTest extends BaseTestCase { private $stringSmall; private $stringCommaSeparated; private $stringDotSeparated; + private $stringWithoutSpaces; + /** + * @throws ReflectionException + */ public function testConstructor() { static::assertHasNoConstructor(Miscellaneous::class); @@ -159,7 +164,7 @@ class MiscellaneousTest extends BaseTestCase $expected = "int(123)\n"; if ($xdebugLoaded) { - $libraryPath = realpath(sprintf('%s%s', dirname(__FILE__), '/../..')); + $libraryPath = realpath(sprintf('%s%s', __DIR__, '/../..')); $filePath = sprintf('%s%s', $libraryPath, '/src/Utilities/Miscellaneous.php:'); /* @@ -343,7 +348,10 @@ class MiscellaneousTest extends BaseTestCase public function testGetOperatingSystemNameServer() { - self::assertEquals(php_uname('s'), Miscellaneous::getOperatingSystemNameServer()); + /* + * While running Docker OS is a Linux + */ + self::assertEquals('Linux', Miscellaneous::getOperatingSystemNameServer()); } public function testSubstringToWord() @@ -361,37 +369,36 @@ 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 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 +668,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 +686,10 @@ class MiscellaneousTest extends BaseTestCase Miscellaneous::getInvertedColor('1234567'); } + /** + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + */ public function testGetInvertedColorWithInvalidValue() { $this->setExpectedException(InvalidColorHexValueException::class); @@ -686,6 +701,10 @@ class MiscellaneousTest extends BaseTestCase Miscellaneous::getInvertedColor('00ppqq'); } + /** + * @throws IncorrectColorHexLengthException + * @throws InvalidColorHexValueException + */ public function testGetInvertedColor() { /* @@ -1174,6 +1193,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'; } /** @@ -1186,5 +1206,6 @@ class MiscellaneousTest extends BaseTestCase unset($this->stringSmall); unset($this->stringCommaSeparated); unset($this->stringDotSeparated); + unset($this->stringWithoutSpaces); } } diff --git a/tests/Utilities/QueryBuilderUtilityTest.php b/tests/Utilities/QueryBuilderUtilityTest.php new file mode 100644 index 0000000..ece2b21 --- /dev/null +++ b/tests/Utilities/QueryBuilderUtilityTest.php @@ -0,0 +1,341 @@ + + * @copyright Meritoo + */ +class QueryBuilderUtilityTest extends BaseTestCase +{ + public function testConstructor() + { + static::assertHasNoConstructor(QueryBuilderUtility::class); + } + + /** + * @param QueryBuilder $queryBuilder The query builder to retrieve root alias + * @param null|string $rootAlias Expected root alias of given query builder + * + * @dataProvider provideQueryBuilderAndRootAlias + */ + public function testGetRootAlias(QueryBuilder $queryBuilder, $rootAlias) + { + static::assertSame($rootAlias, QueryBuilderUtility::getRootAlias($queryBuilder)); + } + + /** + * @param QueryBuilder $queryBuilder The query builder to verify + * @param string $propertyName Name of property that maybe is joined + * @param null|string $propertyAlias Expected alias of given property joined in given query builder + * + * @dataProvider provideQueryBuilderAndPropertyAlias + */ + public function testGetJoinedPropertyAlias(QueryBuilder $queryBuilder, $propertyName, $propertyAlias) + { + static::assertSame($propertyAlias, QueryBuilderUtility::getJoinedPropertyAlias($queryBuilder, $propertyName)); + } + + public function testSetCriteriaWithoutCriteria() + { + $entityManager = $this->getMock(EntityManagerInterface::class); + $queryBuilder = new QueryBuilder($entityManager); + $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder); + + static::assertSame($queryBuilder, $newQueryBuilder); + static::assertCount(0, $newQueryBuilder->getParameters()); + static::assertNull($newQueryBuilder->getDQLPart('where')); + } + + public function testSetCriteriaWithoutAlias() + { + $criteria = [ + 'lorem' => 11, + 'ipsum' => 22, + ]; + + $entityManager = $this->getMock(EntityManagerInterface::class); + $queryBuilder = new QueryBuilder($entityManager); + $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder, $criteria); + + static::assertSame($queryBuilder, $newQueryBuilder); + static::assertCount(count($criteria), $newQueryBuilder->getParameters()); + static::assertNotNull($newQueryBuilder->getDQLPart('where')); + } + + /** + * @param QueryBuilder $queryBuilder The query builder + * @param array $criteria The criteria used in WHERE clause + * + * @dataProvider provideQueryBuilderAndCriteria + */ + public function testSetCriteria(QueryBuilder $queryBuilder, array $criteria) + { + $newQueryBuilder = QueryBuilderUtility::setCriteria($queryBuilder, $criteria); + $criteriaCount = count($criteria); + $nullsCount = 0; + + /* + * I have to verify count/amount of NULLs and decrease $criteriaCount, because for null parameter is not added + */ + array_walk($criteria, function ($value) use (&$nullsCount) { + if (null === $value) { + ++$nullsCount; + } + }); + + static::assertSame($queryBuilder, $newQueryBuilder); + static::assertCount($criteriaCount - $nullsCount, $newQueryBuilder->getParameters()); + static::assertNotNull($newQueryBuilder->getDQLPart('where')); + } + + public function testDeleteEntitiesWithoutFlush() + { + $methods = [ + 'remove', + 'flush', + ]; + + $entityManager = $this->getMock(EntityManager::class, $methods, [], '', false); + $entities1 = []; + + $entities2 = [ + new \stdClass(), + ]; + + static::assertFalse(QueryBuilderUtility::deleteEntities($entityManager, $entities1, false)); + static::assertTrue(QueryBuilderUtility::deleteEntities($entityManager, $entities2, false)); + } + + public function testDeleteEntities() + { + $methods = [ + 'remove', + 'flush', + ]; + + $entityManager = $this->getMock(EntityManager::class, $methods, [], '', false); + $entities1 = []; + + $entities2 = [ + new \stdClass(), + ]; + + static::assertFalse(QueryBuilderUtility::deleteEntities($entityManager, $entities1)); + static::assertTrue(QueryBuilderUtility::deleteEntities($entityManager, $entities2)); + } + + /** + * @param QueryBuilder $queryBuilder The query builder + * @param array|ArrayCollection $parameters Parameters to add. Collection of Doctrine\ORM\Query\Parameter + * instances or an array with key-value pairs. + * + * @dataProvider provideQueryBuilderAndParameters + */ + public function testAddParameters(QueryBuilder $queryBuilder, $parameters) + { + $newQueryBuilder = QueryBuilderUtility::addParameters($queryBuilder, $parameters); + + static::assertSame($queryBuilder, $newQueryBuilder); + static::assertCount(count($parameters), $newQueryBuilder->getParameters()); + } + + /** + * Provides query builder to retrieve root alias and expected root alias + * + * @return Generator + */ + public function provideQueryBuilderAndRootAlias() + { + $entityManager = $this->getMock(EntityManagerInterface::class); + + yield[ + new QueryBuilder($entityManager), + null, + ]; + + yield[ + (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), + 'lm', + ]; + + yield[ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i'), + 'l', + ]; + } + + /** + * Provides query builder, name of property and expected alias of given property + * + * @return Generator + */ + public function provideQueryBuilderAndPropertyAlias() + { + $entityManager = $this->getMock(EntityManagerInterface::class); + + yield[ + new QueryBuilder($entityManager), + '', + null, + ]; + + yield[ + new QueryBuilder($entityManager), + 'lorem', + null, + ]; + + yield[ + (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), + 'lm', + null, + ]; + + yield[ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i'), + 'ipsum', + 'i', + ]; + + yield[ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i') + ->innerJoin('i.dolor', 'd'), + 'ipsum1', + null, + ]; + + yield[ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i') + ->innerJoin('i.dolor', 'd'), + 'ipsum', + 'i', + ]; + + yield[ + (new QueryBuilder($entityManager)) + ->from('lorem', 'l') + ->leftJoin('l.ipsum', 'i') + ->innerJoin('i.dolor', 'd'), + 'dolor', + 'd', + ]; + } + + /** + * Provides query builder and criteria used in WHERE clause + * + * @return Generator + */ + public function provideQueryBuilderAndCriteria() + { + $entityManager = $this->getMock(EntityManager::class, ['getExpressionBuilder'], [], '', false); + + $entityManager + ->expects(static::any()) + ->method('getExpressionBuilder') + ->willReturn(new Expr()); + + yield[ + (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), + [ + 'lorem' => 11, + 'ipsum' => 22, + 'dolor' => null, + ], + ]; + + yield[ + (new QueryBuilder($entityManager))->from('lorem_ipsum', 'lm'), + [ + 'lorem' => [ + 11, + '>=', + ], + 'ipsum' => [ + 22, + '<', + ], + 'dolor' => null, + ], + ]; + } + + /** + * Provides query builder and parameters to add to given query builder + * + * @return Generator + */ + public function provideQueryBuilderAndParameters() + { + $entityManager = $this->getMock(EntityManagerInterface::class); + + yield[ + new QueryBuilder($entityManager), + [], + ]; + + yield[ + new QueryBuilder($entityManager), + new ArrayCollection(), + ]; + + yield[ + new QueryBuilder($entityManager), + [ + 'lorem' => 11, + 'ipsum' => 22, + ], + ]; + + yield[ + new QueryBuilder($entityManager), + new ArrayCollection([ + 'lorem' => 11, + 'ipsum' => 22, + ]), + ]; + + yield[ + new QueryBuilder($entityManager), + [ + new Parameter('lorem', 11), + new Parameter('ipsum', 22), + ], + ]; + + yield[ + new QueryBuilder($entityManager), + new ArrayCollection([ + new Parameter('lorem', 11), + new Parameter('ipsum', 22), + ]), + ]; + } +} diff --git a/tests/Utilities/Reflection/A.php b/tests/Utilities/Reflection/A.php index 81263b1..d3c5e0c 100644 --- a/tests/Utilities/Reflection/A.php +++ b/tests/Utilities/Reflection/A.php @@ -12,8 +12,8 @@ namespace Meritoo\Common\Test\Utilities\Reflection; * The A class. * Used for testing the Reflection class. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class A { diff --git a/tests/Utilities/Reflection/B.php b/tests/Utilities/Reflection/B.php index 3366835..0ada1d0 100644 --- a/tests/Utilities/Reflection/B.php +++ b/tests/Utilities/Reflection/B.php @@ -12,10 +12,10 @@ namespace Meritoo\Common\Test\Utilities\Reflection; * The B class. * Used for testing the Reflection class. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ -class B extends A +class B extends A implements I { protected $name = 'Lorem Ipsum'; diff --git a/tests/Utilities/Reflection/C.php b/tests/Utilities/Reflection/C.php index 8baa5ec..8807a35 100644 --- a/tests/Utilities/Reflection/C.php +++ b/tests/Utilities/Reflection/C.php @@ -12,8 +12,8 @@ namespace Meritoo\Common\Test\Utilities\Reflection; * The C class. * Used for testing the Reflection class. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class C extends B { diff --git a/tests/Utilities/Reflection/D.php b/tests/Utilities/Reflection/D.php index a3f8c36..d031a08 100644 --- a/tests/Utilities/Reflection/D.php +++ b/tests/Utilities/Reflection/D.php @@ -12,8 +12,8 @@ namespace Meritoo\Common\Test\Utilities\Reflection; * The D class. * Used for testing the Reflection class. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class D { diff --git a/tests/Utilities/Reflection/E.php b/tests/Utilities/Reflection/E.php index 7f767b9..177e94d 100644 --- a/tests/Utilities/Reflection/E.php +++ b/tests/Utilities/Reflection/E.php @@ -12,8 +12,8 @@ namespace Meritoo\Common\Test\Utilities\Reflection; * The E trait. * Used for testing the Reflection class. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ trait E { diff --git a/tests/Utilities/Reflection/F.php b/tests/Utilities/Reflection/F.php index 9d21d9c..f563db7 100644 --- a/tests/Utilities/Reflection/F.php +++ b/tests/Utilities/Reflection/F.php @@ -12,8 +12,8 @@ namespace Meritoo\Common\Test\Utilities\Reflection; * The F class. * Used for testing the Reflection class. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class F { diff --git a/tests/Utilities/Reflection/G.php b/tests/Utilities/Reflection/G.php index e12808c..0fb8ff6 100644 --- a/tests/Utilities/Reflection/G.php +++ b/tests/Utilities/Reflection/G.php @@ -12,8 +12,8 @@ namespace Meritoo\Common\Test\Utilities\Reflection; * The G class. * Used for testing the Reflection class. * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class G { diff --git a/tests/Utilities/Reflection/H.php b/tests/Utilities/Reflection/H.php new file mode 100644 index 0000000..68fa525 --- /dev/null +++ b/tests/Utilities/Reflection/H.php @@ -0,0 +1,27 @@ + + * @copyright Meritoo + */ +class H +{ + const DOLOR = 'sit'; + + const LOREM = 'ipsum'; + + const MAX_USERS = 5; + + const MIN_USERS = 2; +} diff --git a/tests/Utilities/Reflection/I.php b/tests/Utilities/Reflection/I.php new file mode 100644 index 0000000..d6a2063 --- /dev/null +++ b/tests/Utilities/Reflection/I.php @@ -0,0 +1,20 @@ + + * @copyright Meritoo + */ +interface I +{ +} diff --git a/tests/Utilities/ReflectionTest.php b/tests/Utilities/ReflectionTest.php index 9907779..69ce170 100644 --- a/tests/Utilities/ReflectionTest.php +++ b/tests/Utilities/ReflectionTest.php @@ -13,6 +13,7 @@ use Generator; use Meritoo\Common\Collection\Collection; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException; +use Meritoo\Common\Exception\Reflection\NotExistingPropertyException; use Meritoo\Common\Exception\Reflection\TooManyChildClassesException; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Test\Utilities\Reflection\A; @@ -22,14 +23,16 @@ use Meritoo\Common\Test\Utilities\Reflection\D; use Meritoo\Common\Test\Utilities\Reflection\E; use Meritoo\Common\Test\Utilities\Reflection\F; use Meritoo\Common\Test\Utilities\Reflection\G; +use Meritoo\Common\Test\Utilities\Reflection\H; +use Meritoo\Common\Test\Utilities\Reflection\I; use Meritoo\Common\Utilities\Reflection; use ReflectionProperty; /** * Test case of the useful reflection methods * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class ReflectionTest extends BaseTestCase { @@ -379,6 +382,130 @@ class ReflectionTest extends BaseTestCase self::assertEquals($expected, Reflection::getPropertyValues($collection, 'gInstance.firstName', true)); } + public function testGetMaxNumberConstantUsingClassWithoutConstants() + { + static::assertNull(Reflection::getMaxNumberConstant(A::class)); + } + + public function testGetMaxNumberConstant() + { + static::assertEquals(5, Reflection::getMaxNumberConstant(H::class)); + } + + public function testHasMethodUsingClassWithoutMethod() + { + static::assertFalse(Reflection::hasMethod(A::class, 'getUser')); + } + + public function testHasMethod() + { + static::assertTrue(Reflection::hasMethod(A::class, 'getCount')); + } + + public function testHasPropertyUsingClassWithoutProperty() + { + static::assertFalse(Reflection::hasProperty(A::class, 'users')); + } + + public function testHasProperty() + { + static::assertTrue(Reflection::hasProperty(A::class, 'count')); + } + + public function testHasConstantUsingClassWithoutConstant() + { + static::assertFalse(Reflection::hasConstant(H::class, 'users')); + } + + public function testHasConstant() + { + static::assertTrue(Reflection::hasConstant(H::class, 'LOREM')); + } + + public function testGetConstantValueUsingClassWithoutConstant() + { + static::assertNull(Reflection::getConstantValue(H::class, 'users')); + } + + public function testGetConstantValue() + { + static::assertEquals(H::LOREM, Reflection::getConstantValue(H::class, 'LOREM')); + } + + public function testIsInterfaceImplementedUsingClassWithoutInterface() + { + static::assertFalse(Reflection::isInterfaceImplemented(A::class, I::class)); + } + + public function testIsInterfaceImplemented() + { + static::assertTrue(Reflection::isInterfaceImplemented(B::class, I::class)); + } + + public function testIsChildOfClassUsingClassWithoutChildClass() + { + static::assertFalse(Reflection::isChildOfClass(A::class, B::class)); + } + + public function testIsChildOfClass() + { + static::assertTrue(Reflection::isChildOfClass(B::class, A::class)); + } + + public function testGetPropertyUsingClassWithoutProperty() + { + static::assertNull(Reflection::getProperty(A::class, 'lorem')); + } + + public function testGetPropertyUsingClassWithPrivateProperty() + { + $property = Reflection::getProperty(A::class, 'count', ReflectionProperty::IS_PRIVATE); + + static::assertInstanceOf(ReflectionProperty::class, $property); + static::assertTrue($property->isPrivate()); + static::assertEquals('count', $property->getName()); + } + + public function testGetPropertyUsingClassWithProtectedProperty() + { + $property = Reflection::getProperty(B::class, 'name', ReflectionProperty::IS_PROTECTED); + + static::assertInstanceOf(ReflectionProperty::class, $property); + static::assertTrue($property->isProtected()); + static::assertEquals('name', $property->getName()); + } + + /** + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * + * @dataProvider provideObjectAndNotExistingProperty + */ + public function testSetPropertyValueUsingNotExistingProperty($object, $property) + { + $this->setExpectedException(NotExistingPropertyException::class); + + $object = new \stdClass(); + Reflection::setPropertyValue($object, 'test', 'test test test'); + } + + /** + * @param mixed $object Object that should contains given property + * @param string $property Name of the property + * @param mixed $value Value of the property + * + * @dataProvider provideObjectPropertyAndValue + */ + public function testSetPropertyValue($object, $property, $value) + { + $oldValue = Reflection::getPropertyValue($object, $property); + Reflection::setPropertyValue($object, $property, $value); + $newValue = Reflection::getPropertyValue($object, $property); + + static::assertNotSame($oldValue, $value); + static::assertSame($newValue, $value); + } + /** * Provides invalid class and trait * @@ -406,4 +533,59 @@ class ReflectionTest extends BaseTestCase [], ]; } + + /** + * Provides object and name of not existing property + * + * @return Generator + */ + public function provideObjectAndNotExistingProperty() + { + yield[ + new \stdClass(), + 'test', + ]; + + yield[ + new A(), + 'test', + ]; + + yield[ + new B(), + 'firstName', + ]; + } + + /** + * Provides object, name of property and value of the property + * + * @return Generator + */ + public function provideObjectPropertyAndValue() + { + yield[ + new A(), + 'count', + 123, + ]; + + yield[ + new B(), + 'name', + 'test test', + ]; + + yield[ + new G(), + 'firstName', + 'Jane', + ]; + + yield[ + new G(), + 'lastName', + 'Smith', + ]; + } } diff --git a/tests/Utilities/RegexTest.php b/tests/Utilities/RegexTest.php index fe89710..8ecea57 100644 --- a/tests/Utilities/RegexTest.php +++ b/tests/Utilities/RegexTest.php @@ -8,19 +8,26 @@ namespace Meritoo\Common\Utilities; +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 * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class RegexTest extends BaseTestCase { private $simpleText; private $camelCaseText; + /** + * @throws ReflectionException + */ public function testConstructor() { static::assertHasNoConstructor(Regex::class); @@ -145,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)); @@ -164,6 +175,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 */ @@ -183,6 +200,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 */ @@ -228,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() @@ -273,6 +299,1436 @@ 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)); + } + + public function testGetBundleNamePattern() + { + 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)); + } + + /** + * @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)); + } + + /** + * @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)); + } + + /** + * @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)); + } + + 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 + * @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 + * + * @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, + ]; + } + + /** + * 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, + ]; + } + + /** + * 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, + ]; + } + + /** + * 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, + ]; + } + + /** + * 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} */ diff --git a/tests/Utilities/Repository/Sortable.php b/tests/Utilities/Repository/Sortable.php new file mode 100644 index 0000000..c4b0413 --- /dev/null +++ b/tests/Utilities/Repository/Sortable.php @@ -0,0 +1,66 @@ + + * @copyright Meritoo + */ +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..aafeadb --- /dev/null +++ b/tests/Utilities/RepositoryTest.php @@ -0,0 +1,602 @@ + + * @copyright Meritoo + */ +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, + ]; + } +} diff --git a/tests/Utilities/UriTest.php b/tests/Utilities/UriTest.php index 6c195d9..e341d65 100644 --- a/tests/Utilities/UriTest.php +++ b/tests/Utilities/UriTest.php @@ -8,14 +8,15 @@ namespace Meritoo\Common\Test\Utilities; +use Generator; use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Utilities\Uri; /** * Test case of the useful uri methods (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class UriTest extends BaseTestCase { @@ -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', + ]; + } } diff --git a/tests/Utilities/XmlTest.php b/tests/Utilities/XmlTest.php index 779c6e8..804d77a 100644 --- a/tests/Utilities/XmlTest.php +++ b/tests/Utilities/XmlTest.php @@ -15,8 +15,8 @@ use SimpleXMLElement; /** * Test case of the useful XML-related methods (only static functions) * - * @author Krzysztof Niziol - * @copyright Meritoo.pl + * @author Meritoo + * @copyright Meritoo */ class XmlTest extends BaseTestCase { diff --git a/tests/ValueObject/VersionTest.php b/tests/ValueObject/VersionTest.php new file mode 100644 index 0000000..fb0e783 --- /dev/null +++ b/tests/ValueObject/VersionTest.php @@ -0,0 +1,188 @@ + + * @copyright Meritoo + */ +class VersionTest extends BaseTestCase +{ + public function testConstructor() + { + static::assertConstructorVisibilityAndArguments(Version::class, OopVisibilityType::IS_PUBLIC, 3, 3); + } + + public function testNewInstance() + { + $version = new Version(1, 0, 2); + + static::assertInstanceOf(Version::class, $version); + static::assertSame(1, Reflection::getPropertyValue($version, 'majorPart')); + static::assertSame(0, Reflection::getPropertyValue($version, 'minorPart')); + static::assertSame(2, Reflection::getPropertyValue($version, 'patchPart')); + } + + /** + * @param Version $version The version + * @param string $expected Expected string + * + * @dataProvider provideConvertedToString + */ + public function testToString(Version $version, $expected) + { + static::assertSame($expected, (string)$version); + } + + /** + * @param string $version The version + * @param Version $expected (optional) Expected version + * + * @dataProvider provideAsString + */ + public function testFromString($version, Version $expected = null) + { + static::assertEquals($expected, Version::fromString($version)); + } + + /** + * @param array $version The version + * @param Version $expected (optional) Expected version + * + * @dataProvider provideAsArray + */ + public function testFromArray(array $version, Version $expected = null) + { + static::assertEquals($expected, Version::fromArray($version)); + } + + /** + * Provide instance of version and expected version converted to string + * + * @return Generator + */ + public function provideConvertedToString() + { + yield[ + new Version(0, 0, 0), + '0.0.0', + ]; + + yield[ + new Version(1, 0, 2), + '1.0.2', + ]; + + yield[ + new Version(10, 5, 41), + '10.5.41', + ]; + } + + /** + * Provide version as string and expected instance of version + * + * @return Generator + */ + public function provideAsString() + { + yield[ + '', + null, + ]; + + yield[ + '1.0', + null, + ]; + + yield[ + '10', + null, + ]; + + yield[ + '0.0.0', + new Version(0, 0, 0), + ]; + + yield[ + '1.0.2', + new Version(1, 0, 2), + ]; + + yield[ + '10.5.41', + new Version(10, 5, 41), + ]; + } + + /** + * Provide version as array and expected instance of version + * + * @return Generator + */ + public function provideAsArray() + { + yield[ + [], + null, + ]; + + yield[ + [ + 1, + 0, + ], + null, + ]; + + yield[ + [ + 10, + ], + null, + ]; + + yield[ + [ + 0, + 0, + 0, + ], + new Version(0, 0, 0), + ]; + + yield[ + [ + 1, + 0, + 2, + ], + new Version(1, 0, 2), + ]; + + yield[ + [ + 10, + 5, + 41, + ], + new Version(10, 5, 41), + ]; + } +}