169 Commits

Author SHA1 Message Date
Meritoo
39ede292d6 Merge branch 'develop' 2018-11-03 09:09:09 +01:00
Meritoo
8e9dcb3206 Reflection > setPropertiesValues() method > sets values of properties in given object 2018-11-03 08:53:01 +01:00
Meritoo
06fbf63e09 Tests > refactoring 2018-11-03 08:50:12 +01:00
Meritoo
4e600ec599 Utilities > Reflection > setPropertyValue() method > fix description and test 2018-11-03 08:16:49 +01:00
Meritoo
b4ccbbac11 Utilities > Date > update descriptions of methods 2018-11-03 08:10:03 +01:00
Meritoo
c82f53219e Phing > PHPUnit > run with code coverage (to get all reports) 2018-10-29 08:31:38 +01:00
Meritoo
c8fc0b14ff Exceptions > UnknownTypeException > remove duplicated and unnecessary sprintf() call > sprintf(sprintf()) 2018-10-28 00:12:18 +02:00
Meritoo
3c3d1b997e Docker > docker-compose.yml > add "phpunit" service > used to run PHPUnit's tests 2018-10-28 00:10:42 +02:00
Meritoo
61209e3f67 Documentation > Development > add commands based on Phing & update whole document 2018-10-28 00:09:29 +02:00
Meritoo
822dbf6830 Phing > tests > remove mutation tests (because Infection requires PHP 7.1+) 2018-10-28 00:06:52 +02:00
Meritoo
870bfe48a2 Docker > Dockerfile > fix installation of Composer 2018-10-28 00:03:35 +02:00
Meritoo
ff416fda69 Phing > update configuration 2018-10-25 11:05:32 +02:00
Meritoo
61676a445e Docker > update docker-compose.yml > composer > fix "allowed memory size of 1610612736 bytes exhausted" bug 2018-10-25 10:31:44 +02:00
Meritoo
1f5106bcf0 Docker > improve performance > fix indentations 2018-10-25 10:31:21 +02:00
Meritoo
971224b2e6 PHPUnit > update configuration 2018-10-25 10:28:00 +02:00
Meritoo
7e4b14a92f Phing > update configuration 2018-10-25 10:27:48 +02:00
Meritoo
38c68b0952 Readme > add badge with required PHP version 2018-10-19 22:54:26 +02:00
Meritoo
ca9c3bd8f1 Utilities > Date > update descriptions of methods 2018-10-19 22:54:11 +02:00
Meritoo
97c6112919 TravisCI > fix indentation 2018-09-20 20:41:48 +02:00
Meritoo
26b136d676 Tests > increase code coverage 2018-09-20 17:30:07 +02:00
Meritoo
4db631223f Phing > tests > PHPUnit > do not use dox format (for output results) 2018-09-08 08:21:50 +02:00
Meritoo
5d6b559108 Phing > tests > missing path of directory with code coverage report 2018-09-07 13:48:44 +02:00
Meritoo
575bb344cd BaseTestCaseTrait > minor refactoring 2018-08-27 22:04:35 +02:00
Meritoo
35b70f53e7 BaseType > minor refactoring 2018-08-26 16:39:45 +02:00
Meritoo
51ff110101 Phing > update configuration 2018-08-26 15:43:34 +02:00
Meritoo
2f9138d093 Merge branch 'develop' 2018-08-08 18:37:09 +02:00
Meritoo
75707a3f76 Utilities > Bootstrap4CssSelector > useful methods related to CSS selectors and the Bootstrap4 (front-end component library) 2018-08-07 23:31:50 +02:00
Meritoo
8ecbefbba6 Utilities > CssSelector > useful methods related to CSS selectors 2018-08-07 23:31:30 +02:00
Meritoo
e850375c19 Tests > refactoring & minor improvements 2018-08-06 21:43:57 +02:00
Meritoo
0bd1e1e158 Merge branch 'develop' 2018-07-29 16:01:31 +02:00
Meritoo
535ae65e5e Utilities > Reflection > setPropertyValue() method > sets value of given property 2018-07-29 16:00:13 +02:00
Meritoo
60d7b03cd7 Utilities > Reflection > refactoring 2018-07-29 15:34:33 +02:00
Meritoo
c20fa5941f Docker > improve performance 2018-07-28 21:01:07 +02:00
Meritoo
a448d592d2 Documentation > Value Objects 2018-07-02 21:24:20 +02:00
Meritoo
e53273fb32 Merge branch 'develop' 2018-07-02 20:20:52 +02:00
Meritoo
cc30ad8d9e Move version of this package to "VERSION" file (from "composer.json" file) 2018-07-02 20:19:29 +02:00
Meritoo
9f08a2aaaf ValueObject > class Version > represents version of software 2018-07-02 20:07:33 +02:00
Meritoo
b49605a26c TravisCI - fix "No output has been received in the last 10m0s" bug (build times out because no output was received) 2018-07-02 10:40:33 +02:00
Meritoo
8441c82356 TravisCI > run using PHP 7.2 too 2018-07-02 09:53:16 +02:00
Meritoo
55dde2e898 Merge branch 'develop' 2018-07-02 09:34:53 +02:00
Meritoo
a32e0c4cca Documentation > Exceptions 2018-07-02 09:31:07 +02:00
Meritoo
834b24f348 Exceptions > create instance of exception using static "create()" method (instead of constructor) 2018-07-02 08:54:24 +02:00
Meritoo
9342f0e87e Docker > rename "php-cli" service to "php" 2018-07-02 08:47:56 +02:00
Meritoo
72fd87e165 Composer > support/require PHP 5.6+ (instead of 5.5.9+) 2018-07-02 08:12:26 +02:00
Meritoo
64499b49d3 Update @author and @copyright in classes' descriptions 2018-07-01 21:07:47 +02:00
Meritoo
848adef015 Arrays > minor refactoring 2018-07-01 17:45:03 +02:00
Meritoo
1431fd9935 Composer > require ext-pcre 2018-07-01 17:37:51 +02:00
Meritoo
3bb7a182c2 Merge branch 'develop' 2018-06-22 08:26:10 +02:00
Meritoo
5c9436e4e2 Collection > add() method > treat empty string as not provided index (same as null) 2018-06-22 08:10:06 +02:00
Meritoo
1a649d35e1 Merge branch 'develop' 2018-06-18 09:37:27 +02:00
Meritoo
107480d01b StyleCI > disable & remove 2018-06-16 14:43:16 +02:00
Meritoo
f4c12661b4 StyleCI configuration > fix bug "The provided fixer 'concat_with_spaces' cannot be enabled at the same time as 'concat_without_spaces'" 2018-06-16 14:36:33 +02:00
Meritoo
fc7df571e2 StyleCI configuration > fix bug "The provided fixer 'binary_operator_spaces' cannot be enabled again because it was already enabled" 2018-06-16 14:34:00 +02:00
Meritoo
0f37edfc9b Coding standard > fix automatically 2018-06-16 14:31:04 +02:00
Meritoo
ae3e82e233 Documentation > Docker > add paragraph for PHP Coding Standards Fixer 2018-06-16 14:21:01 +02:00
Meritoo
c99a099c31 StyleCI & PHP Coding Standards Fixer > update configuration 2018-06-16 14:15:35 +02:00
Meritoo
c443ef22d7 .gitignore > PHP Coding Standards Fixer > ignore custom settings 2018-06-16 14:12:07 +02:00
Meritoo
be8b4a3498 Arrays > remove unnecessary code 2018-06-16 14:10:57 +02:00
Meritoo
b1ddc6d561 .env.dist > enter default values (for easier .env creation) 2018-06-16 10:04:14 +02:00
Meritoo
ffe34eb9cf StyleCI > update configuration 2018-06-15 23:06:47 +02:00
Meritoo
155c091a3e StyleCI > update configuration 2018-06-15 23:04:06 +02:00
Meritoo
0a3955026b Revert "StyleCI > update configuration"
This reverts commit f9fa5f5
2018-06-15 23:00:53 +02:00
Meritoo
f9fa5f5915 StyleCI > update configuration 2018-06-15 23:00:29 +02:00
Meritoo
43945a8721 Composer > do not require symfony/http-foundation package
Miscellaneous > remove getCurlResponseWithHeaders() method
2018-06-15 22:54:00 +02:00
Meritoo
e9da0cf351 Reorganize documentation & update Readme 2018-06-14 22:28:53 +02:00
Meritoo
4c534394d9 Docker > Dockerfile > add "WORKDIR" (instead of "working_dir" in docker-compose.yml) 2018-06-14 21:35:50 +02:00
Meritoo
3726a26e47 Reorganize documentation & update Readme 2018-06-14 21:35:14 +02:00
Meritoo
fb24bc2ff1 Docker > use project-related binaries globally 2018-06-14 11:50:45 +02:00
Meritoo
57a78d1299 Reorganize documentation & update Readme 2018-06-14 11:32:54 +02:00
Meritoo
696cff023c Add changelog 2018-06-14 11:32:25 +02:00
Meritoo
9197682cd2 Readme > update paragraphs with Composer, Docker & use 1st level headers 2018-06-14 09:55:44 +02:00
Meritoo
49638ff1c3 .gitignore > update sections' separators 2018-06-13 22:21:28 +02:00
Meritoo
abf0ebf7ec Tests > increase code coverage 2018-06-09 14:25:20 +02:00
Meritoo
2e60176d95 Docker > Dockerfile > make bash terminal wider (increase columns count) 2018-06-07 20:56:48 +02:00
Meritoo
c351ce887a Tests > implement PHPUnit (instead of Codeception) 2018-06-07 20:51:55 +02:00
Meritoo
8a6262a8c3 Phing > tests > update name of property with path (tests_framework.path > tests.framework.path) & ignore /build directory 2018-05-28 21:22:00 +02:00
Meritoo
3c83a8800e Start names of special directories without dot 2018-05-28 21:10:20 +02:00
Meritoo
233473d915 Tests > implement Codeception (instead of PHPUnit) 2018-05-28 17:53:25 +02:00
Meritoo
7382bce842 Phing > tests > do not verify if the "tests" directory exists 2018-05-28 17:05:12 +02:00
Meritoo
c5b42017d2 Phing > tests > do not create database (for code coverage) 2018-05-28 17:03:19 +02:00
Meritoo
bc54f734e2 Phing > update properties.dist > remove unnecessary properties and disabled code 2018-05-28 16:56:59 +02:00
Meritoo
0eb5343df0 Docker > name of containers > use custom suffix
Docker > the "composer" service
2018-05-28 15:03:52 +02:00
Meritoo
52e74c8b48 Tests > increase code coverage 2018-05-28 15:03:11 +02:00
Meritoo
96bdb6eb60 Improve coding standard 2018-05-06 17:21:55 +02:00
Meritoo
5be449a83d Docker > Dockerfile > fix bug when error messages are displayed in french instead of english language (example: "chmod(): Aucun fichier ou dossier de ce type") 2018-05-06 14:40:17 +02:00
Meritoo
132a0a00e7 Docker > Dockerfile > fix bug "pecl/xdebug requires PHP (version >= 7.0.0), installed version is 5.5.38" 2018-05-04 12:53:45 +02:00
Meritoo
6fd18111b4 TravisCI - fix "No output has been received in the last 10m0s" bug (build times out because no output was received) 2018-04-04 21:54:45 +02:00
Meritoo
26c63ecb5c TravisCI > composer > install hirak/prestissimo package globally 2018-04-04 21:40:44 +02:00
Meritoo
bedb6333b9 TravisCI > "composer install" command > increase verbosity to maximum 2018-04-04 21:21:51 +02:00
Meritoo
ec2b5742ec Revert "TravisCI - fix "No output has been received in the last 10m0s" bug (build times out because no output was received)"
This reverts commit ec2f3c6
2018-04-04 21:16:36 +02:00
Meritoo
ec2f3c6ead TravisCI - fix "No output has been received in the last 10m0s" bug (build times out because no output was received) 2018-04-04 08:57:08 +02:00
Meritoo
834c12f280 TravisCI - install locales before running tests - remove unnecessary command 2018-04-03 22:57:41 +02:00
Meritoo
122ff41dad TravisCI - install locales before running tests 2018-04-03 19:13:38 +02:00
Meritoo
180a8b8b5d TravisCI - install locales before running tests 2018-04-03 17:10:40 +02:00
Meritoo
499c603d54 TravisCI - install locales before running tests 2018-04-03 17:04:43 +02:00
Meritoo
1cbc87222f TravisCI - install locales before running tests 2018-04-03 16:58:54 +02:00
Meritoo
129b75ea93 Revert "TravisCI - install locales before running tests"
This reverts commit aae7609
2018-04-03 16:58:32 +02:00
Meritoo
aae7609c8c TravisCI - install locales before running tests 2018-04-03 16:55:12 +02:00
Meritoo
5578b051a7 Update PHPDoc and comments 2018-04-03 08:26:51 +02:00
Meritoo
f111174ed2 Tests - increase code coverage 2018-04-03 08:22:10 +02:00
Meritoo
ddbff1b557 Update PHPDoc and comments 2018-04-02 22:46:52 +02:00
Meritoo
8d1df9ced8 Tests - increase code coverage 2018-04-02 22:44:30 +02:00
Meritoo
b7d0b61094 tests > PHPUnit configuration > update 2018-03-30 21:15:42 +02:00
Meritoo
ad64d2e02a Docker - Dockerfile - minor update 2018-01-27 13:10:14 +01:00
Meritoo
470b8244ec Utilities - Locale - getLocale() method - returns locale for given category 2018-01-27 13:05:20 +01:00
Meritoo
af38c35a1b Utilities - Locale - setLocale() method - return result of setting new locale (instead of "true")
Tests - Locale - fix incorrectly prepared tests
2018-01-27 13:04:04 +01:00
Meritoo
1e3e1d454e Docker - Dockerfile - install "locales" package & generate popular locales
Required to run tests related to setlocale() function (and Meritoo\Common\Utilities\Locale class) properly
2018-01-27 12:59:55 +01:00
Meritoo
57b411b59f Tests - increase code coverage 2018-01-17 21:37:07 +01:00
Meritoo
8a4860088f Phing - Composer-related task - validate Composer 2018-01-14 21:19:06 +01:00
Meritoo
e9b8fb8852 Regex - isBinaryValue() method - returns information if given value is a binary value 2018-01-10 17:35:42 +01:00
Meritoo
780d4df17e Tests - increase code coverage 2017-12-26 14:37:17 +01:00
Meritoo
d801e675fc Exception - InvalidHtmlAttributesException - an exception used while html attributes are invalid 2017-12-24 00:03:23 +01:00
Meritoo
6753076937 Regex - isValidHtmlAttribute() & areValidHtmlAttributes() methods - returns information if given html attribute is valid & if given html attributes are valid 2017-12-23 23:08:49 +01:00
Meritoo
7f713e0c6e Docker - name of containers - use custom prefix 2017-12-22 10:44:07 +01:00
Meritoo
ebbed4825c Bundle - getBundleViewPath() method - return path using namespaced syntax 2017-12-21 23:45:01 +01:00
Meritoo
7d23ff59d1 Bundle - getBundleViewPath() method - verify name of bundle 2017-12-21 22:45:23 +01:00
Meritoo
0e4c33241e Tests - BundleTest - minor refactoring 2017-12-21 22:05:07 +01:00
Meritoo
66aefa2446 Regex - isValidBundleName() method - returns information if given name of bundle is valid 2017-12-21 21:47:45 +01:00
Meritoo
5aaf7cde72 Minor refactoring 2017-12-21 20:41:12 +01:00
Meritoo
8bb529b88d Docker - Dockerfile - minor refactoring 2017-12-02 13:23:26 +01:00
Meritoo
3588c00009 Docker - do not install "zip" package 2017-12-02 13:12:34 +01:00
Meritoo
78480ac853 .gitignore - ignore .env 2017-12-02 12:53:32 +01:00
Meritoo
8bcf006e02 Tests - increase code coverage 2017-11-05 19:35:13 +01:00
Meritoo
edc51aeee1 DatePeriod - change namespace (Meritoo\Common\Utilities -> Meritoo\Common\Type) & extend BaseType 2017-11-03 20:21:08 +01:00
Meritoo
6d4e422165 BaseTestCase & BaseTypeTestCase - add traits to use in other test cases (e.g. in Symfony's kernel-related test case) 2017-11-02 22:00:38 +01:00
Meritoo
6f441bb9ea Tests - BaseTestCaseTest - fix bug while there is a difference (split second) 2017-11-02 13:58:24 +01:00
Meritoo
73030d703b composer.json - bump version 2017-11-02 12:25:39 +01:00
Meritoo
36ddb326b9 Tests - increase code coverage 2017-10-31 21:27:42 +01:00
Meritoo
452a4ec458 Tests - BaseTestCase - rename method getFilePathToTests() -> getFilePathForTesting() 2017-10-31 21:26:39 +01:00
Meritoo
325fe6b141 Support PHP 5.5.9+ 2017-10-31 20:28:55 +01:00
Meritoo
a1c26b3812 Phing - tests - phpcodesniffer task - fix "This task requires the PHP_CodeSniffer package installed and available on the include path" bug
Details: https://github.com/phingofficial/phing/issues/716
2017-10-26 20:04:05 +02:00
Meritoo
67d93036cf Phing - update properties.dist file 2017-10-22 21:40:23 +02:00
Meritoo
9368616dfe composer.json - update versions of the "dev" packages 2017-10-22 20:09:02 +02:00
Meritoo
5ab68d3667 Tests - Docker - update Xdebug configuration
Required to fix problem "Connection with XDebug 2.5.1 was not established. Validate installation."
2017-10-22 17:55:49 +02:00
Meritoo
4613a63f02 Tests - Docker - install vim, add custom php.ini, add "vendor/bin" to the $PATH global variable 2017-10-20 00:03:38 +02:00
Meritoo
9dac5bd11c Tests - Docker - update name of image and container 2017-10-18 21:50:02 +02:00
Meritoo
12100db058 Tests - Docker - update port 2017-10-18 20:02:09 +02:00
Meritoo
f9ab0a6194 Tests - Docker - add required libraries, PHP extensions & optimize size of Docker's image 2017-10-18 17:01:13 +02:00
Meritoo
b824808cd4 Tests - use Docker (as environment guard) 2017-10-18 00:31:18 +02:00
Meritoo
71e1eeb81b Start names of special directories with dot
BaseTestCase - add setter for path of directory with data used by test cases
2017-10-17 20:49:13 +02:00
Meritoo
70c273750d .gitignore update 2017-10-10 20:09:40 +02:00
Meritoo
e5e39651f3 Tests - fix names of constructors' tests 2017-10-02 15:56:53 +02:00
Meritoo
4683970c87 composer.json - update versions of the "dev" packages & sort them 2017-10-02 14:06:57 +02:00
Meritoo
559466c0ce composer.json - move tests-related classes to "autoload-dev" section (used for development purposes only and avoid polluting the autoloader in production) 2017-09-29 09:19:03 +02:00
Meritoo
bfd69c1098 Minor fix of coding standard 2017-09-27 21:52:10 +02:00
Meritoo
45493b37b0 Remove composer.lock 2017-09-27 21:51:48 +02:00
Meritoo
37e7b14ae2 Minor fix of coding standard 2017-09-27 20:09:51 +02:00
Meritoo
a12aaf4bc0 Tests - increase code coverage 2017-09-27 17:08:39 +02:00
Meritoo
f9c480aa19 Reflection - getPropertyValue() method - verify if getter is accessible publicly 2017-09-27 17:00:25 +02:00
Meritoo
ffa3fbffe7 Exception - DisabledMethodException - an exception used while method cannot be called, because is disabled 2017-09-22 23:27:21 +02:00
Meritoo
48aa27fb86 Tests - test cases of exceptions 2017-09-22 23:26:30 +02:00
Meritoo
86cc5ff79b Refactor & fix coding standard 2017-09-22 23:25:16 +02:00
Meritoo
633696ebc0 Reflection - getProperties() method - allow to include properties of parent classes 2017-09-21 22:38:50 +02:00
Meritoo
a0d28b326e BaseTestCase - make static and rename methods (start names of methods with "assert" instead of "verify") 2017-09-21 16:52:15 +02:00
Meritoo
318a635ffd BaseTestCase - assertHasNoConstructor() method - asserts that class with given namespace has no constructor 2017-09-21 16:47:41 +02:00
Meritoo
6c70fdd673 Revert "Composer - update packages"
This reverts commit 204e879
2017-09-20 22:00:09 +02:00
Meritoo
204e8793ac Composer - update packages 2017-09-20 21:55:05 +02:00
Meritoo
3dd37ae202 BaseTestCase - fix getting path of file used by tests (by implementing the Miscellaneous::getProjectRootPath() method) 2017-09-20 21:54:07 +02:00
Meritoo
ef017c9d6a Miscellaneous - getProjectRootPath() method - returns project's root path 2017-09-20 21:52:34 +02:00
Meritoo
5030dc2062 Refactor & fix coding standard 2017-09-20 21:47:39 +02:00
Meritoo
2c76158093 Readme - fix displaying 1st block of code 2017-09-20 16:19:36 +02:00
Meritoo
0b560fdf18 Exception - 3 exceptions related to file path & content 2017-09-20 13:50:18 +02:00
Meritoo
284d403061 Fix coding standard (minor fix) 2017-09-20 12:55:25 +02:00
Meritoo
7dbb3f9b2e Tests - update namespace of PHPUnit's TestCase
Related to update versions of the "dev" packages
2017-09-20 11:58:21 +02:00
Meritoo
fba821b798 Readme - StyleCI badge - update configuration file (required to fix failed StyleCI analysis) 2017-09-20 10:56:49 +02:00
Meritoo
3985c70076 Readme - minor update 2017-09-20 09:30:06 +02:00
Meritoo
921d4e6106 composer.json - update versions of the "dev" packages 2017-09-20 09:29:19 +02:00
Meritoo
7aa2239dbd Fix coding standard (no_blank_lines_after_phpdoc, single_blank_line_before_namespace, yoda_style) 2017-09-20 09:27:56 +02:00
Meritoo
e1fefcdeae Readme - move badges below description & update description 2017-09-19 20:10:27 +02:00
129 changed files with 10436 additions and 6247 deletions

15
.env.dist Normal file
View File

@@ -0,0 +1,15 @@
# -----------------------------------------------------------------------------
### Docker
# -----------------------------------------------------------------------------
#
# All containers
#
DOCKER_CONTAINER_OWNER=meritoo
DOCKER_CONTAINER_PROJECT=common-library
#
# PHP configuration:
# - timezone
#
TIMEZONE=Europe/Warsaw

69
.gitignore vendored
View File

@@ -1,44 +1,58 @@
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
# Environment-related parameters
# ------------------------------------------------------------------------------
.env
# ------------------------------------------------------------------------------
### Vendors ### Vendors
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
/vendor/ /vendor/
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### Composer ### Composer
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
/composer.lock
/composer.phar /composer.phar
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### Phing ### Phing
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
/phing/properties /phing/properties
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### PHPUnit ### PHPUnit
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
/phpunit.xml /phpunit.xml
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### PHP Coding Standards Fixer generated files ### PHP Coding Standards Fixer
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
/.php_cs
/.php_cs.cache /.php_cs.cache
# ---------------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------
### Build files
# -----------------------------------------------------------------------------
/build/
# ------------------------------------------------------------------------------
### Generated databases ### Generated databases
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
/data/tmp /data/tmp
*.sql *.sql
*.sqlite *.sqlite
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### Compiled source ### Compiled source
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
*.com *.com
*.class *.class
*.dll *.dll
@@ -47,23 +61,22 @@
*.so *.so
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### Shell scripts ### Shell scripts
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
/*.sh /*.sh
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### JetBrains ### JetBrains
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
/.idea /.idea
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### NetBeans template ### NetBeans template
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
nbproject/private/ nbproject/private/
build/
nbbuild/ nbbuild/
dist/ dist/
nbdist/ nbdist/
@@ -71,9 +84,9 @@ nbactions.xml
.nb-gradle/ .nb-gradle/
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### OSX template ### OSX template
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
.DS_Store .DS_Store
.AppleDouble .AppleDouble
.LSOverride .LSOverride
@@ -100,9 +113,9 @@ Temporary Items
.apdisk .apdisk
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### Linux template ### Linux template
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
*~ *~
# temporary files which can be created if a process still has a handle open of a deleted file # temporary files which can be created if a process still has a handle open of a deleted file
@@ -115,9 +128,9 @@ Temporary Items
.Trash-* .Trash-*
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
### Windows template ### Windows template
# ---------------------------------------------------------------------------------------------------------------------- # ------------------------------------------------------------------------------
# Windows image file caches # Windows image file caches
Thumbs.db Thumbs.db
ehthumbs.db ehthumbs.db

View File

@@ -1,13 +1,6 @@
<?php <?php
$finder = PhpCsFixer\Finder::create() $finder = PhpCsFixer\Finder::create()
/*
* Do not verify:
* - all DependencyInjection/Configuration classes: the Configuration.php files
* - autoloader from /app directory: autoload.php
*/
->notPath('/DependencyInjection\/Configuration\.php/')
->notPath('/autoload\.php/')
->in([ ->in([
__DIR__ . '/src', __DIR__ . '/src',
__DIR__ . '/tests', __DIR__ . '/tests',
@@ -15,16 +8,20 @@ $finder = PhpCsFixer\Finder::create()
return PhpCsFixer\Config::create() return PhpCsFixer\Config::create()
->setRules([ ->setRules([
'@Symfony' => true, '@Symfony' => true,
'phpdoc_summary' => false, 'binary_operator_spaces' => [
'phpdoc_separation' => false,
'phpdoc_align' => false,
'cast_spaces' => false,
'binary_operator_spaces' => [
'align_double_arrow' => true, 'align_double_arrow' => true,
], ],
'concat_space' => [ 'blank_line_before_return' => false,
'cast_spaces' => false,
'concat_space' => [
'spacing' => 'one', '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); ->setFinder($finder);

View File

@@ -1 +0,0 @@
preset: symfony

View File

@@ -4,9 +4,14 @@ php:
- 5.6 - 5.6
- 7.0 - 7.0
- 7.1 - 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: install:
- composer install - travis_wait 30 composer install -v
script: script:
- php ./vendor/bin/phpunit - php ./vendor/bin/phpunit

56
CHANGELOG.md Normal file
View File

@@ -0,0 +1,56 @@
# Meritoo Common Library
Common and useful classes, methods, exceptions etc.
# 0.1.4
1. Phing > update configuration
2. Utilities > Date > update descriptions of methods
3. Docker > docker-compose.yml > add "phpunit" service > used to run PHPUnit's tests
4. Reflection > setPropertiesValues() method > sets values of properties in given object
# 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

106
README.md
View File

@@ -1,103 +1,29 @@
# Meritoo Common Library [![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) # Meritoo Common Library
Useful classes, methods, extensions etc.
## Installation Common and useful classes, methods, exceptions etc.
Run [Composer](https://getcomposer.org) to install new package: [![PHP Version](https://img.shields.io/badge/php-%3E%3D5.6-blue.svg)](https://img.shields.io/badge/php-%3E%3D5.6-blue.svg) [![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)
```bash # Installation
$ composer require meritoo/common-library
```
> How to install Composer: https://getcomposer.org/download Run [Composer](https://getcomposer.org) to install this package in your project:
## Static methods ```bash
composer require meritoo/common-library
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 > [How to install Composer?](https://getcomposer.org/download)
Located here: `Meritoo\Common\Test\Base\BaseTestCase`. Just extend the `BaseTestCase` class and use it like in `Meritoo\Common\Test\Utilities\DateTest` class: # Usage
```php 1. [Base test case (with common methods and data providers)](docs/Base-test-case.md)
class DateTest extends BaseTestCase 2. [Collection of elements](docs/Collection-of-elements.md)
{ 3. [Exceptions](docs/Static-methods.md)
/** 4. [Static methods](docs/Static-methods.md)
* @param mixed $value Empty value, e.g. "" 5. [Value Objects](docs/Value-Objects.md)
* @dataProvider provideEmptyValue
*/
public function testGetDateTimeEmptyValue($value)
{
self::assertFalse(Date::getDateTime($value));
}
(...) # Development
}
```
or in `Meritoo\Common\Test\Utilities\MimeTypesTest` class: More information [you can find here](docs/Development.md)
```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)
```
Enjoy! Enjoy!

1
VERSION Normal file
View File

@@ -0,0 +1 @@
0.1.4

View File

@@ -1,46 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project name="Meritoo Package" basedir="." default="build:main" phingVersion="2.14.0"> <project name="Meritoo Package" basedir="." default="build:main" phingVersion="2.14.0">
<!-- Properties --> <!-- Properties -->
<if> <if>
<available file="phing/properties" property="custom.properties.available"/> <available file="${project.basedir}/phing/properties" property="custom.properties.available"/>
<then> <then>
<property file="phing/properties" /> <property file="${project.basedir}/phing/properties"/>
</then> </then>
<else> <else>
<property file="phing/properties.dist" /> <property file="${project.basedir}/phing/properties.dist"/>
</else> </else>
</if> </if>
<!-- Default / main target --> <!-- Default / main target -->
<target name="build:main" <target name="build:main"
depends="build:app, build:tests" depends="build:app,
description="Builds everything and runs all tests" /> build:tests"
/>
<!-- Build app --> <!-- Build app -->
<target name="build:app" description="Prepares app to build and tests"> <target name="build:app">
<phing phingfile="phing/app.xml" haltonfailure="true" /> <phing phingfile="${project.basedir}/phing/app.xml" haltonfailure="true"/>
</target> </target>
<!-- Build tests --> <!-- Build tests -->
<target name="build:tests" description="Runs all tests, checks and creates docs"> <target name="build:tests">
<phing phingfile="phing/tests.xml" haltonfailure="true" /> <phing phingfile="${project.basedir}/phing/tests.xml" haltonfailure="true"/>
<!--
Conditional running of tests.
Disabled, because not required.
Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
2017-02-22
<if>
<equals arg1="${env}" arg2="test" />
<then>
<phing phingfile="phing/tests.xml" haltonfailure="true" />
</then>
<else>
<echo message="[Skipped] Running tests, checks and creating docs, because it's a not 'test' environment..." />
</else>
</if>
-->
</target> </target>
</project> </project>

View File

@@ -2,7 +2,6 @@
"name": "meritoo/common-library", "name": "meritoo/common-library",
"description": "Useful classes, methods, extensions etc.", "description": "Useful classes, methods, extensions etc.",
"license": "MIT", "license": "MIT",
"version": "0.0.7",
"authors": [ "authors": [
{ {
"name": "Meritoo.pl", "name": "Meritoo.pl",
@@ -11,24 +10,32 @@
} }
], ],
"require": { "require": {
"php": ">=5.6.0", "php": ">=5.6",
"ext-intl": "*",
"ext-pcre": "*",
"doctrine/orm": "^2.5", "doctrine/orm": "^2.5",
"gedmo/doctrine-extensions": "^2.4", "gedmo/doctrine-extensions": "^2.4"
"symfony/http-foundation": "^3.3"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8 || ^5.0", "friendsofphp/php-cs-fixer": "^2.2",
"squizlabs/php_codesniffer": "^2.8",
"phpmd/phpmd": "^2.6",
"sebastian/phpcpd": "^3.0",
"pdepend/pdepend": "^2.5", "pdepend/pdepend": "^2.5",
"phploc/phploc": "^3.0", "phploc/phploc": "^2.1",
"friendsofphp/php-cs-fixer": "^2.1" "phpmd/phpmd": "^2.6",
"phpunit/phpunit": "^4.8",
"sebastian/phpcpd": "^2.0",
"squizlabs/php_codesniffer": "^2.9"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Meritoo\\Common\\": "src/Meritoo/Common/", "Meritoo\\Common\\": "src/"
"Meritoo\\Common\\Test\\": "tests/Meritoo/Common/Test/"
} }
},
"autoload-dev": {
"psr-4": {
"Meritoo\\Common\\Test\\": "tests/"
}
},
"config": {
"sort-packages": true
} }
} }

3518
composer.lock generated

File diff suppressed because it is too large Load Diff

33
docker-compose.yml Normal file
View File

@@ -0,0 +1,33 @@
version: '3'
services:
#
# Required to run project
#
php:
image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php
container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-php
entrypoint: php
command: -S 0.0.0.0:9999
build:
context: ./docker/config
args:
- TIMEZONE=${TIMEZONE}
volumes:
- .:/project:cached
composer:
image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php
container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-composer
entrypoint: php -d memory_limit=-1 /usr/local/bin/composer
volumes:
- .:/project:cached
#
# Required to run PHPUnit's tests
#
phpunit:
image: ${DOCKER_CONTAINER_OWNER}/${DOCKER_CONTAINER_PROJECT}-php
container_name: ${DOCKER_CONTAINER_OWNER}-${DOCKER_CONTAINER_PROJECT}-phpunit
entrypoint: ./vendor/bin/phpunit
command: --version
volumes:
- .:/project:cached

131
docker/config/Dockerfile Normal file
View File

@@ -0,0 +1,131 @@
FROM php:5.6-cli
MAINTAINER Meritoo <github@meritoo.pl>
#
# Tools & libraries
#
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
vim \
git \
unzip \
libicu-dev \
locales \
&& apt-get clean \
&& rm -rf \
/var/lib/apt/lists/* \
/tmp/* \
/var/tmp/*
#
# Generating locales:
# - de_DE
# - es_ES
# - en_GB
# - en_US
# - fr_FR
# - it_IT
# - pl_PL
# - ru_RU
#
RUN sed -i 's/^# de_DE/de_DE/g; \
s/^# es_ES/es_ES/g; \
s/^# en_GB/en_GB/g; \
s/^# en_US/en_US/g; \
s/^# fr_FR/fr_FR/g; \
s/^# it_IT/it_IT/g; \
s/^# pl_PL/pl_PL/g; \
s/^# ru_RU/ru_RU/g;' /etc/locale.gen \
&& locale-gen
#
# Set default language
#
# Required to avoid problem with using strange language by error messages.
# Example: "chmod(): Aucun fichier ou dossier de ce type"
#
ENV LANGUAGE=en_US.UTF-8
#
# PHP extensions
#
RUN docker-php-ext-install \
intl \
mbstring
#
# PHP extensions (PECL):
# - Xdebug
#
RUN pecl install \
xdebug-2.5.5 \
&& docker-php-ext-enable \
xdebug
COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
#
# PHP configuration:
# - default configuration
# - timezone
#
COPY php.ini /usr/local/etc/php/php.ini
ARG TIMEZONE
RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \
&& echo ${TIMEZONE} > /etc/timezone \
&& printf '[PHP]\ndate.timezone = "%s"\n' ${TIMEZONE} > /usr/local/etc/php/conf.d/tzone.ini \
&& "date"
#RUN echo "\n""date.timezone = $TIMEZONE""\n" >> /usr/local/etc/php/php.ini
#
# Phing
#
RUN pear channel-discover pear.phing.info \
&& pear install [--alldeps] phing/phing
#
# Composer - environment variables:
# - disable warning about running commands as root/super user
# - disable automatic clearing of sudo sessions
#
# More:
# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
#
ENV COMPOSER_ALLOW_SUPERUSER 1
#
# Composer + https://packagist.org/packages/hirak/prestissimo package
#
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php -r "if (hash_file('SHA384', 'composer-setup.php') === \
'93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { 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 \
--no-progress \
--no-suggest \
--no-interaction \
--prefer-dist \
--optimize-autoloader \
--classmap-authoritative \
hirak/prestissimo \
&& rm -rf ~/.composer/cache/* \
&& composer clear-cache \
&& composer --version
#
# Bash
#
RUN sed -i 's/^# export/export/g; \
s/^# alias/alias/g;' ~/.bashrc \
&& echo 'COLUMNS=200'"\n" >> ~/.bashrc
#
# Use project-related binaries globally
#
ENV PATH="/project/vendor/bin:${PATH}"
WORKDIR /project

3
docker/config/php.ini Normal file
View File

@@ -0,0 +1,3 @@
display_errors = On
display_startup_errors = On
error_reporting = E_ALL

6
docker/config/xdebug.ini Normal file
View File

@@ -0,0 +1,6 @@
[xdebug]
zend_extension=xdebug.so
xdebug.remote_enable=1
xdebug.remote_port=9001
xdebug.remote_host=10.254.254.254

53
docs/Base-test-case.md Normal file
View File

@@ -0,0 +1,53 @@
# Meritoo Common Library
Common and useful classes, methods, exceptions etc.
# Base test case (with common methods and data providers)
Located here: `Meritoo\Common\Test\Base\BaseTestCase`. Just extend the `BaseTestCase` class and use it like in `Meritoo\Common\Test\Utilities\DateTest` class:
```php
class DateTest extends BaseTestCase
{
/**
* @param mixed $value Empty value, e.g. ""
* @dataProvider provideEmptyValue
*/
public function testGetDateTimeEmptyValue($value)
{
self::assertFalse(Date::getDateTime($value));
}
(...)
}
```
or in `Meritoo\Common\Test\Utilities\MimeTypesTest` class:
```php
class MimeTypesTest extends BaseTestCase
{
(...)
/**
* @param bool $mimeType The mime type, e.g. "video/mpeg"
* @dataProvider provideBooleanValue
*/
public function testGetExtensionBooleanMimeType($mimeType)
{
self::assertEquals('', MimeTypes::getExtension($mimeType));
}
(...)
}
```
# More
1. [**Base test case (with common methods and data providers)**](Base-test-case.md)
2. [Collection of elements](Collection-of-elements.md)
3. [Exceptions](Exceptions.md)
4. [Static methods](Static-methods.md)
5. [Value Objects](Value-Objects.md)
[&lsaquo; Back to `Readme`](../README.md)

View File

@@ -0,0 +1,51 @@
# Meritoo Common Library
Common and useful classes, methods, exceptions etc.
# Collection of elements
Located here: `Meritoo\Common\Collection\Collection`. It's a set of some elements, e.g. objects. It's iterable and countable. Provides very useful methods. Some of them:
- `getFirst()` - returns the first element in the collection
- `getLast()` - returns the last element in the collection
- `isEmpty()` - returns information if collection is empty
- `add($element, $index = null)` - adds given element (at the end of collection)
- `addMultiple($elements, $useIndexes = false)` - adds given elements (at the end of collection)
- `prepend($element)` - prepends given element (adds given element at the beginning of collection)
- `remove($element)` - removes given element
Examples of usage below.
### An empty collection
```php
use Meritoo\Common\Collection\Collection;
$emptyCollection = new Collection();
var_dump($emptyCollection->isEmpty()); // bool(true)
```
### Simple collection
```php
use Meritoo\Common\Collection\Collection;
$elements = [
'lorem',
'ipsum',
123 => 'dolor',
345 => 'sit',
];
$simpleCollection = new Collection($elements);
var_dump($simpleCollection->has('dolor')); // bool(true)
```
# More
1. [Base test case (with common methods and data providers)](Base-test-case.md)
2. [**Collection of elements**](Collection-of-elements.md)
3. [Exceptions](Exceptions.md)
4. [Static methods](Static-methods.md)
5. [Value Objects](Value-Objects.md)
[&lsaquo; Back to `Readme`](../README.md)

123
docs/Development.md Normal file
View File

@@ -0,0 +1,123 @@
# Meritoo Common Library
Development-related information
# Requirements
* [Docker](https://www.docker.com)
* Your favourite IDE :)
# Getting started
1. Build, create and start Docker's containers by running command:
```bash
docker-compose up -d
```
2. Rebuild project by running command (installs packages, prepares required directories and runs tests):
```bash
docker-compose exec php phing
```
> [What is Docker?](https://www.docker.com/what-docker)
# Composer
Available as `composer` service. You can run any Composer's command using the `composer` service:
```bash
docker-compose run --rm composer [command]
```
Examples below.
##### Install packages
```bash
docker-compose run --rm composer install
```
##### Update packages
```bash
docker-compose run --rm composer update
```
##### Add package
```bash
docker-compose run --rm composer require [vendor]/[package]
```
##### Remove package
```bash
docker-compose run --rm composer remove [vendor]/[package]
```
# Coding Standards Fixer
Fix coding standard by running command:
```bash
docker-compose exec php php-cs-fixer fix
```
or
```bash
docker-compose exec php phing -f phing/tests.xml build:fix-coding-standards
```
Omit cache and run the Fixer from scratch by running command:
```bash
docker-compose exec php rm .php_cs.cache && docker-compose exec php php-cs-fixer fix
```
> [Want more?](https://cs.sensiolabs.org)
# Tests
### Prerequisites
Install required packages by running command: `docker-compose run --rm composer install`.
### Running [PHPUnit](https://phpunit.de) tests
##### Easy (with code coverage)
```bash
docker-compose run --rm phpunit --verbose
```
or
```bash
docker-compose exec php phing -f phing/tests.xml test:phpunit
```
##### Quick (without code coverage)
```bash
docker-compose run --rm phpunit --verbose --no-coverage
```
# Versions of packages
### squizlabs/php_codesniffer
I have to use [squizlabs/php_codesniffer](https://packagist.org/packages/squizlabs/php_codesniffer) `^2.9` instead of
`^3.3`, because [Phing doesn't support 3.x PHP_CodeSniffer](https://github.com/phingofficial/phing/issues/716).
# Other
Rebuild project and run tests by running command:
```bash
docker-compose exec php phing
```
[&lsaquo; Back to `Readme`](../README.md)

62
docs/Exceptions.md Normal file
View File

@@ -0,0 +1,62 @@
# Meritoo Common Library
Common and useful classes, methods, exceptions etc.
# Exceptions
### Create instance of exception
This package contains a lot of exceptions. Each of them contains static method `create()` with proper arguments that is used to create instance of the exception. Example:
```php
use Meritoo\Common\Exception\Bundle\IncorrectBundleNameException;
throw IncorrectBundleNameException::create('RisusIpsum');
```
### Base exception for unknown type of something
##### Short description
It's a `Meritoo\Common\Exception\Base\UnknownTypeException` class. Related to `Meritoo\Common\Type\Base\BaseType` class that represents type of something, e.g. type of button, order.
##### Usage
You can extend `Meritoo\Common\Exception\Base\UnknownTypeException` class and create your own static method, e.g. `createException()`, which will be used create instance of the exception. Inside the `createException()` method you can call `parent::create()` method.
##### Example
```php
<?php
namespace Your\Package\Exception\Type;
use Meritoo\Common\Exception\Base\UnknownTypeException;
use Your\Package\Type\SimpleType;
class UnknownSimpleTypeException extends UnknownTypeException
{
/**
* Creates exception
*
* @param string $unknownType Unknown and simple type
* @return UnknownSimpleTypeException
*/
public static function createException($unknownType)
{
/* @var UnknownSimpleTypeException $exception */
$exception = parent::create($unknownType, new SimpleType(), 'my simple type of something');
return $exception;
}
}
```
# More
1. [Base test case (with common methods and data providers)](Base-test-case.md)
2. [Collection of elements](Collection-of-elements.md)
3. [**Exceptions**](Exceptions.md)
4. [Static methods](Static-methods.md)
5. [Value Objects](Value-Objects.md)
[&lsaquo; Back to `Readme`](../README.md)

24
docs/Static-methods.md Normal file
View File

@@ -0,0 +1,24 @@
# Meritoo Common Library
Common and useful classes, methods, exceptions etc.
# Static methods
This package contains a lot of class with static methods, so usage is not so complicated. Just run the static method who would you like to use. Example:
```php
use Meritoo\Common\Utilities\Arrays;
$firstElement = Arrays::getFirstElement(['lorem', 'ipsum']);
var_dump($firstElement); // string(5) "lorem"
```
# More
1. [Base test case (with common methods and data providers)](Base-test-case.md)
2. [Collection of elements](Collection-of-elements.md)
3. [Exceptions](Exceptions.md)
4. [**Static methods**](Static-methods.md)
5. [Value Objects](Value-Objects.md)
[&lsaquo; Back to `Readme`](../README.md)

53
docs/Value-Objects.md Normal file
View File

@@ -0,0 +1,53 @@
# Meritoo Common Library
Common and useful classes, methods, exceptions etc.
# Value Objects
Located in `Meritoo\Common\ValueObject` namespace.
### Version
##### Namespace
`Meritoo\Common\ValueObject\Version`
##### Info
Represents version of software. Contains 3 properties:
1. `$majorPart` - the "major" part of version
2. `$minorPart` - the "minor" part of version
3. `$patchPart` - the "patch" part of version
##### New instance
New instance can be created using:
1. Constructor:
```php
new Version(1, 0, 2);
```
2. Static methods:
1. `fromArray()` - creates new instance using given version as array
```php
Version::fromArray([1, 0, 2]);
```
2. `fromString()` - creates new instance using given version as string:
```php
Version::fromString('1.0.2');
```
# More
1. [Base test case (with common methods and data providers)](Base-test-case.md)
2. [Collection of elements](Collection-of-elements.md)
3. [Exceptions](Exceptions.md)
4. [Static methods](Static-methods.md)
5. [**Value Objects**](Value-Objects.md)
[&lsaquo; Back to `Readme`](../README.md)

View File

@@ -1,89 +1,184 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project name="Meritoo Package" basedir="." default="build:main" phingVersion="2.14.0">
<project name="Meritoo Package" basedir="." default="build:main" phingVersion="2.16.0">
<!-- Properties --> <!-- Properties -->
<if> <if>
<available file="phing/properties" property="custom.properties.available"/> <available file="${project.basedir}/phing/properties" property="custom.properties.available"/>
<then> <then>
<property file="phing/properties" /> <property file="${project.basedir}/phing/properties"/>
</then> </then>
<else> <else>
<property file="phing/properties.dist" /> <property file="${project.basedir}/phing/properties.dist"/>
</else> </else>
</if> </if>
<!-- Filesets -->
<import file="${project.basedir}/phing/filesets.xml"/>
<!-- Default / main target --> <!-- Default / main target -->
<target name="build:main" <target name="build:main"
depends="build:app" depends="build:app"
description="Builds the application" /> />
<!-- App target --> <!-- App target -->
<target name="build:app" <target name="build:app"
depends="app:composer, app:vendors, app:checkout" depends="app:clean,
description="Prepares app to build." /> app:composer:self-update,
app:composer:install,
<!-- Check / update composer --> app:composer:validate,
<target name="app:composer" description="Checks / updates composer"> app:checkout"
<echo msg="Checking / updating composer..." /> />
<!-- Updates Composer -->
<target name="app:composer:self-update">
<if> <if>
<available file="composer.phar" /> <not>
<available file="${composer.path}" property="composer.local.unavailable"/>
</not>
<then> <then>
<echo msg="[Skipped] Downloading of Composer skipped, because exist in the project..." />
</then>
<else>
<if> <if>
<os family="windows" /> <os family="windows"/>
<then> <then>
<fail message="Composer not found! Go to http://getcomposer.org/download and download the Composer." /> <fail message="Composer not found! Go to http://getcomposer.org/download and download the Composer."/>
</then> </then>
<else> <else>
<exec command="${composer.download_command}" checkreturn="true" /> <exec command="${composer.download_command}" checkreturn="true" passthru="true"/>
</else> </else>
</if> </if>
</else> </then>
</if> </if>
<composer command="selfupdate" />
<!-- Update Composer -->
<composer php="${composer.php}" composer="${composer.path}" command="selfupdate">
<arg value="--ansi"/>
</composer>
</target> </target>
<!-- Project Install/update vendors --> <!-- Validates composer.* files -->
<target name="app:vendors" description="Installs / updates vendors"> <target name="app:composer:validate" depends="app:composer:install">
<echo msg="Installing / updating vendors..." /> <composer php="${composer.php}" composer="${composer.path}" command="validate">
<arg value="--no-check-all"/>
<arg value="--strict"/>
<arg value="--ansi"/>
</composer>
</target>
<!-- Project clean -->
<target name="app:clean">
<if> <if>
<istrue value="${composer.self-update}"/> <equals arg1="${env}" arg2="prod"/>
<then> <then>
<composer php="${composer.php}" composer="${composer.path}" command="self-update"/> <echo message="[Skipped] Cleaning project (and directories cleanup) -> 'prod' environment"/>
</then>
</if>
<if>
<istrue value="${composer.validate}"/>
<then>
<composer php="${composer.php}" composer="${composer.path}" command="validate"/>
</then>
</if>
<if>
<equals arg1="${env}" arg2="prod" />
<then>
<composer php="${composer.php}" composer="${composer.path}" command="install">
<arg value="--optimize-autoloader" />
</composer>
</then> </then>
<else> <else>
<composer php="${composer.php}" composer="${composer.path}" command="install" /> <foreach list="${directoriesToEmpty}" param="directory" target="app:clean:empty"/>
</else> </else>
</if> </if>
<foreach list="${directoriesToCheck}" param="directory" target="app:clean:check"/>
<touch file="${dir.cache}/.gitkeep"/>
<touch file="${dir.logs}/.gitkeep"/>
<touch file="${dir.sessions}/.gitkeep"/>
<foreach list="${directoriesToEmpty}" param="directory" target="app:permissions"/>
</target>
<!-- Cleaning directory (making empty) directory -->
<target name="app:clean:empty">
<if>
<available file="${directory}" type="dir" property="dir_is_available"/>
<then>
<delete includeemptydirs="true" dir="${directory}"/>
</then>
</if>
</target>
<!-- Checking if directory exists -->
<target name="app:clean:check">
<if>
<not>
<available file="${directory}" type="dir" property="dir_is_available"/>
</not>
<then>
<if>
<or>
<contains string="${directory}" substring="cache"/>
<contains string="${directory}" substring="logs"/>
<contains string="${directory}" substring="sessions"/>
</or>
<then>
<mkdir dir="${directory}" mode="0777"/>
</then>
<else>
<mkdir dir="${directory}" mode="0775"/>
</else>
</if>
</then>
</if>
</target>
<!-- Installs vendors -->
<target name="app:composer:install" depends="app:composer:self-update">
<composer php="${composer.php}" composer="${composer.path}" command="install">
<arg value="--optimize-autoloader"/>
<arg value="--ansi"/>
</composer>
</target>
<!-- Clearing cache -->
<target name="app:cache">
<if>
<istrue value="${cache.clearWithWarmup}"/>
<then>
<SymfonyConsole console="bin/console" command="cache:clear">
<arg name="env" value="${env}"/>
</SymfonyConsole>
</then>
<else>
<SymfonyConsole console="bin/console" command="cache:clear">
<arg name="env" value="${env}"/>
<arg name="no-warmup"/>
</SymfonyConsole>
</else>
</if>
</target>
<!-- Clearing cache (faster) -->
<target name="app:cache:faster">
<SymfonyConsole console="bin/console" command="cache:clear">
<arg name="env" value="${env}"/>
<arg name="no-optional-warmers"/>
</SymfonyConsole>
</target>
<!-- Warming up cache -->
<target name="app:cache:warmup">
<SymfonyConsole console="bin/console" command="cache:warmup">
<arg name="env" value="${env}"/>
</SymfonyConsole>
</target>
<!-- Setting permissions of given directory -->
<target name="app:permissions">
<if>
<not>
<os family="windows"/>
</not>
<then>
<exec command="chmod -R 777 ${directory}/*"/>
</then>
</if>
</target> </target>
<!-- Checkout and finalization --> <!-- Checkout and finalization -->
<target name="app:checkout"> <target name="app:checkout">
<tstamp> <tstamp>
<format property="date_end" pattern="%Y-%m-%d %H:%M" /> <format property="date_end" pattern="%Y-%m-%d %H:%M"/>
</tstamp> </tstamp>
<echo msg="------------------------------------" /> <echo msg="------------------------------------"/>
<echo msg="Build finished at: ${date_end}" /> <echo msg="Build finished at: ${date_end}"/>
<echo msg="------------------------------------" /> <echo msg="------------------------------------"/>
</target> </target>
</project> </project>

20
phing/composer-install.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
EXPECTED_SIGNATURE="$(curl -L https://composer.github.io/installer.sig)"
# Original line (with wget):
# EXPECTED_SIGNATURE="$(wget -q -O - https://composer.github.io/installer.sig)"
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_SIGNATURE="$(php -r "echo hash_file('SHA384', 'composer-setup.php');")"
if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]
then
>&2 echo 'ERROR: Invalid installer signature'
rm composer-setup.php
exit 1
fi
php composer-setup.php --quiet
RESULT=$?
rm composer-setup.php
exit $RESULT

36
phing/filesets.xml Normal file
View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="Meritoo Package" basedir="." default="build:main" phingVersion="2.16.0">
<!-- Filesets -->
<fileset id="cache" dir="${dir.cache}">
<include name="**/*"/>
<exclude name=".gitkeep"/>
</fileset>
<fileset id="logs" dir="${dir.logs}">
<include name="**/*"/>
<exclude name=".gitkeep"/>
</fileset>
<fileset id="sessions" dir="${dir.sessions}">
<include name="**/*"/>
<exclude name=".gitkeep"/>
</fileset>
<!-- Directories to check -->
<property name="directoriesToCheck" value="
${dir.cache},
${dir.logs},
${dir.sessions},
${dir.data.tests},
${dir.data.temporary},
${dir.docker.data},
${dir.docker.logs}"
/>
<!-- Directories to empty -->
<property name="directoriesToEmpty" value="
${dir.cache},
${dir.logs},
${dir.sessions},
${dir.data.temporary}"
/>
</project>

View File

@@ -1,19 +1,3 @@
# --------------------------------------------------------------------------------
# Information
# --------------------------------------------------------------------------------
# Property files contain key/value pairs
# key = value
#
# Property keys may contain alphanumeric chars and colons, but
# not special chars. This way you can create pseudo-namespaces
#
# You can refer to values of other properties by enclosing their keys in "${}".
# Example: dir.js = ${dir.web}/js
#
# Everything behind the equal sign is the value, you do
# not have to enclose strings: text=This is some text, Your OS is ${php.os}
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
# Common, e.g. default environment # Common, e.g. default environment
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
@@ -22,104 +6,77 @@
# #
env = dev env = dev
# Install assets using symlinks
#
assets.installWithSymlink = true
# Clear cache with the "warmup" option # Clear cache with the "warmup" option
# #
cache.clearWithWarmup = 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
#
# Meritoo <github@meritoo.pl>
# 2017-06-06
#
cache.clearWithWarmup = false
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
# Composer # Composer
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
composer.download_command = php -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));" # Command used to download Composer
# Path to composer executable or composer.phar file
# #
composer.path = composer.phar composer.download_command = bash ${project.basedir}/phing/composer-install.sh
#composer.path = /usr/local/bin/composer
# Path to composer executable or downloaded composer.phar file
#
composer.path = ${project.basedir}/composer.phar
# Path to php executable used by composer # Path to php executable used by composer
# #
composer.php = php composer.php = php
# Self update of the composer
#
composer.self-update = false
# Validate the composer.json file
#
composer.validate = false
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
# Directories # Directories
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
# System directories # System directories
# #
dir.data = ${project.basedir}/data
dir.src = ${project.basedir}/src dir.src = ${project.basedir}/src
dir.var = ${project.basedir}/tests/Resources/var
dir.cache = ${dir.var}/cache
dir.logs = ${dir.var}/log
dir.sessions = ${dir.var}/sessions
dir.data = ${project.basedir}/data
dir.tests = ${project.basedir}/tests dir.tests = ${project.basedir}/tests
# --------------------------------------------------------------------------------
# Build directories # Build directories
# -------------------------------------------------------------------------------- #
dir.build = ${project.basedir}/build dir.build = ${project.basedir}/build
dir.reports = ${dir.build}/logs dir.reports = ${dir.build}/reports
dir.reports.pdepend = ${dir.reports}/pdepend dir.reports.pdepend = ${dir.reports}/pdepend
dir.reports.coverage = ${dir.reports}/phpunit_coverage dir.reports.coverage = ${dir.reports}/phpunit_coverage
#
# Disabled, because unnecessary right now
# phpdocumentor/phpdocumentor cannot be installed via Composer
#
# Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
# 2017-02-22
#
#dir.docs = ${dir.build}/docs
#dir.docs.phpdoc2 = ${dir.docs}/phpdoc2
# --------------------------------------------------------------------------------
# Data directories # Data directories
# -------------------------------------------------------------------------------- #
dir.data.tests = ${dir.data}/tests dir.data.tests = ${dir.data}/tests
dir.data.temporary = ${dir.data}/tmp dir.data.temporary = ${dir.data}/tmp
# Docker directories
#
dir.docker = ${project.basedir}/docker
dir.docker.data = ${dir.docker}/data/db
dir.docker.logs = ${dir.docker}/logs/nginx
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
# Testing # Testing
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
# Path of the PHP Coding Standards Fixer (http://cs.sensiolabs.org)
#
tests.cs_fixer.command = ./vendor/bin/php-cs-fixer fix --verbose
# Test database path # Test database path
# #
tests.database = ${dir.data.temporary}/database.sqlite tests.database = ${dir.data.temporary}/database.sqlite
# Paths of frameworks used to run tests:
# - PHPUnit (unit tests)
# #
# Disabled, because unnecessary right now tests.phpunit.command = ./vendor/bin/phpunit --verbose
# PHPUnit is installed and loaded by Composer
#
# Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
# 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 <krzysztof.niziol@meritoo.pl>
# 2017-02-22
#
# Collect coverage data during tests
#phpunit.withCoverage = true
# Path of the PHPUnit (https://phpunit.de)
#
phpUnit.path = ./vendor/bin/phpunit
# Path of the PHP Coding Standards Fixer (http://cs.sensiolabs.org)
#
phpCsFixer.path = ./vendor/bin/php-cs-fixer

View File

@@ -1,315 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project name="Meritoo Package" basedir="." default="build:main" phingVersion="2.14.0">
<!--
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 <krzysztof.niziol@meritoo.pl> <project name="Meritoo Package" basedir="." default="build:main" phingVersion="2.16.0">
2017-02-23 <autoloader/>
-->
<autoloader />
<!-- Properties --> <!-- Properties -->
<if> <if>
<available file="phing/properties" property="custom.properties.available"/> <available file="${project.basedir}/phing/properties" property="custom.properties.available"/>
<then> <then>
<property file="phing/properties" /> <property file="${project.basedir}/phing/properties"/>
</then> </then>
<else> <else>
<property file="phing/properties.dist" /> <property file="${project.basedir}/phing/properties.dist"/>
</else> </else>
</if> </if>
<!-- Filesets --> <!-- Filesets -->
<fileset id="sourcecode" dir="${dir.src}"> <fileset id="sourcecode" dir="${dir.src}">
<include name="**/*.php" /> <include name="**/*.php"/>
<exclude name="*Test.php" /> <exclude name="*Test.php"/>
<exclude name="**/*Test.php" /> <exclude name="**/*Test.php"/>
<exclude name="**/Resources/**" /> <exclude name="**/Resources/**"/>
<exclude name="**/DataFixtures/**" /> <exclude name="**/DataFixtures/**"/>
<exclude name="**/Tests/**" /> <exclude name="**/Tests/**"/>
</fileset> </fileset>
<fileset id="tests" dir="${dir.tests}"> <fileset id="tests" dir="${dir.tests}">
<include name="**/*Test*.php" /> <include name="**/*Test*.php"/>
</fileset> </fileset>
<!-- Default / main target --> <!-- Default / main target -->
<target name="build:main" <target name="build:main"
depends="build:fix-coding-standards, build:clean, build:prepare, build:check, build:test, app:checkout" depends="build:fix-coding-standards,
description="Runs all tests and builds everything" /> build:check,
<!-- build:test,
Before: app:checkout"
depends="build:fix-coding-standards, build:clean, build:prepare, build:check, build:test, build:doc, app:checkout" />
After:
depends="build:fix-coding-standards, build:clean, build:prepare, build:check, build:test, app:checkout"
The "build:doc" task is disabled, because it cannot be installed via Composer:
a) phpdocumentor/phpdocumentor v2.9.0 requires symfony/validator ~2.2
b) symfony/validator ~2.2 causes to remove symfony/symfony 3.*
Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
2017-02-22
-->
<!-- Fixing coding standards using the PHP Coding Standards Fixer (http://cs.sensiolabs.org) --> <!-- Fixing coding standards using the PHP Coding Standards Fixer (http://cs.sensiolabs.org) -->
<target name="build:fix-coding-standards" description="Fixes coding standards using the PHP Coding Standards Fixer"> <target name="build:fix-coding-standards">
<echo msg="Fixing coding standards using the PHP Coding Standards Fixer (http://cs.sensiolabs.org)..." /> <exec command="${tests.cs_fixer.command}" passthru="true"/>
<!--
Attention.
Rules for formatting are defined in /.php_cs.dist file.
-->
<exec
passthru="true"
command="${phpCsFixer.path} fix --verbose"
/>
</target> </target>
<!-- Doc target -->
<!--
Disabled, because it cannot be installed via Composer:
a) phpdocumentor/phpdocumentor v2.9.0 requires symfony/validator ~2.2
b) symfony/validator ~2.2 causes to remove symfony/symfony 3.*
Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
2017-02-22
-->
<!--<target name="build:doc"-->
<!--depends="build:prepare, doc:phpdoc2"-->
<!--description="Generates API documentation" />-->
<!-- Check target --> <!-- Check target -->
<target name="build:check" <target name="build:check"
depends="check:cs, check:md, check:cpd, check:depend, check:loc" depends="check:cs,
description="Analyzes code" /> check:md,
check:cpd,
check:depend,
check:loc"
/>
<!-- Test target --> <!-- Test target -->
<target name="build:test" <target name="build:test"
depends="test:phpunit" depends="test:phpunit"
description="Executes all tests" /> />
<!-- Project build clean -->
<target name="build:clean" description="Cleans up build directories">
<echo msg="Cleaning docs and reports directories..." />
<!--<delete dir="${dir.docs}" />-->
<delete dir="${dir.reports}" />
</target>
<!-- Project build prepare -->
<target name="build:prepare" description="Create build directories">
<echo msg="Creating build directories..." />
<!--<mkdir dir="${dir.docs}" />-->
<!--<mkdir dir="${dir.docs.phpdoc2}" />-->
<mkdir dir="${dir.reports}" />
<mkdir dir="${dir.reports.coverage}" />
<mkdir dir="${dir.reports.pdepend}" />
</target>
<!-- PHPDocumentor2 API documentation target -->
<!--
Disabled, because it cannot be installed via Composer:
a) phpdocumentor/phpdocumentor v2.9.0 requires symfony/validator ~2.2
b) symfony/validator ~2.2 causes to remove symfony/symfony 3.*
Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
2017-02-22
<target name="doc:phpdoc2" description="Generates API documentations">
<echo msg="Generating API Documentation with phpDocumentor 2..." />
<phpdoc2 title="${phing.project.name}"
destdir="${dir.docs.phpdoc2}"
template="responsive">
<fileset refid="sourcecode" />
</phpdoc2>
</target>
-->
<!-- Symfony2 code sniffer --> <!-- Symfony2 code sniffer -->
<!-- <target name="check:cs" depends="build:prepare">
Attention 1.
To use Symfony2 standards to check coding you have to:
copy, symlink or check out repo to a folder called Symfony2 inside the phpcs Standards directory.
Example:
$ pear config-show | grep php_dir
$ cd /path/to/pear/PHP/CodeSniffer/Standards
$ git clone git://github.com/opensky/Symfony2-coding-standard.git Symfony2
Attention 2.
PSR2 standard is used instead of Symfony2 standard, because after installation squizlabs/php_codesniffer package
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 <krzysztof.niziol@meritoo.pl>
2017-02-22
-->
<target name="check:cs" description="Checks coding standard">
<echo msg="Checking coding standard..." />
<phpcodesniffer standard="PSR2" showWarnings="true"> <phpcodesniffer standard="PSR2" showWarnings="true">
<fileset refid="sourcecode" /> <fileset refid="sourcecode"/>
<formatter type="checkstyle" outfile="${dir.reports}/checkstyle.xml" /> <formatter type="checkstyle" outfile="${dir.reports}/checkstyle.xml"/>
<formatter type="csv" outfile="${dir.reports}/checkstyle.csv" /> <formatter type="csv" outfile="${dir.reports}/checkstyle.csv"/>
<formatter type="summary" outfile="${dir.reports}/checkstyle_summary.txt" /> <formatter type="summary" outfile="${dir.reports}/checkstyle_summary.txt"/>
</phpcodesniffer> </phpcodesniffer>
</target> </target>
<!-- copy/paste detector --> <!-- copy/paste detector -->
<target name="check:cpd" description="Checks similar code blocks."> <target name="check:cpd" depends="build:prepare">
<echo msg="Checking similar code blocks..." />
<phpcpd> <phpcpd>
<fileset refid="sourcecode" /> <fileset refid="sourcecode"/>
<formatter type="pmd" outfile="${dir.reports}/pmd-cpd.xml" /> <formatter type="pmd" outfile="${dir.reports}/pmd-cpd.xml"/>
</phpcpd> </phpcpd>
<!--
Previous / old version
Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
2017-02-22
<exec command="phpcpd \-\-log-pmd=${dir.reports}/pmd-cpd.xml ${dir.src}" />
-->
</target> </target>
<!-- Mess detector --> <!-- Mess detector -->
<target name="check:md" description="Generate code metrics"> <target name="check:md" depends="build:prepare">
<echo msg="Generating code metrics..." />
<phpmd rulesets="codesize,controversial,design,naming,unusedcode"> <phpmd rulesets="codesize,controversial,design,naming,unusedcode">
<fileset refid="sourcecode" /> <fileset refid="sourcecode"/>
<formatter type="html" outfile="${dir.reports}/phpmd.html" /> <formatter type="html" outfile="${dir.reports}/phpmd.html"/>
<formatter type="text" outfile="${dir.reports}/phpmd.txt" /> <formatter type="text" outfile="${dir.reports}/phpmd.txt"/>
</phpmd> </phpmd>
</target> </target>
<!-- Code dependency --> <!-- Code dependency -->
<target name="check:depend" description="Checks coupling and dependency"> <target name="check:depend" depends="build:prepare">
<echo msg="Checking coupling and dependency..." />
<phpdepend> <phpdepend>
<fileset refid="sourcecode" /> <fileset refid="sourcecode"/>
<logger type="jdepend-xml" outfile="${dir.reports.pdepend}/jdepend.xml" /> <logger type="jdepend-xml" outfile="${dir.reports.pdepend}/jdepend.xml"/>
<logger type="jdepend-chart" outfile="${dir.reports.pdepend}/dependencies.svg" /> <logger type="jdepend-chart" outfile="${dir.reports.pdepend}/dependencies.svg"/>
<logger type="overview-pyramid" outfile="${dir.reports.pdepend}/overview-pyramid.svg" /> <logger type="overview-pyramid" outfile="${dir.reports.pdepend}/overview-pyramid.svg"/>
</phpdepend> </phpdepend>
</target> </target>
<!-- Measure the size and analyzing the structure of a project --> <!-- Measure the size and analyzing the structure of a project -->
<target name="check:loc" description="Measures the size and analyzes the structure of a project"> <target name="check:loc" depends="build:prepare">
<echo msg="Measuring the size and analyzing the structure of a project..." />
<phploc reportType="txt" reportName="phploc" reportDirectory="${dir.reports}"> <phploc reportType="txt" reportName="phploc" reportDirectory="${dir.reports}">
<fileset refid="sourcecode" /> <fileset refid="sourcecode"/>
</phploc> </phploc>
<!--
Previous / old version
Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
2017-02-22
<exec command="phploc \-\-log-csv=${dir.reports}/phploc.csv ${dir.src}" />
-->
</target> </target>
<!-- Unit tests --> <!-- PHPUnit tests -->
<target name="test:phpunit" description="Executes PHPUnit tests"> <target name="test:phpunit" depends="build:prepare">
<!-- Check test database --> <exec command="${tests.phpunit.command}" passthru="true"/>
</target>
<!-- Project build clean -->
<target name="build:clean">
<if> <if>
<not> <available file="${dir.reports}" type="dir" property="dir_is_available"/>
<available file="${dir.data.tests}" type="dir" property="dir.data.tests.available" />
</not>
<then> <then>
<mkdir dir="${dir.data.tests}" /> <delete dir="${dir.reports}"/>
</then> </then>
</if> </if>
<if> </target>
<not>
<available file="${tests.database}" property="tests.database.available" />
</not>
<then>
<touch file="${tests.database}" />
</then>
</if>
<echo msg="Running unit tests..." />
<coverage-setup database="${dir.reports.coverage}/coverage.db">
<fileset refid="sourcecode" />
</coverage-setup>
<exec command="${phpUnit.path} --verbose --configuration ${project.basedir}/phpunit.xml.dist" passthru="true" />
<!--
I have to use ExecTask to run PHPUnit instead of PHPUnitTask, because tests are not running if PHPUnitTask is
used (don't know why):
Total tests run: 0, Failures: 0, Errors: 0, Incomplete: 0, Skipped: 0
Krzysztof Niziol <krzysztof.niziol@meritoo.pl> <!-- Project build prepare -->
2017-02-23 <target name="build:prepare" depends="build:clean">
<mkdir dir="${dir.reports}"/>
<phpunit configuration="${project.basedir}/phpunit.xml.dist" printsummary="true"> <mkdir dir="${dir.reports.pdepend}"/>
<formatter type="xml" todir="${dir.reports}" outfile="phpunit.xml" /> <mkdir dir="${dir.reports.coverage}"/>
<formatter type="plain" todir="${dir.reports}" outfile="phpunit.txt" />
<formatter type="clover" todir="${dir.reports.coverage}" />
<formatter type="summary" todir="${dir.reports}" outfile="phpunit_summary.txt" />
</phpunit>
-->
<!--
Previous / old version
Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
2017-02-22
<if>
<istrue value="${phpunit.useExec}" />
<then>
<if>
<istrue value="${phpunit.withCoverage}" />
<then>
<echo message="Running tests with code coverage..." />
<exec command="phpunit \-\-log-junit ${dir.reports}/phpunit.xml \-\-coverage-clover ${dir.reports.coverage}/clover-coverage.xml \-\-coverage-crap4j ${dir.reports.coverage}/crap4j-coverage.xml \-\-coverage-html ${dir.reports.coverage}/ -c ${project.basedir} \-\-colors" passthru="true" checkreturn="true" />
</then>
<else>
<echo message="Running tests without code coverage..." />
<exec command="phpunit \-\-log-junit ${dir.reports}/phpunit.xml -c ${project.basedir} \-\-colors" passthru="true" checkreturn="true" />
</else>
</if>
</then>
<else>
<if>
<istrue value="${phpunit.withCoverage}" />
<then>
<echo message="Running tests with code coverage..." />
<coverage-setup database="${dir.reports.coverage}/coverage.db">
<fileset refid="sourcecode" />
</coverage-setup>
<phpunit printsummary="true" codecoverage="true">
<formatter type="xml" todir="${dir.reports}" outfile="phpunit.xml" />
<formatter type="plain" todir="${dir.reports}" outfile="phpunit.txt" />
<formatter type="clover" todir="${dir.reports.coverage}" />
<formatter type="summary" todir="${dir.reports}" outfile="phpunit_summary.txt" />
</phpunit>
</then>
<else>
<echo message="Running tests without code coverage..." />
<phpunit printsummary="true">
<formatter todir="${dir.reports}" type="xml" outfile="phpunit.xml" />
<batchtest>
<fileset refid="tests" />
</batchtest>
</phpunit>
</else>
</if>
</else>
</if>
-->
</target> </target>
<!-- Checkout and finalization --> <!-- Checkout and finalization -->
<target name="app:checkout"> <target name="app:checkout">
<tstamp> <tstamp>
<format property="date_end" pattern="%Y-%m-%d %H:%M" /> <format property="date_end" pattern="%Y-%m-%d %H:%M"/>
</tstamp> </tstamp>
<echo msg="--------------------------------------------" /> <echo msg="--------------------------------------------"/>
<echo msg="Build tests finished at: ${date_end}" /> <echo msg="Build tests finished at: ${date_end}"/>
<echo msg="--------------------------------------------" /> <echo msg="--------------------------------------------"/>
</target> </target>
</project> </project>

View File

@@ -1,35 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false" <!-- https://phpunit.de/manual/4.8/en/appendixes.configuration.html -->
backupStaticAttributes="false" <phpunit
colors="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
convertErrorsToExceptions="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/4.8/phpunit.xsd"
convertNoticesToExceptions="true" bootstrap="vendor/autoload.php"
convertWarningsToExceptions="true" colors="true"
processIsolation="false" verbose="true"
stopOnFailure="false"
syntaxCheck="true"
bootstrap="./vendor/autoload.php"
> >
<php>
<ini name="error_reporting" value="-1"/>
</php>
<testsuites> <testsuites>
<testsuite name="Meritoo Package - Main Test Suite"> <testsuite name="Meritoo Package - Main Test Suite">
<directory>./tests/</directory> <directory>tests/</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
<filter> <filter>
<whitelist> <whitelist>
<directory>./src/</directory> <directory>src/</directory>
</whitelist> </whitelist>
</filter> </filter>
<groups>
<exclude>
<group>performance</group>
</exclude>
</groups>
<logging> <logging>
<log type="coverage-html" target="./build/logs/phpunit_coverage/html" /> <log type="coverage-html" target="build/reports/phpunit_coverage/html"/>
</logging> </logging>
</phpunit> </phpunit>

View File

@@ -18,8 +18,8 @@ use Meritoo\Common\Utilities\Arrays;
* Collection of elements. * Collection of elements.
* It's a set of some elements, e.g. objects. * It's a set of some elements, e.g. objects.
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Collection implements Countable, ArrayAccess, IteratorAggregate class Collection implements Countable, ArrayAccess, IteratorAggregate
{ {
@@ -109,7 +109,7 @@ class Collection implements Countable, ArrayAccess, IteratorAggregate
*/ */
public function add($element, $index = null) public function add($element, $index = null)
{ {
if ($index === null) { if (null === $index || '' === $index) {
$this->elements[] = $element; $this->elements[] = $element;
} else { } else {
$this->elements[$index] = $element; $this->elements[$index] = $element;
@@ -216,7 +216,7 @@ class Collection implements Countable, ArrayAccess, IteratorAggregate
{ {
$index = Arrays::getIndexOf($this->elements, $element); $index = Arrays::getIndexOf($this->elements, $element);
return $index !== null && $index !== false; return null !== $index && false !== $index;
} }
/** /**

View File

@@ -15,27 +15,28 @@ use Meritoo\Common\Utilities\Arrays;
/** /**
* An exception used while type of something is unknown * An exception used while type of something is unknown
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
abstract class UnknownTypeException extends Exception abstract class UnknownTypeException extends Exception
{ {
/** /**
* Class constructor * Creates exception
* *
* @param string|int $unknownType The unknown type of something (value of constant) * @param mixed $unknownType The unknown type of something (value of constant)
* @param BaseType $typeInstance An instance of class that contains type of the something * @param BaseType $typeInstance An instance of class that contains type of the something
* @param string $typeName Name 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' $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.'; . ' of these types: %s.';
$message = sprintf(sprintf($template, $unknownType, $typeName, $types)); $allTypes = $typeInstance->getAll();
parent::__construct($message); $types = Arrays::values2string($allTypes, '', ', ');
$message = sprintf($template, $unknownType, $typeName, $types);
return new static($message);
} }
} }

View File

@@ -0,0 +1,36 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Bundle;
use Exception;
/**
* An exception used while name of bundle is incorrect
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\File;
/**
* An exception used while file with given path is empty (has no content)
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class EmptyFileException extends \Exception
{
/**
* Creates exception
*
* @param string $emptyFilePath Path of the empty file
* @return EmptyFileException
*/
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);
return new static($message);
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\File;
/**
* An exception used while path of given file is empty
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class EmptyFilePathException extends \Exception
{
/**
* Creates exception
*/
public static function create()
{
return new static('Path of the file is empty. Did you provide path of proper file?');
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\File;
/**
* An exception used while file with given path does not exist
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class NotExistingFileException extends \Exception
{
/**
* Creates exception
*
* @param string $notExistingFilePath Path of not existing (or not readable) file
* @return NotExistingFileException
*/
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);
return new static($message);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Method;
use Exception;
/**
* An exception used while method cannot be called, because is disabled
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class DisabledMethodException extends Exception
{
/**
* Creates exception
*
* @param string $disabledMethod Name of the disabled method
* @param string $alternativeMethod (optional) Name of the alternative method
* @return DisabledMethodException
*/
public static function create($disabledMethod, $alternativeMethod = '')
{
$template = 'Method %s() cannot be called, because is disabled.';
if (!empty($alternativeMethod)) {
$template .= ' Use %s() instead.';
}
$message = sprintf($template, $disabledMethod, $alternativeMethod);
return new static($message);
}
}

View File

@@ -13,20 +13,21 @@ use Exception;
/** /**
* An exception used while name of class or trait cannot be resolved * An exception used while name of class or trait cannot be resolved
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class CannotResolveClassNameException extends Exception class CannotResolveClassNameException extends Exception
{ {
/** /**
* Class constructor * Creates exception
* *
* @param array|object|string $source Source of the class's / trait's name. It cane be an array of objects, * @param array|object|string $source Source of the class's / trait's name. It can be an array of objects,
* namespaces, object or namespace. * namespaces, object or namespace.
* @param bool $forClass (optional) If is set to true, message of this exception for class is * @param bool $forClass (optional) If is set to true, message of this exception for class is
* prepared. Otherwise - for trait. * prepared. Otherwise - for trait.
* @return CannotResolveClassNameException
*/ */
public function __construct($source, $forClass = true) public static function create($source, $forClass = true)
{ {
$forWho = 'trait'; $forWho = 'trait';
$value = ''; $value = '';
@@ -42,6 +43,6 @@ class CannotResolveClassNameException extends Exception
$template = 'Name of %s from given \'%s\'%s cannot be resolved. Is there everything ok?'; $template = 'Name of %s from given \'%s\'%s cannot be resolved. Is there everything ok?';
$message = sprintf($template, $forWho, gettype($source), $value); $message = sprintf($template, $forWho, gettype($source), $value);
parent::__construct($message); return new static($message);
} }
} }

View File

@@ -14,18 +14,19 @@ use Meritoo\Common\Utilities\Reflection;
/** /**
* An exception used while given class has no child classes * An exception used while given class has no child classes
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class MissingChildClassesException extends Exception 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, * @param array|object|string $parentClass Class that hasn't child classes, but it should. An array of objects,
* strings, object or string. * 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' $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?'; . ' 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); $parentClassName = Reflection::getClassName($parentClass);
$message = sprintf($template, $parentClassName); $message = sprintf($template, $parentClassName);
parent::__construct($message); return new static($message);
} }
} }

View File

@@ -0,0 +1,33 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Reflection;
/**
* An exception used while property does not exist in instance of class
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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);
}
}

View File

@@ -14,19 +14,20 @@ use Meritoo\Common\Utilities\Reflection;
/** /**
* An exception used while given class has more than one child class * An exception used while given class has more than one child class
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class TooManyChildClassesException extends Exception 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 * @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. * of objects, strings, object or string.
* @param array $childClasses Child classes * @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" $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?"; . " 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); $parentClassName = Reflection::getClassName($parentClass);
$message = sprintf($template, $parentClassName, implode("\n- ", $childClasses), $parentClassName); $message = sprintf($template, $parentClassName, implode("\n- ", $childClasses), $parentClassName);
parent::__construct($message); return new static($message);
} }
} }

View File

@@ -11,22 +11,24 @@ namespace Meritoo\Common\Exception\Regex;
/** /**
* An exception used while length of given hexadecimal value of color is incorrect * An exception used while length of given hexadecimal value of color is incorrect
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class IncorrectColorHexLengthException extends \Exception class IncorrectColorHexLengthException extends \Exception
{ {
/** /**
* Class constructor * Creates exception
* *
* @param string $color Incorrect hexadecimal value of color * @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.' $template = 'Length of hexadecimal value of color \'%s\' is incorrect. It\'s %d, but it should be 3 or 6.'
. ' Is there everything ok?'; . ' Is there everything ok?';
$message = sprintf($template, $color, strlen($color)); $message = sprintf($template, $color, strlen($color));
parent::__construct($message);
return new static($message);
} }
} }

View File

@@ -11,19 +11,21 @@ namespace Meritoo\Common\Exception\Regex;
/** /**
* An exception used while given hexadecimal value of color is invalid * An exception used while given hexadecimal value of color is invalid
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class InvalidColorHexValueException extends \Exception class InvalidColorHexValueException extends \Exception
{ {
/** /**
* Class constructor * Creates exception
* *
* @param string $color Invalid hexadecimal value of color * @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); $message = sprintf('Hexadecimal value of color \'%s\' is invalid. Is there everything ok?', $color);
parent::__construct($message);
return new static($message);
} }
} }

View File

@@ -0,0 +1,31 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Regex;
/**
* An exception used while html attributes are invalid
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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);
}
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Regex;
/**
* An exception used while url is invalid
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class InvalidUrlException extends \Exception
{
/**
* Creates exception
*
* @param string $url Invalid url
* @return InvalidUrlException
*/
public static function create($url)
{
$message = sprintf('Url \'%s\' is invalid. Is there everything ok?', $url);
return new static($message);
}
}

View File

@@ -0,0 +1,36 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Type;
use Meritoo\Common\Exception\Base\UnknownTypeException;
use Meritoo\Common\Type\DatePartType;
/**
* An exception used while type of date part, e.g. "year", is unknown
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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;
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Type;
use Meritoo\Common\Exception\Base\UnknownTypeException;
use Meritoo\Common\Type\OopVisibilityType;
/**
* An exception used while the visibility of a property, a method or (as of PHP 7.1.0) a constant is unknown
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class UnknownOopVisibilityTypeException extends UnknownTypeException
{
/**
* Creates exception
*
* @param string $unknownType Unknown visibility of a property, a method or (as of PHP 7.1.0) a constant
* @return UnknownOopVisibilityTypeException
*/
public static function createException($unknownType)
{
/* @var UnknownOopVisibilityTypeException $exception */
$exception = parent::create($unknownType, new OopVisibilityType(), 'OOP-related visibility');
return $exception;
}
}

View File

@@ -1,32 +0,0 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Exception\Date;
use Meritoo\Common\Exception\Base\UnknownTypeException;
use Meritoo\Common\Type\DatePartType;
/**
* An exception used while type of date part, e.g. "year", is unknown
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @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));
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace Meritoo\Common\Exception\Regex;
/**
* An exception used while url is invalid
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class InvalidUrlException extends \Exception
{
/**
* Class constructor
*
* @param string $url Invalid url
*/
public function __construct($url)
{
$message = sprintf('Url \'%s\' is invalid. Is there everything ok?', $url);
parent::__construct($message);
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace Meritoo\Common\Exception\Type;
use Meritoo\Common\Exception\Base\UnknownTypeException;
use Meritoo\Common\Type\OopVisibilityType;
/**
* 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 <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class UnknownOopVisibilityTypeException extends UnknownTypeException
{
/**
* {@inheritdoc}
*/
public function __construct($unknownType)
{
parent::__construct($unknownType, new OopVisibilityType(), 'OOP-related visibility');
}
}

View File

@@ -1,46 +0,0 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
/**
* Useful methods for bundle
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Bundle
{
/**
* Returns path to view / template of given bundle
*
* @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template"
* @param string $bundleName Name of the bundle, e.g. "MyExtraBundle"
* @param string $extension (optional) Extension of the view / template
* @return string|null
*/
public static function getBundleViewPath($viewPath, $bundleName, $extension = 'html.twig')
{
/*
* Unknown path, extension of the view / template or name of the bundle?
* Nothing to do
*/
if (empty($viewPath) || empty($bundleName) || empty($extension)) {
return null;
}
/*
* Path of the view / template doesn't end with given extension?
*/
if (!Regex::endsWith($viewPath, $extension)) {
$viewPath = sprintf('%s.%s', $viewPath, $extension);
}
return sprintf('%s:%s', $bundleName, $viewPath);
}
}

View File

@@ -1,109 +0,0 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
/**
* Useful methods for repository
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class Repository
{
/**
* Replenishes positions of given items
*
* @param array $items The items
* @param bool $asLast (optional) If is set to true, items are placed at the end. Otherwise - at the top.
* @param bool $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.
*/
public static function replenishPositions($items, $asLast = true, $force = false)
{
$position = self::getExtremePosition($items, $asLast);
if ($position === null && $force) {
$position = 0;
}
if ($position !== null && !empty($items)) {
foreach ($items as $item) {
if (method_exists($item, 'getPosition')) {
if ($item->getPosition() === null) {
if ($asLast) {
++$position;
} else {
--$position;
}
if (method_exists($item, 'setPosition')) {
$item->setPosition($position);
}
}
}
}
}
}
/**
* Returns extreme position (max or min) of given items
*
* @param array $items The items
* @param bool $max (optional) If is set to true, maximum value is returned. Otherwise - minimum.
* @return int
*/
public static function getExtremePosition($items, $max = true)
{
$extreme = null;
if (!empty($items)) {
foreach ($items as $item) {
if (Reflection::hasMethod($item, 'getPosition')) {
$position = $item->getPosition();
if ($max) {
if ($position > $extreme) {
$extreme = $position;
}
} else {
if ($position < $extreme) {
$extreme = $position;
}
}
}
}
}
return $extreme;
}
/**
* Returns query builder for given entity's repository.
* The entity should contain given property, e.g. "name".
*
* @param EntityRepository $repository Repository of the entity
* @param string $property (optional) Name of property used by the ORDER BY clause
* @param string $direction (optional) Direction used by the ORDER BY clause ("ASC" or "DESC")
* @return QueryBuilder
*/
public static function getEntityOrderedQueryBuilder(
EntityRepository $repository,
$property = 'name',
$direction = 'ASC'
) {
$alias = 'qb';
return $repository
->createQueryBuilder($alias)
->orderBy(sprintf('%s.%s', $alias, $property), $direction);
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Base;
use Meritoo\Common\Traits\Test\Base\BaseTestCaseTrait;
use PHPUnit\Framework\TestCase;
/**
* Base test case with common methods and data providers
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
abstract class BaseTestCase extends TestCase
{
use BaseTestCaseTrait;
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Base;
use Meritoo\Common\Traits\Test\Base\BaseTypeTestCaseTrait;
/**
* Base test case for the type of something
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
abstract class BaseTypeTestCase extends BaseTestCase
{
use BaseTypeTestCaseTrait;
}

View File

@@ -0,0 +1,110 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Traits\CssSelector;
/**
* Useful methods related to CSS selectors of form
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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);
}
}

View File

@@ -6,24 +6,32 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
namespace Meritoo\Common\Test\Base; namespace Meritoo\Common\Traits\Test\Base;
use DateTime; use DateTime;
use Generator; use Generator;
use Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException; use Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException;
use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Common\Type\OopVisibilityType;
use PHPUnit_Framework_TestCase; use Meritoo\Common\Utilities\Miscellaneous;
use ReflectionClass; use ReflectionClass;
use ReflectionMethod; use ReflectionMethod;
use stdClass;
/** /**
* Base test case with common methods and data providers * Trait for the base test case
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
abstract class BaseTestCase extends PHPUnit_Framework_TestCase trait BaseTestCaseTrait
{ {
/**
* Path of directory with data used by test cases
*
* @var string
*/
private static $testsDataDirPath = 'data/tests';
/** /**
* Provides an empty value * Provides an empty value
* *
@@ -39,6 +47,20 @@ abstract class BaseTestCase extends PHPUnit_Framework_TestCase
yield[[]]; yield[[]];
} }
/**
* Provides an empty scalar value
*
* @return Generator
*/
public function provideEmptyScalarValue()
{
yield[''];
yield[' '];
yield[null];
yield[0];
yield[false];
}
/** /**
* Provides boolean value * Provides boolean value
* *
@@ -95,6 +117,26 @@ abstract class BaseTestCase extends PHPUnit_Framework_TestCase
yield['surprise/me/one/more/time.txt']; 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. * 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.
@@ -103,13 +145,18 @@ abstract class BaseTestCase extends PHPUnit_Framework_TestCase
* @param string $directoryPath (optional) Path of directory containing the file * @param string $directoryPath (optional) Path of directory containing the file
* @return string * @return string
*/ */
public function getFilePathToTests($fileName, $directoryPath = '') public function getFilePathForTesting($fileName, $directoryPath = '')
{ {
if (!empty($directoryPath)) { $rootPath = Miscellaneous::getProjectRootPath();
$directoryPath = '/' . $directoryPath;
}
return sprintf('%s/../../../../../data/tests/%s%s', __DIR__, $fileName, $directoryPath); $paths = [
$rootPath,
self::$testsDataDirPath,
$directoryPath,
$fileName,
];
return Miscellaneous::concatenatePaths($paths);
} }
/** /**
@@ -129,7 +176,7 @@ abstract class BaseTestCase extends PHPUnit_Framework_TestCase
* - string - name of the method * - string - name of the method
* - instance of ReflectionMethod - just the method (provided by ReflectionClass::getMethod() method) * - instance of ReflectionMethod - just the method (provided by ReflectionClass::getMethod() method)
*/ */
protected function verifyMethodVisibilityAndArguments( protected static function assertMethodVisibilityAndArguments(
$classNamespace, $classNamespace,
$method, $method,
$visibilityType, $visibilityType,
@@ -174,15 +221,14 @@ abstract class BaseTestCase extends PHPUnit_Framework_TestCase
/** /**
* Verifies visibility and arguments of class constructor * Verifies visibility and arguments of class constructor
* *
* @param string $classNamespace Namespace of class that contains method to verify * @param string $classNamespace Namespace of class that contains constructor to verify
* @param string $visibilityType Expected visibility of verified method. One of OopVisibilityType class * @param string $visibilityType Expected visibility of verified method. One of OopVisibilityType class
* constants. * constants.
* @param int $argumentsCount (optional) Expected count/amount of arguments of the verified method * @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 * @param int $requiredArgumentsCount (optional) Expected count/amount of required arguments of the verified
* method * method
* @throws UnknownOopVisibilityTypeException
*/ */
protected function verifyConstructorVisibilityAndArguments( protected static function assertConstructorVisibilityAndArguments(
$classNamespace, $classNamespace,
$visibilityType, $visibilityType,
$argumentsCount = 0, $argumentsCount = 0,
@@ -194,6 +240,38 @@ abstract class BaseTestCase extends PHPUnit_Framework_TestCase
$reflection = new ReflectionClass($classNamespace); $reflection = new ReflectionClass($classNamespace);
$method = $reflection->getConstructor(); $method = $reflection->getConstructor();
return $this->verifyMethodVisibilityAndArguments($classNamespace, $method, $visibilityType, $argumentsCount, $requiredArgumentsCount); static::assertMethodVisibilityAndArguments(
$classNamespace,
$method,
$visibilityType,
$argumentsCount,
$requiredArgumentsCount
);
}
/**
* Asserts that class with given namespace has no constructor
*
* @param string $classNamespace Namespace of class that contains constructor to verify
*/
protected static function assertHasNoConstructor($classNamespace)
{
/*
* Let's grab the constructor
*/
$reflection = new ReflectionClass($classNamespace);
$constructor = $reflection->getConstructor();
static::assertNull($constructor);
}
/**
* Sets path of directory with data used by test cases
*
* @param string $testsDataDirPath Path of directory with data used by test cases
*/
protected static function setTestsDataDirPath($testsDataDirPath)
{
static::$testsDataDirPath = $testsDataDirPath;
} }
} }

View File

@@ -1,17 +1,23 @@
<?php <?php
namespace Meritoo\Common\Test\Base; /**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Traits\Test\Base;
use Generator; use Generator;
use Meritoo\Common\Type\Base\BaseType; use Meritoo\Common\Type\Base\BaseType;
/** /**
* Base test case for the type of something * Trait for the base test case for the type of something
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
abstract class BaseTypeTestCase extends BaseTestCase trait BaseTypeTestCaseTrait
{ {
/** /**
* Verifies availability of all types * Verifies availability of all types

View File

@@ -14,8 +14,8 @@ use Meritoo\Common\Utilities\Reflection;
* Base / abstract type of something, e.g. type of button, order, date etc. * Base / abstract type of something, e.g. type of button, order, date etc.
* Child class should contain constants - each of them represent one type. * Child class should contain constants - each of them represent one type.
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
abstract class BaseType abstract class BaseType
{ {
@@ -33,7 +33,7 @@ abstract class BaseType
*/ */
public function getAll() public function getAll()
{ {
if ($this->all === null) { if (null === $this->all) {
$this->all = Reflection::getConstants($this); $this->all = Reflection::getConstants($this);
} }
@@ -43,7 +43,7 @@ abstract class BaseType
/** /**
* Returns information if given type is correct * Returns information if given type is correct
* *
* @param string $type The type to check * @param mixed $type The type to check
* @return bool * @return bool
*/ */
public function isCorrectType($type) public function isCorrectType($type)

View File

@@ -13,8 +13,8 @@ use Meritoo\Common\Type\Base\BaseType;
/** /**
* Type of date part, e.g. "year" * Type of date part, e.g. "year"
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class DatePartType extends BaseType class DatePartType extends BaseType
{ {

View File

@@ -6,18 +6,20 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
namespace Meritoo\Common\Utilities; namespace Meritoo\Common\Type;
use DateTime; use DateTime;
use Meritoo\Common\Type\Base\BaseType;
use Meritoo\Common\Utilities\Date;
/** /**
* A date's period. * A date's period.
* Contains start and end date of the period. * Contains start and end date of the period.
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class DatePeriod class DatePeriod extends BaseType
{ {
/** /**
* The period constant: last month * The period constant: last month
@@ -108,17 +110,6 @@ class DatePeriod
$this->endDate = $endDate; $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 * Returns formatted one of the period's date: start date or end date
* *
@@ -140,7 +131,7 @@ class DatePeriod
/* /*
* Unknown date or format is invalid? * Unknown date or format is invalid?
*/ */
if ($date === null || !Date::isValidDateFormat($format)) { if (null === $date || !Date::isValidDateFormat($format)) {
return ''; return '';
} }

View File

@@ -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 * The visibility of a property, a method or (as of PHP 7.1.0) a constant
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
* *
* @see http://php.net/manual/en/language.oop5.visibility.php * @see http://php.net/manual/en/language.oop5.visibility.php
*/ */

View File

@@ -11,8 +11,8 @@ namespace Meritoo\Common\Utilities;
/** /**
* Useful arrays methods * Useful arrays methods
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Arrays class Arrays
{ {
@@ -48,23 +48,6 @@ class Arrays
if (is_array($value)) { if (is_array($value)) {
$effect .= self::values2string($value, $arrayColumnKey, $separator); $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 { } else {
if (empty($arrayColumnKey)) { if (empty($arrayColumnKey)) {
$effect .= $value; $effect .= $value;
@@ -415,7 +398,7 @@ class Arrays
* var autoGeneratedVariable = new Array(...);autoGeneratedVariable[0] = new Array(...); * var autoGeneratedVariable = new Array(...);autoGeneratedVariable[0] = new Array(...);
* autoGeneratedVariable[1] = new Array(...); * autoGeneratedVariable[1] = new Array(...);
*/ */
if ($counter === 1) { if (1 === $counter) {
$effect .= "\n"; $effect .= "\n";
} }
@@ -530,6 +513,10 @@ class Arrays
*/ */
public static function removeElement(array $array, $item) 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)) { if (empty($array) || !in_array($item, $array)) {
return false; return false;
} }
@@ -626,6 +613,10 @@ class Arrays
*/ */
public static function setKeysAsValues(array $array, $ignoreDuplicatedValues = true) public static function setKeysAsValues(array $array, $ignoreDuplicatedValues = true)
{ {
/*
* No elements?
* Nothing to do
*/
if (empty($array)) { if (empty($array)) {
return []; return [];
} }
@@ -682,7 +673,7 @@ class Arrays
return null; return null;
} }
$effect = $array; $effect = &$array;
ksort($effect, $sortFlags); ksort($effect, $sortFlags);
foreach ($effect as &$value) { foreach ($effect as &$value) {
@@ -758,7 +749,7 @@ class Arrays
foreach ($exploded as $item) { foreach ($exploded as $item) {
$exploded2 = explode($valuesKeysSeparator, $item); $exploded2 = explode($valuesKeysSeparator, $item);
if (count($exploded2) == 2) { if (2 == count($exploded2)) {
$key = trim($exploded2[0]); $key = trim($exploded2[0]);
$value = trim($exploded2[1]); $value = trim($exploded2[1]);
@@ -831,60 +822,66 @@ class Arrays
*/ */
public static function getLastElementsPaths(array $array, $separator = '.', $parentPath = '', $stopIfMatchedBy = '') 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 = []; $paths = [];
if (!empty($array)) { foreach ($array as $key => $value) {
if (!empty($stopIfMatchedBy)) { $path = $key;
$stopIfMatchedBy = self::makeArray($stopIfMatchedBy); $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; * Check if the key or current path matches one of patterns at which the process should be stopped,
$stopRecursion = false; * 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)) {
* If the path of parent element is delivered, $stopRecursion = true;
* I have to use it and build longer path break;
*/
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;
}
} }
} }
}
/* /*
* The value is passed to the returned array if: * The value is passed to the returned array if:
* - it's not an array * - it's not an array
* or * or
* - the process is stopped, recursive is not used * - the process is stopped, recursive is not used
*/ */
if (!is_array($value) || (is_array($value) && empty($value)) || $stopRecursion) { if (!is_array($value) || (is_array($value) && empty($value)) || $stopRecursion) {
$paths[$path] = $value; $paths[$path] = $value;
continue; continue;
} }
/* /*
* Let's iterate through the next level, using recursive * Let's iterate through the next level, using recursive
*/ */
if (is_array($value)) { if (is_array($value)) {
$recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy); $recursivePaths = self::getLastElementsPaths($value, $separator, $path, $stopIfMatchedBy);
$paths += $recursivePaths; $paths += $recursivePaths;
}
} }
} }
@@ -1083,6 +1080,10 @@ class Arrays
*/ */
public static function getAllValuesOfKey(array $array, $key) public static function getAllValuesOfKey(array $array, $key)
{ {
/*
* No elements?
* Nothing to do
*/
if (empty($array)) { if (empty($array)) {
return null; return null;
} }
@@ -1124,7 +1125,7 @@ class Arrays
if (!empty($array)) { if (!empty($array)) {
$childPosition = 1; $childPosition = 1;
if ($startPosition !== null) { if (null !== $startPosition) {
$array[$keyName] = $startPosition; $array[$keyName] = $startPosition;
} }
@@ -1316,7 +1317,7 @@ class Arrays
* *
* If one of the above is true, not all elements of given array are empty * If one of the above is true, not all elements of given array are empty
*/ */
if ((!is_array($element) && $strictNull && $element !== null) || !empty($element)) { if ((!is_array($element) && $strictNull && null !== $element) || !empty($element)) {
return false; return false;
} }
} }
@@ -1353,7 +1354,7 @@ class Arrays
* Values should be compared only and both arrays are one-dimensional? * Values should be compared only and both arrays are one-dimensional?
* Let's find difference by using simple function * Let's find difference by using simple function
*/ */
if ($valuesOnly && self::getDimensionsCount($array1) == 1 && self::getDimensionsCount($array2) == 1) { if ($valuesOnly && 1 == self::getDimensionsCount($array1) && 1 == self::getDimensionsCount($array2)) {
return array_diff($array1, $array2); return array_diff($array1, $array2);
} }
@@ -1381,7 +1382,7 @@ class Arrays
} }
} }
if ($difference !== null) { if (null !== $difference) {
$effect[] = $difference; $effect[] = $difference;
} }
} else { } else {
@@ -1472,7 +1473,7 @@ class Arrays
* Start index not provided? * Start index not provided?
* Let's look for the first index / key of given array * Let's look for the first index / key of given array
*/ */
if ($startIndex === null) { if (null === $startIndex) {
$startIndex = self::getFirstKey($array); $startIndex = self::getFirstKey($array);
} }
@@ -1617,7 +1618,7 @@ class Arrays
* Index of element or of element's key is unknown? * Index of element or of element's key is unknown?
* Probably the element does not exist in given array, so... nothing to do * Probably the element does not exist in given array, so... nothing to do
*/ */
if ($elementKey === null || $indexOfKey === null) { if (null === $elementKey || null === $indexOfKey) {
return null; return null;
} }

View File

@@ -0,0 +1,85 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
/**
* Useful methods related to CSS selectors and the Bootstrap4 (front-end component library)
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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);
}
}

89
src/Utilities/Bundle.php Normal file
View File

@@ -0,0 +1,89 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Meritoo\Common\Exception\Bundle\IncorrectBundleNameException;
/**
* Useful methods for bundle
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class Bundle
{
/**
* Returns path of given bundle to view / template with given extension
*
* @param string $viewPath Path of the view / template, e.g. "MyDirectory/my-template"
* @param string $bundleName Full name of the bundle, e.g. "MyExtraBundle"
* @param string $extension (optional) Extension of the view / template (default: "html.twig")
* @throws IncorrectBundleNameException
* @return string|null
*/
public static function getBundleViewPath($viewPath, $bundleName, $extension = 'html.twig')
{
/*
* Unknown path, extension of the view / template or name of the bundle?
* Nothing to do
*/
if (empty($viewPath) || empty($bundleName) || empty($extension)) {
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?
*/
if (!Regex::endsWith($viewPath, $extension)) {
$viewPath = sprintf('%s.%s', $viewPath, $extension);
}
/*
* 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];
}
}

View File

@@ -13,8 +13,8 @@ use stdClass;
/** /**
* Useful Composer-related methods (only static functions) * Useful Composer-related methods (only static functions)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Composer class Composer
{ {
@@ -59,7 +59,7 @@ class Composer
* Unknown data from the composer.json file or there is no node with given name? * Unknown data from the composer.json file or there is no node with given name?
* Nothing to do * Nothing to do
*/ */
if ($data === null || !isset($data->{$nodeName})) { if (null === $data || !isset($data->{$nodeName})) {
return null; return null;
} }

View File

@@ -0,0 +1,22 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Meritoo\Common\Traits\CssSelector\FormCssSelector;
/**
* Useful methods related to CSS selectors
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class CssSelector
{
use FormCssSelector;
}

View File

@@ -10,14 +10,16 @@ namespace Meritoo\Common\Utilities;
use DateInterval; use DateInterval;
use DateTime; 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\DatePartType;
use Meritoo\Common\Type\DatePeriod;
/** /**
* Useful date methods * Useful date methods
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Date class Date
{ {
@@ -62,101 +64,113 @@ class Date
const DATE_DIFFERENCE_UNIT_YEARS = 'years'; const DATE_DIFFERENCE_UNIT_YEARS = 'years';
/** /**
* Returns start and end date for given period. * Returns date's period (that contains start and end date) for given period
* 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. * @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) public static function getDatesForPeriod($period)
{ {
$datePeriod = null; /*
* Type of period is incorrect?
if (DatePeriod::isCorrectPeriod($period)) { * Nothing to do
$dateStart = null; */
$dateEnd = null; if (!(new DatePeriod())->isCorrectType($period)) {
return 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 ($period == DatePeriod::LAST_YEAR || $period == DatePeriod::NEXT_YEAR) {
$yearDifference = 1;
if ($period == DatePeriod::LAST_YEAR) {
$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 ($dateStart !== null && $dateEnd !== null) {
$dateStart->setTime(0, 0, 0);
$dateEnd->setTime(23, 59, 59);
$datePeriod = new DatePeriod($dateStart, $dateEnd);
}
} }
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 +244,8 @@ class Date
* @param int $month The month value * @param int $month The month value
* @param int $day The day value * @param int $day The day value
* *
* @return int
* @throws UnknownDatePartTypeException * @throws UnknownDatePartTypeException
* @return int
*/ */
public static function getDayOfWeek($year, $month, $day) public static function getDayOfWeek($year, $month, $day)
{ {
@@ -243,21 +257,21 @@ class Date
* Oops, incorrect year * Oops, incorrect year
*/ */
if ($year <= 0) { if ($year <= 0) {
throw new UnknownDatePartTypeException(DatePartType::YEAR, $year); throw UnknownDatePartTypeException::createException(DatePartType::YEAR, $year);
} }
/* /*
* Oops, incorrect month * Oops, incorrect month
*/ */
if ($month < 1 || $month > 12) { if ($month < 1 || $month > 12) {
throw new UnknownDatePartTypeException(DatePartType::MONTH, $month); throw UnknownDatePartTypeException::createException(DatePartType::MONTH, $month);
} }
/* /*
* Oops, incorrect day * Oops, incorrect day
*/ */
if ($day < 1 || $day > 31) { if ($day < 1 || $day > 31) {
throw new UnknownDatePartTypeException(DatePartType::DAY, $day); throw UnknownDatePartTypeException::createException(DatePartType::DAY, $day);
} }
if ($month < 3) { if ($month < 3) {
@@ -311,7 +325,7 @@ class Date
$encoding = mb_detect_encoding($name); $encoding = mb_detect_encoding($name);
if ($encoding === false) { if (false === $encoding) {
$name = mb_convert_encoding($name, 'UTF-8', 'ISO-8859-2'); $name = mb_convert_encoding($name, 'UTF-8', 'ISO-8859-2');
} }
@@ -356,11 +370,11 @@ class Date
return null; return null;
} }
$dateStart = self::getDateTime($dateStart, true); $start = self::getDateTime($dateStart, true);
$dateEnd = self::getDateTime($dateEnd, true); $end = self::getDateTime($dateEnd, true);
$difference = []; $difference = [];
$dateDiff = $dateEnd->getTimestamp() - $dateStart->getTimestamp(); $dateDiff = $end->getTimestamp() - $start->getTimestamp();
$daysInSeconds = 0; $daysInSeconds = 0;
$hoursInSeconds = 0; $hoursInSeconds = 0;
@@ -378,46 +392,46 @@ class Date
self::DATE_DIFFERENCE_UNIT_MINUTES, self::DATE_DIFFERENCE_UNIT_MINUTES,
]; ];
if ($differenceUnit === null || $differenceUnit == self::DATE_DIFFERENCE_UNIT_YEARS) { if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) {
$diff = $dateEnd->diff($dateStart); $diff = $end->diff($start);
/* /*
* Difference between dates in years should be returned only? * Difference between dates in years should be returned only?
*/ */
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_YEARS) { if (self::DATE_DIFFERENCE_UNIT_YEARS === $differenceUnit) {
return $diff->y; return $diff->y;
} }
$difference[self::DATE_DIFFERENCE_UNIT_YEARS] = $diff->y; $difference[self::DATE_DIFFERENCE_UNIT_YEARS] = $diff->y;
} }
if ($differenceUnit === null || $differenceUnit == self::DATE_DIFFERENCE_UNIT_MONTHS) { if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) {
$diff = $dateEnd->diff($dateStart); $diff = $end->diff($start);
/* /*
* Difference between dates in months should be returned only? * Difference between dates in months should be returned only?
*/ */
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_MONTHS) { if (self::DATE_DIFFERENCE_UNIT_MONTHS === $differenceUnit) {
return $diff->m; return $diff->m;
} }
$difference[self::DATE_DIFFERENCE_UNIT_MONTHS] = $diff->m; $difference[self::DATE_DIFFERENCE_UNIT_MONTHS] = $diff->m;
} }
if ($differenceUnit === null || in_array($differenceUnit, $relatedUnits)) { if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) {
$days = (int)floor($dateDiff / $daySeconds); $days = (int)floor($dateDiff / $daySeconds);
/* /*
* Difference between dates in days should be returned only? * Difference between dates in days should be returned only?
*/ */
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_DAYS) { if (self::DATE_DIFFERENCE_UNIT_DAYS === $differenceUnit) {
return $days; return $days;
} }
/* /*
* All units should be returned? * All units should be returned?
*/ */
if ($differenceUnit === null) { if (null === $differenceUnit) {
$difference[self::DATE_DIFFERENCE_UNIT_DAYS] = $days; $difference[self::DATE_DIFFERENCE_UNIT_DAYS] = $days;
} }
@@ -427,20 +441,20 @@ class Date
$daysInSeconds = $days * $daySeconds; $daysInSeconds = $days * $daySeconds;
} }
if ($differenceUnit === null || in_array($differenceUnit, $relatedUnits)) { if (null === $differenceUnit || in_array($differenceUnit, $relatedUnits, true)) {
$hours = (int)floor(($dateDiff - $daysInSeconds) / $hourSeconds); $hours = (int)floor(($dateDiff - $daysInSeconds) / $hourSeconds);
/* /*
* Difference between dates in hours should be returned only? * Difference between dates in hours should be returned only?
*/ */
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_HOURS) { if (self::DATE_DIFFERENCE_UNIT_HOURS === $differenceUnit) {
return $hours; return $hours;
} }
/* /*
* All units should be returned? * All units should be returned?
*/ */
if ($differenceUnit === null) { if (null === $differenceUnit) {
$difference[self::DATE_DIFFERENCE_UNIT_HOURS] = $hours; $difference[self::DATE_DIFFERENCE_UNIT_HOURS] = $hours;
} }
@@ -450,13 +464,13 @@ class Date
$hoursInSeconds = $hours * $hourSeconds; $hoursInSeconds = $hours * $hourSeconds;
} }
if ($differenceUnit === null || $differenceUnit == self::DATE_DIFFERENCE_UNIT_MINUTES) { if (null === $differenceUnit || self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) {
$minutes = (int)floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60); $minutes = (int)floor(($dateDiff - $daysInSeconds - $hoursInSeconds) / 60);
/* /*
* Difference between dates in minutes should be returned only? * Difference between dates in minutes should be returned only?
*/ */
if ($differenceUnit == self::DATE_DIFFERENCE_UNIT_MINUTES) { if (self::DATE_DIFFERENCE_UNIT_MINUTES === $differenceUnit) {
return $minutes; return $minutes;
} }
@@ -475,6 +489,7 @@ class Date
* @param string $intervalTemplate (optional) Template used to build date interval. It should contain "%d" as the * @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. * placeholder which is replaced with a number that represents each iteration.
* Default: interval for days. * Default: interval for days.
* @throws Exception
* @return array * @return array
*/ */
public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD') public static function getDatesCollection(DateTime $startDate, $datesCount, $intervalTemplate = 'P%dD')
@@ -515,16 +530,21 @@ class Date
/** /**
* Returns random date based on given start date * Returns random date based on given start date
* *
* @param DateTime $startDate The start date. Start of the random date. * @param DateTime $startDate (optional) Beginning of the random date. If not provided, current date will
* @param int $start (optional) Start of random partition * be used (default behaviour).
* @param int $end (optional) End of random partition * @param int $start (optional) Start of random partition. If not provided, 1 will be used
* (default behaviour).
* @param int $end (optional) End of random partition. If not provided, 100 will be used
* (default behaviour).
* @param string $intervalTemplate (optional) Template used to build date interval. The placeholder is replaced * @param string $intervalTemplate (optional) Template used to build date interval. The placeholder is replaced
* with next, iterated value. * with next, iterated value. If not provided, "P%sD" will be used (default
* behaviour).
* @throws Exception
* @return DateTime * @return DateTime
*/ */
public static function getRandomDate(DateTime $startDate = null, $start = 1, $end = 100, $intervalTemplate = 'P%sD') public static function getRandomDate(DateTime $startDate = null, $start = 1, $end = 100, $intervalTemplate = 'P%sD')
{ {
if ($startDate === null) { if (null === $startDate) {
$startDate = new DateTime(); $startDate = new DateTime();
} }
@@ -540,7 +560,7 @@ class Date
} }
$randomDate = clone $startDate; $randomDate = clone $startDate;
$randomInterval = new DateInterval(sprintf($intervalTemplate, rand($start, $end))); $randomInterval = new DateInterval(sprintf($intervalTemplate, mt_rand($start, $end)));
return $randomDate->add($randomInterval); return $randomDate->add($randomInterval);
} }
@@ -552,10 +572,11 @@ class Date
* @param mixed $value The value which maybe is a date * @param mixed $value The value which maybe is a date
* @param bool $allowCompoundFormats (optional) If is set to true, the compound formats used to create an * @param bool $allowCompoundFormats (optional) If is set to true, the compound formats used to create an
* instance of DateTime class are allowed (e.g. "now", "last day of next * instance of DateTime class are allowed (e.g. "now", "last day of next
* month", "yyyy"). Otherwise - not and every incorrect value is refused. * month", "yyyy"). Otherwise - not and every incorrect value is refused
* (default behaviour).
* @param string $dateFormat (optional) Format of date used to verify if given value is actually a date. * @param string $dateFormat (optional) Format of date used to verify if given value is actually a date.
* It should be format matched to the given value, e.g. "Y-m-d H:i" for * It should be format matched to the given value, e.g. "Y-m-d H:i" for
* "2015-01-01 10:00" value. * "2015-01-01 10:00" value. Default: "Y-m-d".
* @return DateTime|bool * @return DateTime|bool
*/ */
public static function getDateTime($value, $allowCompoundFormats = false, $dateFormat = 'Y-m-d') public static function getDateTime($value, $allowCompoundFormats = false, $dateFormat = 'Y-m-d')
@@ -590,7 +611,7 @@ class Date
*/ */
$dateFromFormat = DateTime::createFromFormat($dateFormat, $value); $dateFromFormat = DateTime::createFromFormat($dateFormat, $value);
if ($dateFromFormat === false) { if (false === $dateFromFormat) {
/* /*
* Nothing to do more, because: * Nothing to do more, because:
* a) instance of the DateTime was created * a) instance of the DateTime was created
@@ -623,7 +644,7 @@ class Date
* So, I have to refuse those special compound formats if they are not explicitly declared as * 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) * compound (2nd argument of this method, set to false by default)
*/ */
if (in_array($value, $specialFormats)) { if (in_array($value, $specialFormats, true)) {
return false; return false;
} }
} }
@@ -648,7 +669,7 @@ class Date
*/ */
$dateString = (new DateTime())->format($value); $dateString = (new DateTime())->format($value);
if ($dateString != $value) { if ($dateString !== (string)$value) {
return new DateTime($dateString); return new DateTime($dateString);
} }
} catch (\Exception $exception) { } catch (\Exception $exception) {
@@ -692,7 +713,7 @@ class Date
* Formatted date it's the format who is validated? * Formatted date it's the format who is validated?
* The format is invalid * The format is invalid
*/ */
if ($formatted == $format) { if ($formatted === $format) {
return false; return false;
} }

View File

@@ -13,8 +13,8 @@ use Generator;
/** /**
* Useful methods for the Generator class (only static functions) * Useful methods for the Generator class (only static functions)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class GeneratorUtility class GeneratorUtility
{ {

View File

@@ -11,8 +11,8 @@ namespace Meritoo\Common\Utilities;
/** /**
* Useful locale methods * Useful locale methods
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Locale class Locale
{ {
@@ -23,7 +23,7 @@ class Locale
* setting. It's the same constant as required by setlocale() function. * 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 $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" * @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): * Available categories (values of $category argument):
* - LC_ALL for all of the below * - LC_ALL for all of the below
@@ -57,9 +57,29 @@ class Locale
} }
$localeLongForm = self::getLongForm($languageCode, $countryCode); $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');
} }
/** /**

View File

@@ -11,8 +11,8 @@ namespace Meritoo\Common\Utilities;
/** /**
* Useful methods for mime types of files * Useful methods for mime types of files
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class MimeTypes class MimeTypes
{ {
@@ -759,9 +759,8 @@ class MimeTypes
* Returns mime type of given file * Returns mime type of given file
* *
* @param string $filePath Path of the file to check * @param string $filePath Path of the file to check
* @return string
*
* @throws \RuntimeException * @throws \RuntimeException
* @return string
*/ */
public static function getMimeType($filePath) public static function getMimeType($filePath)
{ {

View File

@@ -9,14 +9,13 @@
namespace Meritoo\Common\Utilities; namespace Meritoo\Common\Utilities;
use Gedmo\Sluggable\Util\Urlizer; use Gedmo\Sluggable\Util\Urlizer;
use Symfony\Component\HttpFoundation\Cookie;
use Transliterator; use Transliterator;
/** /**
* Miscellaneous methods (only static functions) * Miscellaneous methods (only static functions)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Miscellaneous class Miscellaneous
{ {
@@ -61,15 +60,15 @@ class Miscellaneous
$startFileName = mb_substr($startFileName, 1); $startFileName = mb_substr($startFileName, 1);
} }
$directoryContent = scandir($directoryPath); $directoryContent = scandir($directoryPath, SCANDIR_SORT_ASCENDING);
if (!empty($directoryContent)) { if (!empty($directoryContent)) {
foreach ($directoryContent as $fileName) { foreach ($directoryContent as $fileName) {
if ($fileName != '.' && $fileName != '..') { if ('.' !== $fileName && '..' !== $fileName) {
$content = null; $content = null;
if (!empty($startFileName) && !$startFileFound) { if (!empty($startFileName) && !$startFileFound) {
if ($fileName == $startFileName) { if ($fileName === $startFileName) {
$startFileFound = true; $startFileFound = true;
} }
@@ -80,21 +79,21 @@ class Miscellaneous
$content = self::getDirectoryContent($directoryPath . $fileName, true, $maxFilesCount - $count); $content = self::getDirectoryContent($directoryPath . $fileName, true, $maxFilesCount - $count);
} }
if ($content !== null) { if (null !== $content) {
$files[$fileName] = $content; $files[$fileName] = $content;
if (!empty($maxFilesCount)) { if (null !== $maxFilesCount) {
$count += Arrays::getNonArrayElementsCount($content); $count += Arrays::getNonArrayElementsCount($content);
} }
} else { } else {
$files[] = $fileName; $files[] = $fileName;
if (!empty($maxFilesCount)) { if (null !== $maxFilesCount) {
++$count; ++$count;
} }
} }
if (!empty($maxFilesCount) && $count >= $maxFilesCount) { if (null !== $maxFilesCount && $count >= $maxFilesCount) {
break; break;
} }
} }
@@ -159,11 +158,17 @@ class Miscellaneous
*/ */
public static function includeFileExtension($fileName, $extension) public static function includeFileExtension($fileName, $extension)
{ {
if (self::getFileExtension($fileName, true) != strtolower($extension)) { $fileExtension = self::getFileExtension($fileName, true);
return sprintf('%s.%s', $fileName, $extension);
/*
* 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 * Let's clear name of file
* *
* Attention. The name without extension may be cleared / urlized only * Attention.
* to avoid incorrect name by replacing "." with "-". * The name without extension may be cleared / urlized only to avoid incorrect name by replacing "." with "-".
*/ */
$withoutExtension = Urlizer::urlize($withoutExtension); $withoutExtension = Urlizer::urlize($withoutExtension);
/* /*
* Now I have to complete the template used to build / generate unique name * Now I have to complete the template used to build / generate unique name
*/ */
$template = '%s-%s'; // file's name and unique key $template = '%s-%s.%s'; // [file's name]-[unique key].[file's extension]
if ($objectId > 0) {
$template .= '-%s'; // object ID
}
$template .= '.%s'; // file's extension
/* /*
* Add some uniqueness * Add some uniqueness
*/ */
$unique = uniqid(mt_rand(), true); $unique = self::getUniqueString(mt_rand());
/* /*
* Finally build and return the unique name * Finally build and return the unique name
*/ */
if ($objectId > 0) { 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); return sprintf($template, $withoutExtension, $unique, $objectId, $extension);
} }
@@ -332,7 +334,7 @@ class Miscellaneous
{ {
$phpModulesArray = get_loaded_extensions(); $phpModulesArray = get_loaded_extensions();
return in_array($phpModuleName, $phpModulesArray); return in_array($phpModuleName, $phpModulesArray, false);
} }
/** /**
@@ -365,7 +367,7 @@ class Miscellaneous
* Oops, cannot instantiate converter * Oops, cannot instantiate converter
* Nothing to do * Nothing to do
*/ */
if ($converter === null) { if (null === $converter) {
return ''; return '';
} }
@@ -460,7 +462,7 @@ class Miscellaneous
* Value to find is neither a string nor an array OR it's an empty string? * Value to find is neither a string nor an array OR it's an empty string?
* Nothing to do * Nothing to do
*/ */
if ((!$searchIsString && !$searchIsArray) || ($searchIsString && strlen($search) == 0)) { if ((!$searchIsString && !$searchIsArray) || ($searchIsString && '' === $search)) {
return $effect; return $effect;
} }
@@ -485,7 +487,7 @@ class Miscellaneous
* Second step: replace with regular expressions. * Second step: replace with regular expressions.
* Attention. Searched and replacement value should be the same type: strings or arrays. * 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) { if ($quoteStrings && $replacementIsString) {
$replacement = '\'' . $replacement . '\''; $replacement = '\'' . $replacement . '\'';
} }
@@ -503,7 +505,7 @@ class Miscellaneous
* Third step: complex replace of the replacement defined as an array. * 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. * 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); $subjectIsArray = is_array($subject);
$effect = ''; $effect = '';
@@ -588,7 +590,12 @@ class Miscellaneous
*/ */
public static function getOperatingSystemNameServer() public static function getOperatingSystemNameServer()
{ {
return php_uname('s'); return PHP_OS;
/*
* Previous version:
* return php_uname('s');
*/
} }
/** /**
@@ -612,7 +619,7 @@ class Miscellaneous
$effect = mb_substr($text, 0, $maxLength, 'utf-8'); $effect = mb_substr($text, 0, $maxLength, 'utf-8');
$lastSpacePosition = mb_strrpos($effect, ' ', 'utf-8'); $lastSpacePosition = mb_strrpos($effect, ' ', 'utf-8');
if ($lastSpacePosition !== false) { if (false !== $lastSpacePosition) {
$effect = mb_substr($effect, 0, $lastSpacePosition, 'utf-8'); $effect = mb_substr($effect, 0, $lastSpacePosition, 'utf-8');
} }
@@ -626,10 +633,10 @@ class Miscellaneous
* Breaks long text * Breaks long text
* *
* @param string $text The text to check and break * @param string $text The text to check and break
* @param int $perLine (optional) Characters count per line * @param int $perLine (optional) Characters count per line. Default: 100.
* @param string $separator (optional) Separator that is placed beetwen lines * @param string $separator (optional) Separator that is placed between lines. Default: "<br>".
* @param string $encoding (optional) Character encoding. Used by mb_substr(). * @param string $encoding (optional) Character encoding. Used by mb_substr(). Default: "UTF-8".
* @param int $proportionalAberration (optional) Proportional aberration for chars (percent value) * @param int $proportionalAberration (optional) Proportional aberration for chars (percent value). Default: 20.
* @return string * @return string
*/ */
public static function breakLongText( public static function breakLongText(
@@ -680,7 +687,8 @@ class Miscellaneous
$spacePosition = mb_strrpos($lineWithAberration, ' ', 0, $encoding); $spacePosition = mb_strrpos($lineWithAberration, ' ', 0, $encoding);
if ($spacePosition > 0) { if (false !== $spacePosition && 0 < $spacePosition) {
/* @var int $spacePosition */
$perLine = $spacePosition; $perLine = $spacePosition;
$insertSeparator = true; $insertSeparator = true;
} }
@@ -716,21 +724,29 @@ class Miscellaneous
* *
* @param string $directoryPath Directory path * @param string $directoryPath Directory path
* @param bool $contentOnly (optional) If is set to true, only content of the directory is removed, not * @param bool $contentOnly (optional) If is set to true, only content of the directory is removed, not
* directory. Otherwise - directory is removed too. * directory itself. Otherwise - directory is removed too (default behaviour).
* @return bool * @return bool|null
*/ */
public static function removeDirectory($directoryPath, $contentOnly = false) public static function removeDirectory($directoryPath, $contentOnly = false)
{ {
/*
* Directory does not exist?
* Nothing to do
*/
if (!file_exists($directoryPath)) { if (!file_exists($directoryPath)) {
return true; return null;
} }
/*
* It's not a directory?
* Let's treat it like file
*/
if (!is_dir($directoryPath)) { if (!is_dir($directoryPath)) {
return unlink($directoryPath); return unlink($directoryPath);
} }
foreach (scandir($directoryPath) as $item) { foreach (scandir($directoryPath, SCANDIR_SORT_ASCENDING) as $item) {
if ($item == '.' || $item == '..') { if ('.' === $item || '..' === $item) {
continue; continue;
} }
@@ -739,6 +755,9 @@ class Miscellaneous
} }
} }
/*
* Directory should be removed too?
*/
if (!$contentOnly) { if (!$contentOnly) {
return rmdir($directoryPath); return rmdir($directoryPath);
} }
@@ -776,7 +795,7 @@ class Miscellaneous
foreach ($members as $key => $value) { foreach ($members as $key => $value) {
$value = mb_strtolower($value); $value = mb_strtolower($value);
if ($key == 0) { if (0 === $key) {
$effect .= self::lowercaseFirst($value); $effect .= self::lowercaseFirst($value);
} else { } else {
$effect .= self::uppercaseFirst($value); $effect .= self::uppercaseFirst($value);
@@ -797,10 +816,6 @@ class Miscellaneous
* - null (default): nothing is done with the string * - null (default): nothing is done with the string
* - true: the rest of string is lowercased * - true: the rest of string is lowercased
* - false: the rest of string is uppercased * - 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) public static function lowercaseFirst($text, $restLowercase = null)
{ {
@@ -812,20 +827,11 @@ class Miscellaneous
if ($restLowercase) { if ($restLowercase) {
$effect = mb_strtolower($effect); $effect = mb_strtolower($effect);
} elseif ($restLowercase === false) { } elseif (false === $restLowercase) {
$effect = mb_strtoupper($effect); $effect = mb_strtoupper($effect);
} }
if (function_exists('lcfirst')) { return lcfirst($effect);
$effect = lcfirst($effect);
} else {
$first = mb_strtolower($effect[0]);
$rest = mb_substr($effect, 1);
$effect = $first . $rest;
}
return $effect;
} }
/** /**
@@ -850,20 +856,11 @@ class Miscellaneous
if ($restLowercase) { if ($restLowercase) {
$effect = mb_strtolower($effect); $effect = mb_strtolower($effect);
} elseif ($restLowercase === false) { } elseif (false === $restLowercase) {
$effect = mb_strtoupper($effect); $effect = mb_strtoupper($effect);
} }
if (function_exists('ucfirst')) { return ucfirst($effect);
$effect = ucfirst($effect);
} else {
$first = mb_strtoupper($effect[0]);
$rest = mb_substr($effect, 1);
$effect = $first . $rest;
}
return $effect;
} }
/** /**
@@ -904,9 +901,9 @@ class Miscellaneous
'TB', 'TB',
'PB', '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]; $unit = $units[(int)$index];
return sprintf('%s %s', $size, $unit); return sprintf('%s %s', $size, $unit);
@@ -1032,6 +1029,8 @@ class Miscellaneous
$separator = DIRECTORY_SEPARATOR; $separator = DIRECTORY_SEPARATOR;
foreach ($paths as $path) { foreach ($paths as $path) {
$path = trim($path);
/* /*
* Empty paths are useless * Empty paths are useless
*/ */
@@ -1153,7 +1152,7 @@ class Miscellaneous
{ {
$value = filter_input($globalSourceType, $variableName); $value = filter_input($globalSourceType, $variableName);
if ($value === null) { if (null === $value) {
$globalSource = null; $globalSource = null;
switch ($globalSourceType) { switch ($globalSourceType) {
@@ -1178,150 +1177,14 @@ class Miscellaneous
break; break;
} }
if ($globalSource !== null && isset($globalSource[$variableName])) { if (null !== $globalSource && isset($globalSource[$variableName])) {
$value = $globalSource[$variableName]; $value = $globalSource[$variableName];
if (!ini_get('magic_quotes_gpc')) {
$value = addslashes($value);
}
} }
} }
return $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:
* <code>
* [
* 'headers' => [
* 'Content-Type' => 'text/html; charset=UTF-8',
* ...
* ],
* 'cookies' => [
* new Symfony\Component\HttpFoundation\Cookie(),
* new Symfony\Component\HttpFoundation\Cookie(),
* ...
* ],
* 'content' => '<html>...</html>'
* ]
* </code>
*
* 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 ($i === 0) {
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 ($key === 'Set-Cookie') {
$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 ($j === 0) {
$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 * Adds missing the "0" characters to given number until given length is reached
* *
@@ -1361,7 +1224,7 @@ class Miscellaneous
continue; continue;
} }
$text = $text . '0'; $text .= '0';
} }
return $text; return $text;
@@ -1416,8 +1279,8 @@ class Miscellaneous
if ($asHexadecimal) { if ($asHexadecimal) {
$hexadecimal = dechex($colorComponent); $hexadecimal = dechex($colorComponent);
if (strlen($hexadecimal) == 1) { if (1 === strlen($hexadecimal)) {
return sprintf('0%s', $hexadecimal, $hexadecimal); return sprintf('0%s', $hexadecimal);
} }
return $hexadecimal; return $hexadecimal;
@@ -1444,14 +1307,14 @@ class Miscellaneous
* Verify and get valid value of color. * Verify and get valid value of color.
* An exception will be thrown if the value is not a 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 * Grab color's components
*/ */
$red = hexdec(substr($color, 0, 2)); $red = hexdec(substr($validColor, 0, 2));
$green = hexdec(substr($color, 2, 2)); $green = hexdec(substr($validColor, 2, 2));
$blue = hexdec(substr($color, 4, 2)); $blue = hexdec(substr($validColor, 4, 2));
/* /*
* Calculate inverted color's components * Calculate inverted color's components
@@ -1471,4 +1334,37 @@ class Miscellaneous
return $invertedColor; return $invertedColor;
} }
/**
* Returns project's root path.
* Looks for directory that contains composer.json.
*
* @return string
*/
public static function getProjectRootPath()
{
$projectRootPath = '';
$fileName = 'composer.json';
$directoryPath = __DIR__;
/*
* Path of directory it's not the path of last directory?
*/
while (DIRECTORY_SEPARATOR !== $directoryPath) {
$filePath = static::concatenatePaths($directoryPath, $fileName);
/*
* Is here file we are looking for?
* Maybe it's a project's root path
*/
if (file_exists($filePath)) {
$projectRootPath = $directoryPath;
}
$directoryPath = dirname($directoryPath);
}
return $projectRootPath;
}
} }

View File

@@ -10,6 +10,7 @@ namespace Meritoo\Common\Utilities;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\Query\Parameter; use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
@@ -17,8 +18,8 @@ use Doctrine\ORM\QueryBuilder;
/** /**
* Useful methods for query builder (the Doctrine's QueryBuilder class) * Useful methods for query builder (the Doctrine's QueryBuilder class)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class QueryBuilderUtility class QueryBuilderUtility
{ {
@@ -33,6 +34,10 @@ class QueryBuilderUtility
{ {
$aliases = $queryBuilder->getRootAliases(); $aliases = $queryBuilder->getRootAliases();
/*
* No aliases?
* Nothing to do
*/
if (empty($aliases)) { if (empty($aliases)) {
return null; return null;
} }
@@ -42,7 +47,8 @@ class QueryBuilderUtility
/** /**
* Returns alias of given property joined in given query builder * 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. * It's also information if given property is already joined in given query builder.
* *
* @param QueryBuilder $queryBuilder The query builder to verify * @param QueryBuilder $queryBuilder The query builder to verify
@@ -53,6 +59,10 @@ class QueryBuilderUtility
{ {
$joins = $queryBuilder->getDQLPart('join'); $joins = $queryBuilder->getDQLPart('join');
/*
* No joins?
* Nothing to do
*/
if (empty($joins)) { if (empty($joins)) {
return null; return null;
} }
@@ -99,33 +109,43 @@ class QueryBuilderUtility
*/ */
public static function setCriteria(QueryBuilder $queryBuilder, array $criteria = [], $alias = '') public static function setCriteria(QueryBuilder $queryBuilder, array $criteria = [], $alias = '')
{ {
if (!empty($criteria)) { /*
if (empty($alias)) { * No criteria used in WHERE clause?
$alias = self::getRootAlias($queryBuilder); * 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)) { foreach ($criteria as $column => $value) {
if (count($value) == 2) { $compareOperator = '=';
$compareOperator = $value[1];
}
$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); $value = $value[0];
if ($value === null) {
$predicate = $queryBuilder->expr()->isNull(sprintf('%s.%s', $alias, $column));
unset($criteria[$column]);
} else {
$queryBuilder->setParameter($column, $value);
}
$queryBuilder = $queryBuilder->andWhere($predicate);
} }
$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; return $queryBuilder;
@@ -136,14 +156,15 @@ class QueryBuilderUtility
* *
* @param EntityManager $entityManager The entity manager * @param EntityManager $entityManager The entity manager
* @param array|ArrayCollection $entities The entities to delete * @param array|ArrayCollection $entities The entities to delete
* @param bool $flushDeleted (optional) If is set to true, flushes the deleted objects. * @param bool $flushDeleted (optional) If is set to true, flushes the deleted objects (default
* Otherwise - not. * behaviour). Otherwise - not.
* @throws OptimisticLockException
* @return bool * @return bool
*/ */
public static function deleteEntities(EntityManager $entityManager, $entities, $flushDeleted = true) public static function deleteEntities(EntityManager $entityManager, $entities, $flushDeleted = true)
{ {
/* /*
* No entities found? * No entities provided?
* Nothing to do * Nothing to do
*/ */
if (empty($entities)) { if (empty($entities)) {
@@ -169,24 +190,30 @@ class QueryBuilderUtility
* Attention. Existing parameters will be overridden. * Attention. Existing parameters will be overridden.
* *
* @param QueryBuilder $queryBuilder The query builder * @param QueryBuilder $queryBuilder The query builder
* @param array|ArrayCollection $parameters Parameters to add. Collection of instances of * @param array|ArrayCollection $parameters Parameters to add. Collection of Doctrine\ORM\Query\Parameter
* Doctrine\ORM\Query\Parameter class or an array with key-value pairs. * instances or an array with key-value pairs.
* @return QueryBuilder * @return QueryBuilder
*/ */
public static function addParameters(QueryBuilder $queryBuilder, $parameters) public static function addParameters(QueryBuilder $queryBuilder, $parameters)
{ {
if (!empty($parameters)) { /*
foreach ($parameters as $key => $parameter) { * No parameters?
$name = $key; * Nothing to do
$value = $parameter; */
if (empty($parameters)) {
return $queryBuilder;
}
if ($parameter instanceof Parameter) { foreach ($parameters as $key => $parameter) {
$name = $parameter->getName(); $name = $key;
$value = $parameter->getValue(); $value = $parameter;
}
$queryBuilder->setParameter($name, $value); if ($parameter instanceof Parameter) {
$name = $parameter->getName();
$value = $parameter->getValue();
} }
$queryBuilder->setParameter($name, $value);
} }
return $queryBuilder; return $queryBuilder;

View File

@@ -8,23 +8,19 @@
namespace Meritoo\Common\Utilities; namespace Meritoo\Common\Utilities;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Util\ClassUtils; use Doctrine\Common\Util\ClassUtils;
use Doctrine\Common\Util\Inflector; use Doctrine\Common\Util\Inflector;
use Meritoo\Common\Collection\Collection;
use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException; use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException;
use Meritoo\Common\Exception\Reflection\MissingChildClassesException; use Meritoo\Common\Exception\Reflection\MissingChildClassesException;
use Meritoo\Common\Exception\Reflection\NotExistingPropertyException;
use Meritoo\Common\Exception\Reflection\TooManyChildClassesException; use Meritoo\Common\Exception\Reflection\TooManyChildClassesException;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use ReflectionObject;
use ReflectionProperty;
/** /**
* Useful reflection methods * Useful reflection methods
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Reflection class Reflection
{ {
@@ -40,14 +36,14 @@ class Reflection
{ {
$effect = []; $effect = [];
$reflection = new ReflectionClass($class); $reflection = new \ReflectionClass($class);
$methods = $reflection->getMethods(); $methods = $reflection->getMethods();
if (!empty($methods)) { if (!empty($methods)) {
$className = self::getClassName($class); $className = self::getClassName($class);
foreach ($methods as $method) { foreach ($methods as $method) {
if ($method instanceof ReflectionMethod) { if ($method instanceof \ReflectionMethod) {
if ($withoutInheritance && $className !== $method->class) { if ($withoutInheritance && $className !== $method->class) {
continue; continue;
} }
@@ -68,14 +64,14 @@ class Reflection
*/ */
public static function getConstants($class) public static function getConstants($class)
{ {
$reflection = new ReflectionClass($class); $reflection = new \ReflectionClass($class);
return $reflection->getConstants(); return $reflection->getConstants();
} }
/** /**
* Returns maximum constant from all constants of given class / object. * Returns maximum integer value of constant of given class / object.
* Values of constants should be integers. * Constants whose values are integers are considered only.
* *
* @param object|string $class The object or name of object's class * @param object|string $class The object or name of object's class
* @return int|null * @return int|null
@@ -108,7 +104,7 @@ class Reflection
*/ */
public static function hasMethod($class, $method) public static function hasMethod($class, $method)
{ {
$reflection = new ReflectionClass($class); $reflection = new \ReflectionClass($class);
return $reflection->hasMethod($method); return $reflection->hasMethod($method);
} }
@@ -122,7 +118,7 @@ class Reflection
*/ */
public static function hasProperty($class, $property) public static function hasProperty($class, $property)
{ {
$reflection = new ReflectionClass($class); $reflection = new \ReflectionClass($class);
return $reflection->hasProperty($property); return $reflection->hasProperty($property);
} }
@@ -136,7 +132,7 @@ class Reflection
*/ */
public static function hasConstant($class, $constant) public static function hasConstant($class, $constant)
{ {
$reflection = new ReflectionClass($class); $reflection = new \ReflectionClass($class);
return $reflection->hasConstant($constant); return $reflection->hasConstant($constant);
} }
@@ -150,7 +146,7 @@ class Reflection
*/ */
public static function getConstantValue($class, $constant) public static function getConstantValue($class, $constant)
{ {
$reflection = new ReflectionClass($class); $reflection = new \ReflectionClass($class);
if (self::hasConstant($class, $constant)) { if (self::hasConstant($class, $constant)) {
return $reflection->getConstant($constant); return $reflection->getConstant($constant);
@@ -189,19 +185,19 @@ class Reflection
* Let's dig more and get proper value * Let's dig more and get proper value
* *
* Required to avoid bug: * 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) * 5. at Reflection ::getPropertyValue (null, 'name', true)
* 6. at ListService->getItemValue (object(Deal), 'project.name', '0') * 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) * while using "project.name" as property - $project has $name property ($project exists in the Deal class)
* and the $project equals null * and the $project equals null
* *
* Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * Meritoo <github@meritoo.pl>
* 2016-11-07 * 2016-11-07
*/ */
if ($object !== null) { if (null !== $object) {
unset($exploded[0]); unset($exploded[0]);
$property = implode('.', $exploded); $property = implode('.', $exploded);
@@ -216,45 +212,58 @@ class Reflection
* Use \ReflectionObject class * Use \ReflectionObject class
*/ */
try { try {
$reflectionProperty = new ReflectionProperty($className, $property); $reflectionProperty = new \ReflectionProperty($className, $property);
$value = $reflectionProperty->getValue($object); $value = $reflectionProperty->getValue($object);
} catch (ReflectionException $exception) { } catch (\ReflectionException $exception) {
/* /*
* 2nd try: * 2nd try:
* Look for the get / has / is methods * Look for the get / has / is methods
*/ */
$class = new ReflectionObject($object); $class = new \ReflectionObject($object);
$valueFound = false; $valueFound = false;
if ($class->hasProperty($property) || $force) { if ($force || $class->hasProperty($property)) {
$property = Inflector::classify($property); $property = Inflector::classify($property);
$methodPrefixes = [ $getterPrefixes = [
'get', 'get',
'has', 'has',
'is', 'is',
]; ];
foreach ($methodPrefixes as $prefix) { foreach ($getterPrefixes as $prefix) {
$method = sprintf('%s%s', $prefix, $property); $getterName = sprintf('%s%s', $prefix, $property);
if ($class->hasMethod($method)) { if ($class->hasMethod($getterName)) {
$value = $object->{$method}(); $method = new \ReflectionMethod($object, $getterName);
/*
* Getter is not accessible publicly?
* I have to skip it, to avoid an error like this:
*
* Call to protected method My\ExtraClass::getExtraProperty() from context 'My\ExtraClass'
*/
if ($method->isProtected() || $method->isPrivate()) {
continue;
}
$value = $object->{$getterName}();
$valueFound = true; $valueFound = true;
break; break;
} }
} }
} }
if (!$valueFound && $reflectionProperty !== null) { if (!$valueFound && null !== $reflectionProperty) {
/* /*
* Oops, we have got exception. * Oops, value of the property is still unknown
* *
* 3rd try: * 3rd try:
* Let's try modify accessibility of the property and try again to get value. * Let's modify accessibility of the property and try again to get value
*/ */
$reflectionProperty->setAccessible(true); $reflectionProperty->setAccessible(true);
$value = $reflectionProperty->getValue($object); $value = $reflectionProperty->getValue($object);
$reflectionProperty->setAccessible(false);
} }
} }
} }
@@ -275,6 +284,14 @@ class Reflection
*/ */
public static function getPropertyValues($objects, $property, $force = false) public static function getPropertyValues($objects, $property, $force = false)
{ {
/*
* No objects?
* Nothing to do
*/
if (empty($objects)) {
return [];
}
if ($objects instanceof Collection) { if ($objects instanceof Collection) {
$objects = $objects->toArray(); $objects = $objects->toArray();
} }
@@ -285,7 +302,7 @@ class Reflection
foreach ($objects as $entity) { foreach ($objects as $entity) {
$value = self::getPropertyValue($entity, $property, $force); $value = self::getPropertyValue($entity, $property, $force);
if ($value !== null) { if (null !== $value) {
$values[] = $value; $values[] = $value;
} }
} }
@@ -345,7 +362,7 @@ class Reflection
if ($withoutNamespace) { if ($withoutNamespace) {
$classOnly = Miscellaneous::getLastElementOfString($name, '\\'); $classOnly = Miscellaneous::getLastElementOfString($name, '\\');
if ($classOnly !== null) { if (null !== $classOnly) {
$name = $classOnly; $name = $classOnly;
} }
@@ -365,13 +382,13 @@ class Reflection
{ {
$fullClassName = self::getClassName($source); $fullClassName = self::getClassName($source);
if (empty($fullClassName)) { if (null === $fullClassName || '' === $fullClassName) {
return ''; return '';
} }
$className = self::getClassName($source, true); $className = self::getClassName($source, true);
if ($className == $fullClassName) { if ($className === $fullClassName) {
return $className; return $className;
} }
@@ -390,7 +407,7 @@ class Reflection
$className = self::getClassName($source); $className = self::getClassName($source);
$interfaces = class_implements($className); $interfaces = class_implements($className);
return in_array($interface, $interfaces); return in_array($interface, $interfaces, true);
} }
/** /**
@@ -407,8 +424,8 @@ class Reflection
$parents = class_parents($childClassName); $parents = class_parents($childClassName);
if (is_array($parents)) { if (is_array($parents) && 0 < count($parents)) {
return in_array($parentClassName, $parents); return in_array($parentClassName, $parents, true);
} }
return false; return false;
@@ -417,36 +434,50 @@ class Reflection
/** /**
* Returns given object properties * Returns given object properties
* *
* @param array|object|string $source An array of objects, namespaces, object or namespace * @param array|object|string $source An array of objects, namespaces, object or namespace
* @param int $filter (optional) Filter of properties. Uses ReflectionProperty class constants. * @param int $filter (optional) Filter of properties. Uses \ReflectionProperty class
* By default all properties are returned. * constants. By default all properties are returned.
* @return array|ReflectionProperty * @param bool $includeParents (optional) If is set to true, properties of parent classes are
* included (recursively). Otherwise - not.
* @return array|\ReflectionProperty
*/ */
public static function getProperties($source, $filter = null) public static function getProperties($source, $filter = null, $includeParents = false)
{ {
$className = self::getClassName($source); $className = self::getClassName($source);
$reflection = new ReflectionClass($className); $reflection = new \ReflectionClass($className);
if ($filter === null) { if (null === $filter) {
$filter = ReflectionProperty::IS_PRIVATE $filter = \ReflectionProperty::IS_PRIVATE
+ ReflectionProperty::IS_PROTECTED + \ReflectionProperty::IS_PROTECTED
+ ReflectionProperty::IS_PUBLIC + \ReflectionProperty::IS_PUBLIC
+ ReflectionProperty::IS_STATIC; + \ReflectionProperty::IS_STATIC;
} }
return $reflection->getProperties($filter); $properties = $reflection->getProperties($filter);
$parentProperties = [];
if ($includeParents) {
$parent = self::getParentClass($source);
if (false !== $parent) {
$parentClass = $parent->getName();
$parentProperties = self::getProperties($parentClass, $filter, $includeParents);
}
}
return array_merge($properties, $parentProperties);
} }
/** /**
* Returns a parent class * 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 * @param array|object|string $source An array of objects, namespaces, object or namespace
* @return ReflectionClass * @return \ReflectionClass|bool
*/ */
public static function getParentClass($source) public static function getParentClass($source)
{ {
$className = self::getClassName($source); $className = self::getClassName($source);
$reflection = new ReflectionClass($className); $reflection = new \ReflectionClass($className);
return $reflection->getParentClass(); return $reflection->getParentClass();
} }
@@ -457,8 +488,8 @@ class Reflection
* *
* @param array|object|string $class Class who child classes should be returned. An array of objects, strings, * @param array|object|string $class Class who child classes should be returned. An array of objects, strings,
* object or string. * object or string.
* @return array|null
* @throws CannotResolveClassNameException * @throws CannotResolveClassNameException
* @return array|null
*/ */
public static function getChildClasses($class) public static function getChildClasses($class)
{ {
@@ -477,8 +508,8 @@ class Reflection
/* /*
* Oops, cannot resolve class * Oops, cannot resolve class
*/ */
if ($className === null) { if (null === $className) {
throw new CannotResolveClassNameException($class); throw CannotResolveClassNameException::create($class);
} }
$childClasses = []; $childClasses = [];
@@ -495,7 +526,7 @@ class Reflection
*/ */
$realClass = ClassUtils::getRealClass($oneClass); $realClass = ClassUtils::getRealClass($oneClass);
if (in_array($realClass, $childClasses)) { if (in_array($realClass, $childClasses, true)) {
continue; continue;
} }
@@ -512,10 +543,9 @@ class Reflection
* *
* @param array|object|string $parentClass Class who child class should be returned. An array of objects, * @param array|object|string $parentClass Class who child class should be returned. An array of objects,
* namespaces, object or namespace. * namespaces, object or namespace.
* @return mixed
*
* @throws MissingChildClassesException * @throws MissingChildClassesException
* @throws TooManyChildClassesException * @throws TooManyChildClassesException
* @return mixed
*/ */
public static function getOneChildClass($parentClass) public static function getOneChildClass($parentClass)
{ {
@@ -526,7 +556,7 @@ class Reflection
* Oops, the base / parent class hasn't child class * Oops, the base / parent class hasn't child class
*/ */
if (empty($childClasses)) { if (empty($childClasses)) {
throw new MissingChildClassesException($parentClass); throw MissingChildClassesException::create($parentClass);
} }
/* /*
@@ -534,20 +564,20 @@ class Reflection
* Oops, the base / parent class has too many child classes * Oops, the base / parent class has too many child classes
*/ */
if (count($childClasses) > 1) { if (count($childClasses) > 1) {
throw new TooManyChildClassesException($parentClass, $childClasses); throw TooManyChildClassesException::create($parentClass, $childClasses);
} }
return trim($childClasses[0]); 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 array|object|string $class An array of objects, namespaces, object or namespace
* @param string $property Name of the property * @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. * By default all properties are allowed / processed.
* @return null|ReflectionProperty * @return null|\ReflectionProperty
*/ */
public static function getProperty($class, $property, $filter = null) public static function getProperty($class, $property, $filter = null)
{ {
@@ -555,9 +585,9 @@ class Reflection
$properties = self::getProperties($className, $filter); $properties = self::getProperties($className, $filter);
if (!empty($properties)) { if (!empty($properties)) {
/* @var $reflectionProperty ReflectionProperty */ /* @var $reflectionProperty \ReflectionProperty */
foreach ($properties as $reflectionProperty) { foreach ($properties as $reflectionProperty) {
if ($reflectionProperty->getName() == $property) { if ($reflectionProperty->getName() === $property) {
return $reflectionProperty; return $reflectionProperty;
} }
} }
@@ -573,8 +603,8 @@ class Reflection
* @param array|string $trait An array of strings or string * @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 * @param bool $verifyParents If is set to true, parent classes are verified if they use given
* trait. Otherwise - not. * trait. Otherwise - not.
* @return bool|null
* @throws CannotResolveClassNameException * @throws CannotResolveClassNameException
* @return bool|null
*/ */
public static function usesTrait($class, $trait, $verifyParents = false) public static function usesTrait($class, $trait, $verifyParents = false)
{ {
@@ -584,26 +614,26 @@ class Reflection
/* /*
* Oops, cannot resolve class * Oops, cannot resolve class
*/ */
if (empty($className)) { if (null === $className || '' === $className) {
throw new CannotResolveClassNameException($class); throw CannotResolveClassNameException::create($class);
} }
/* /*
* Oops, cannot resolve trait * Oops, cannot resolve trait
*/ */
if (empty($traitName)) { if (null === $traitName || '' === $traitName) {
throw new CannotResolveClassNameException($class, false); throw new CannotResolveClassNameException($class, false);
} }
$reflection = new ReflectionClass($className); $reflection = new \ReflectionClass($className);
$traitsNames = $reflection->getTraitNames(); $traitsNames = $reflection->getTraitNames();
$uses = in_array($traitName, $traitsNames); $uses = in_array($traitName, $traitsNames, true);
if (!$uses && $verifyParents) { if (!$uses && $verifyParents) {
$parentClassName = self::getParentClassName($className); $parentClassName = self::getParentClassName($className);
if ($parentClassName !== null) { if (null !== $parentClassName) {
return self::usesTrait($parentClassName, $trait, true); return self::usesTrait($parentClassName, $trait, true);
} }
} }
@@ -621,13 +651,66 @@ class Reflection
public static function getParentClassName($class) public static function getParentClassName($class)
{ {
$className = self::getClassName($class); $className = self::getClassName($class);
$reflection = new ReflectionClass($className); $reflection = new \ReflectionClass($className);
$parentClass = $reflection->getParentClass(); $parentClass = $reflection->getParentClass();
if ($parentClass === null || $parentClass === false) { if (null === $parentClass || false === $parentClass) {
return null; return null;
} }
return $parentClass->getName(); return $parentClass->getName();
} }
/**
* Sets value of given property in given object
*
* @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);
}
}
/**
* Sets values of properties in given object
*
* @param mixed $object Object that should contains given property
* @param array $propertiesValues Key-value pairs, where key - name of the property, value - value of the property
*/
public static function setPropertiesValues($object, array $propertiesValues)
{
/*
* No properties?
* Nothing to do
*/
if (empty($propertiesValues)) {
return;
}
foreach ($propertiesValues as $property => $value) {
static::setPropertyValue($object, $property, $value);
}
}
} }

View File

@@ -14,8 +14,8 @@ use Meritoo\Common\Exception\Regex\InvalidColorHexValueException;
/** /**
* Useful regular expressions methods * Useful regular expressions methods
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Regex class Regex
{ {
@@ -25,18 +25,21 @@ class Regex
* @var array * @var array
*/ */
private static $patterns = [ private static $patterns = [
'email' => '/[\w-]{2,}@[\w-]+\.[\w]{2,}+/', 'email' => '/^[\w-.]{2,}@[\w-]+\.[\w]{2,}+$/',
'phone' => '/^\+?[0-9 ]+$/', 'phone' => '/^\+?[0-9 ]+$/',
'camelCasePart' => '/([a-z]|[A-Z]){1}[a-z]*/', 'camelCasePart' => '/([a-z]|[A-Z]){1}[a-z]*/',
'urlProtocol' => '/^([a-z]+:\/\/)', 'urlProtocol' => '/^([a-z]+:\/\/)',
'urlDomain' => '([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i', 'urlDomain' => '([\da-z\.-]+)\.([a-z\.]{2,6})(\/)?([\w\.\-]*)?(\?)?([\w \.\-\/=&]*)\/?$/i',
'letterOrDigit' => '/[a-zA-Z0-9]+/', 'letterOrDigit' => '/[a-zA-Z0-9]+/',
'htmlEntity' => '/&[a-z0-9]+;/', 'htmlEntity' => '/&[a-z0-9]+;/',
'htmlAttribute' => '/([\w-]+)="([\w -]+)"/',
'fileName' => '/.+\.\w+$/', 'fileName' => '/.+\.\w+$/',
'isQuoted' => '/^[\'"]{1}.+[\'"]{1}$/', 'isQuoted' => '/^[\'"]{1}.+[\'"]{1}$/',
'windowsBasedPath' => '/^[A-Z]{1}:\\\.*$/', 'windowsBasedPath' => '/^[A-Z]{1}:\\\.*$/',
'money' => '/^[-+]?\d+([\.,]{1}\d*)?$/', 'money' => '/^[-+]?\d+([\.,]{1}\d*)?$/',
'color' => '/^[a-f0-9]{6}$/i', '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) public static function isValidEmail($email)
{ {
/*
* Not a string?
* Nothing to do
*/
if (!is_string($email)) {
return false;
}
$pattern = self::getEmailPattern(); $pattern = self::getEmailPattern();
return (bool)preg_match($pattern, $email); 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 * @return bool
*/ */
public static function isValidTaxid($taxidString) public static function isValidTaxId($taxIdString)
{ {
if (!empty($taxidString)) { /*
$weights = [ * Not a string?
6, * Nothing to do
5, */
7, if (!is_string($taxIdString)) {
2, return false;
3, }
4,
5,
6,
7,
];
$taxid = preg_replace('/[\s-]/', '', $taxidString);
$sum = 0;
if (strlen($taxid) == 10 && is_numeric($taxid)) { /*
for ($x = 0; $x <= 8; ++$x) { * Empty/Unknown value?
$sum += $taxid[$x] * $weights[$x]; * Nothing to do
} */
if (empty($taxIdString)) {
return false;
}
if ((($sum % 11) % 10) == $taxid[9]) { $taxId = preg_replace('/[\s-]/', '', $taxIdString);
return true;
} /*
} * 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; return false;
@@ -108,6 +145,14 @@ class Regex
*/ */
public static function isValidUrl($url, $requireProtocol = false) public static function isValidUrl($url, $requireProtocol = false)
{ {
/*
* Not a string?
* Nothing to do
*/
if (!is_string($url)) {
return false;
}
$pattern = self::getUrlPattern($requireProtocol); $pattern = self::getUrlPattern($requireProtocol);
return (bool)preg_match($pattern, $url); return (bool)preg_match($pattern, $url);
@@ -121,88 +166,108 @@ class Regex
*/ */
public static function isValidPhoneNumber($phoneNumber) public static function isValidPhoneNumber($phoneNumber)
{ {
/*
* Not a string?
* Nothing to do
*/
if (!is_string($phoneNumber)) {
return false;
}
$pattern = self::getPhoneNumberPattern(); $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 string $pattern Pattern to match
* @param array $dataArray The array * @param array $array The array (scalar values only)
* @param bool $itsKeyPattern (optional) If is set to true, keys are checks if they match pattern. Otherwise - * @param bool $itsKeyPattern (optional) If is set to true, keys will be checked if they match pattern.
* values are checks. * Otherwise - values will be checked (default behaviour).
* @return array * @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) { if ($itsKeyPattern) {
$effect = []; $effect = [];
if (!empty($dataArray)) { foreach ($array as $key => $value) {
$matches = []; if ((bool)preg_match($pattern, $key)) {
$effect[$key] = $value;
foreach ($dataArray as $key => $value) {
if (preg_match($pattern, $key, $matches)) {
$effect[$key] = $value;
}
} }
} }
return $effect; return $effect;
} }
return preg_grep($pattern, $dataArray); return preg_grep($pattern, $array);
} }
/** /**
* Filters array by given expression and column * 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. * 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 $arrayColumnKey Column name
* @param string $filterExpression Filter expression, e.g. '== 2' or '!= \'home\'' * @param string $filterExpression Simple filter expression (e.g. "== 2" or "!= \'home\'") or regular
* @param bool $itsRegularExpression (optional) If is set to true, means that filter expression is a * expression (e.g. "/\d+/" or "/[a-z]+[,;]{2,}/")
* regular expression * @param bool $itsRegularExpression (optional) If is set to true, means that filter expression is a regular
* expression. Otherwise - not (default behaviour).
* @return array * @return array
*/ */
public static function arrayFilter($array, $arrayColumnKey, $filterExpression, $itsRegularExpression = false) 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) { foreach ($effect as $key => &$item) {
if (isset($item[$arrayColumnKey])) { if (!isset($item[$arrayColumnKey])) {
$value = $item[$arrayColumnKey]; continue;
}
if ($itsRegularExpression) { $value = $item[$arrayColumnKey];
$matches = [];
$pattern = '|' . $filterExpression . '|';
$matchesCount = preg_match($pattern, $value, $matches);
$remove = $matchesCount == 0; 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 { } else {
if ($value == '') { $value = 'false';
$value = '\'\'';
} elseif (is_string($value)) {
$value = '\'' . $value . '\'';
}
eval('$isTrue = ' . $value . $filterExpression . ';');
/* @var bool $isTrue */
$remove = !$isTrue;
}
if ($remove) {
unset($effect[$key]);
} }
} }
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. * Returns information if given $subject matches one or all given $patterns.
* *
* @param array|string $patterns The patterns to match * @param array|string $patterns The patterns to match
* @param string $subject The string to check * @param string $subject The string to check
* @param bool $mustAllMatch (optional) If is set to true, $subject must match all $patterns. Otherwise - * @param bool $mustAllMatch (optional) If is set to true, $subject must match all $patterns. Otherwise -
* not. * not (default behaviour).
* @return bool * @return bool
*/ */
public static function pregMultiMatch($patterns, $subject, $mustAllMatch = false) public static function pregMultiMatch($patterns, $subject, $mustAllMatch = false)
{ {
/*
* No patterns?
* Nothing to do
*/
if (empty($patterns)) {
return false;
}
$effect = false; $effect = false;
$patterns = Arrays::makeArray($patterns); $patterns = Arrays::makeArray($patterns);
if (!empty($patterns)) { if ($mustAllMatch) {
$effect = true;
}
foreach ($patterns as $pattern) {
$matched = (bool)preg_match_all($pattern, $subject);
if ($mustAllMatch) { if ($mustAllMatch) {
$effect = true; $effect = $effect && $matched;
} } else {
if ($matched) {
foreach ($patterns as $pattern) { $effect = $matched;
$matches = []; break;
$matched = (bool)preg_match_all($pattern, $subject, $matches);
if ($mustAllMatch) {
$effect = $effect && $matched;
} else {
if ($matched) {
$effect = $matched;
break;
}
} }
} }
} }
@@ -431,7 +501,7 @@ class Regex
public static function startsWith($string, $beginning) public static function startsWith($string, $beginning)
{ {
if (!empty($string) && !empty($beginning)) { if (!empty($string) && !empty($beginning)) {
if (strlen($beginning) == 1 && !self::isLetterOrDigit($beginning)) { if (1 == strlen($beginning) && !self::isLetterOrDigit($beginning)) {
$beginning = '\\' . $beginning; $beginning = '\\' . $beginning;
} }
@@ -452,7 +522,7 @@ class Regex
*/ */
public static function endsWith($string, $ending) public static function endsWith($string, $ending)
{ {
if (strlen($ending) == 1 && !self::isLetterOrDigit($ending)) { if (1 == strlen($ending) && !self::isLetterOrDigit($ending)) {
$ending = '\\' . $ending; $ending = '\\' . $ending;
} }
@@ -537,7 +607,7 @@ class Regex
*/ */
public static function contains($haystack, $needle) public static function contains($haystack, $needle)
{ {
if (strlen($needle) == 1 && !self::isLetterOrDigit($needle)) { if (1 == strlen($needle) && !self::isLetterOrDigit($needle)) {
$needle = '\\' . $needle; $needle = '\\' . $needle;
} }
@@ -653,7 +723,7 @@ class Regex
} }
$modulo = $sum % 11; $modulo = $sum % 11;
$numberControl = ($modulo == 10) ? 0 : $modulo; $numberControl = (10 == $modulo) ? 0 : $modulo;
return $numberControl == $nip[9]; return $numberControl == $nip[9];
} }
@@ -676,6 +746,14 @@ class Regex
*/ */
public static function isValidMoneyValue($value) public static function isValidMoneyValue($value)
{ {
/*
* Not a scalar value?
* Nothing to do
*/
if (!is_scalar($value)) {
return false;
}
$pattern = self::getMoneyPattern(); $pattern = self::getMoneyPattern();
return (bool)preg_match($pattern, $value); return (bool)preg_match($pattern, $value);
@@ -688,39 +766,162 @@ class Regex
* @param string $color Color to verify * @param string $color Color to verify
* @param bool $throwException (optional) If is set to true, throws an exception if given color is invalid * @param bool $throwException (optional) If is set to true, throws an exception if given color is invalid
* (default behaviour). Otherwise - not. * (default behaviour). Otherwise - not.
* @return string|bool
*
* @throws IncorrectColorHexLengthException * @throws IncorrectColorHexLengthException
* @throws InvalidColorHexValueException * @throws InvalidColorHexValueException
* @return string|bool
*/ */
public static function getValidColorHexValue($color, $throwException = true) public static function getValidColorHexValue($color, $throwException = true)
{ {
/*
* Not a scalar value?
* Nothing to do
*/
if (!is_scalar($color)) {
return false;
}
$color = Miscellaneous::replace($color, '/#/', ''); $color = Miscellaneous::replace($color, '/#/', '');
$length = strlen($color); $length = strlen($color);
if ($length === 3) { /*
$color = Miscellaneous::replace($color, '/(.)(.)(.)/', '$1$1$2$2$3$3'); * Color is not 3 or 6 characters long?
} else { * Nothing to do
if ($length !== 6) { */
if ($throwException) { if (3 !== $length && 6 !== $length) {
throw new IncorrectColorHexLengthException($color);
}
return false;
}
}
$pattern = self::$patterns['color'];
$match = (bool)preg_match($pattern, $color);
if (!$match) {
if ($throwException) { if ($throwException) {
throw new InvalidColorHexValueException($color); throw new IncorrectColorHexLengthException($color);
} }
return false; 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);
} }
} }

View File

@@ -0,0 +1,238 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
/**
* Useful methods for repository
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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 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 unknown (is null) replenishment is stopped / skipped
* (default behaviour).
*/
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;
}
/*
* Extreme position is unknown or there are no items to sort?
* Nothing to do
*/
if (null === $position || empty($items)) {
return;
}
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 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(array $items, $max = true)
{
/*
* No items?
* Nothing to do
*/
if (empty($items)) {
return null;
}
$extreme = null;
foreach ($items as $item) {
/*
* The item is not sortable?
*/
if (!self::isSortable($item)) {
continue;
}
$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;
}
}
return $extreme;
}
/**
* Returns query builder for given entity's repository.
* The entity should contain given property, e.g. "name".
*
* @param EntityRepository $repository Repository of the entity
* @param string $property (optional) Name of property used by the ORDER BY clause
* @param string $direction (optional) Direction used by the ORDER BY clause ("ASC" or "DESC")
* @return QueryBuilder
*/
public static function getEntityOrderedQueryBuilder(
EntityRepository $repository,
$property = 'name',
$direction = 'ASC'
) {
$alias = 'qb';
$queryBuilder = $repository->createQueryBuilder($alias);
if (empty($property)) {
return $queryBuilder;
}
return $queryBuilder->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]));
}
}

View File

@@ -11,8 +11,8 @@ namespace Meritoo\Common\Utilities;
/** /**
* Useful uri methods (only static functions) * Useful uri methods (only static functions)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Uri class Uri
{ {
@@ -24,13 +24,25 @@ class Uri
*/ */
public static function getFullUri($withoutHost = false) 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) 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() public static function getProtocolName()
{ {
$effect = '';
$matches = []; $matches = [];
$protocolData = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'SERVER_PROTOCOL'); // e.g. HTTP/1.1 $protocolData = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'SERVER_PROTOCOL'); // e.g. HTTP/1.1
$matchCount = preg_match('|(.+)\/(.+)|', $protocolData, $matches); $matchCount = preg_match('|(.+)\/(.+)|', $protocolData, $matches);
@@ -68,11 +90,14 @@ class Uri
* $matches[2] - protocol version, e.g. 1.1 * $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() public static function getRefererUri()
{ {
$effect = ''; return Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_REFERER');
if (filter_has_var(INPUT_SERVER, 'HTTP_REFERER')) {
$effect = Miscellaneous::getSafelyGlobalVariable(INPUT_SERVER, 'HTTP_REFERER');
}
return $effect;
} }
/** /**
@@ -214,10 +233,35 @@ class Uri
*/ */
public static function isExternalUrl($url) 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); $currentUrl = self::getServerNameOrIp(true);
$url = self::replenishProtocol($url); $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 = '') public static function getSecuredUrl($url, $user = '', $password = '')
{ {
/*
* Url is not provided?
* Nothing to do
*/
if (empty($url)) {
return '';
}
$protocol = self::getProtocolName(); $protocol = self::getProtocolName();
$host = self::getServerNameOrIp(); $host = self::getServerNameOrIp();

View File

@@ -15,8 +15,8 @@ use SimpleXMLElement;
/** /**
* Useful XML-related methods (only static functions) * Useful XML-related methods (only static functions)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class Xml class Xml
{ {
@@ -40,7 +40,7 @@ class Xml
$query = $path->query('/*/*'); $query = $path->query('/*/*');
$nodesCount = $query->length; $nodesCount = $query->length;
if ($nodesCount == 0) { if (0 == $nodesCount) {
return $element1; return $element1;
} }

179
src/ValueObject/Version.php Normal file
View File

@@ -0,0 +1,179 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\ValueObject;
/**
* Version of software
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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);
}
}

View File

@@ -9,15 +9,16 @@
namespace Meritoo\Common\Test\Collection; namespace Meritoo\Common\Test\Collection;
use ArrayIterator; use ArrayIterator;
use Generator;
use Meritoo\Common\Collection\Collection; use Meritoo\Common\Collection\Collection;
use Meritoo\Common\Test\Base\BaseTestCase; use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType; use Meritoo\Common\Type\OopVisibilityType;
/** /**
* Tests of the collection of elements * Test case of the collection of elements
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class CollectionTest extends BaseTestCase class CollectionTest extends BaseTestCase
{ {
@@ -129,22 +130,39 @@ class CollectionTest extends BaseTestCase
static::assertInstanceOf(ArrayIterator::class, $this->simpleCollection->getIterator()); 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::assertTrue($collection->has($element));
static::assertEquals(1, $this->emptyCollection->count()); static::assertEquals($expectedCount, $collection->count());
static::assertEquals('test1', $this->emptyCollection[0]); 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::assertTrue($collection->has($element));
static::assertEquals(1, $this->emptyCollection->count()); static::assertEquals($expectedCount, $collection->count());
static::assertEquals('test2', $this->emptyCollection[1234]); static::assertEquals($element, $collection[$expectedIndex]);
} }
public function testAddMultipleUsingEmptyArray() public function testAddMultipleUsingEmptyArray()
@@ -306,7 +324,88 @@ class CollectionTest extends BaseTestCase
public function testExistsVisibilityAndArguments() public function testExistsVisibilityAndArguments()
{ {
$this->verifyMethodVisibilityAndArguments(Collection::class, 'exists', OopVisibilityType::IS_PRIVATE, 1, 1); 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,
];
} }
/** /**

View File

@@ -9,17 +9,23 @@
namespace Meritoo\Common\Test\Exception\Base; namespace Meritoo\Common\Test\Exception\Base;
use Meritoo\Common\Exception\Base\UnknownTypeException; use Meritoo\Common\Exception\Base\UnknownTypeException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\Base\BaseType; use Meritoo\Common\Type\Base\BaseType;
use PHPUnit_Framework_TestCase; use Meritoo\Common\Type\OopVisibilityType;
/** /**
* Tests of the exception used while type of something is unknown * Test case of the exception used while type of something is unknown
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class UnknownTypeExceptionTest extends PHPUnit_Framework_TestCase class UnknownTypeExceptionTest extends BaseTestCase
{ {
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(UnknownTestTypeException::class, OopVisibilityType::IS_PUBLIC, 3);
}
public function testWithoutException() public function testWithoutException()
{ {
self::assertEquals('Test 2', (new TestService())->getTranslatedType('test_2')); self::assertEquals('Test 2', (new TestService())->getTranslatedType('test_2'));
@@ -27,7 +33,7 @@ class UnknownTypeExceptionTest extends PHPUnit_Framework_TestCase
public function testTheException() public function testTheException()
{ {
$this->expectException(UnknownTestTypeException::class); $this->setExpectedException(UnknownTestTypeException::class);
self::assertEmpty((new TestService())->getTranslatedType('test_3')); self::assertEmpty((new TestService())->getTranslatedType('test_3'));
} }
} }
@@ -35,8 +41,8 @@ class UnknownTypeExceptionTest extends PHPUnit_Framework_TestCase
/** /**
* Type of something (for testing purposes) * Type of something (for testing purposes)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class TestType extends BaseType class TestType extends BaseType
{ {
@@ -48,27 +54,31 @@ class TestType extends BaseType
/** /**
* An exception used while type of something is unknown (for testing purposes) * An exception used while type of something is unknown (for testing purposes)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class UnknownTestTypeException extends UnknownTypeException 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) * Service used together with type of something (for testing purposes)
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class TestService class TestService
{ {
@@ -76,9 +86,8 @@ class TestService
* Returns translated type (for testing purposes) * Returns translated type (for testing purposes)
* *
* @param string $type Type of something (for testing purposes) * @param string $type Type of something (for testing purposes)
* @return string
*
* @throws UnknownTestTypeException * @throws UnknownTestTypeException
* @return string
*/ */
public function getTranslatedType($type) public function getTranslatedType($type)
{ {

View File

@@ -0,0 +1,71 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Date;
use Generator;
use Meritoo\Common\Exception\Type\UnknownDatePartTypeException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\DatePartType;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while type of date part, e.g. "year", is unknown
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class UnknownDatePartTypeExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(UnknownDatePartTypeException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param string $unknownDatePart Type of date part, e.g. "year". One of DatePartType class constants.
* @param string $value Incorrect value
* @param string $expectedMessage Expected exception's message
*
* @dataProvider provideDatePartAndValue
*/
public function testMessage($unknownDatePart, $value, $expectedMessage)
{
$exception = UnknownDatePartTypeException::createException($unknownDatePart, $value);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides type of date part, incorrect value and expected exception's message
*
* @return Generator
*/
public function provideDatePartAndValue()
{
$template = 'The \'%s\' type of date part (with value %s) is unknown. Probably doesn\'t exist or there is a'
. ' typo. You should use one of these types: day, hour, minute, month, second, year.';
yield[
DatePartType::DAY,
'44',
sprintf($template, DatePartType::DAY, '44'),
];
yield[
DatePartType::MONTH,
'22',
sprintf($template, DatePartType::MONTH, '22'),
];
yield[
DatePartType::MINUTE,
'77',
sprintf($template, DatePartType::MINUTE, '77'),
];
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\File;
use Generator;
use Meritoo\Common\Exception\File\EmptyFileException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while file with given path is empty (has no content)
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class EmptyFileExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(EmptyFileException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param string $emptyFilePath Path of the empty file
* @param string $expectedMessage Expected exception's message
*
* @dataProvider providePathOfFile
*/
public function testMessage($emptyFilePath, $expectedMessage)
{
$exception = EmptyFileException::create($emptyFilePath);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides path of the empty file and expected exception's message
*
* @return Generator
*/
public function providePathOfFile()
{
$template = 'File with path \'%s\' is empty (has no content). Did you provide path of proper file?';
yield[
'aa/bb/cc',
sprintf($template, 'aa/bb/cc'),
];
yield[
'images/show/car.jpg',
sprintf($template, 'images/show/car.jpg'),
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\File;
use Meritoo\Common\Exception\File\EmptyFilePathException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while path of given file is empty
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class EmptyFilePathExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(EmptyFilePathException::class, OopVisibilityType::IS_PUBLIC, 3);
}
public function testConstructorMessage()
{
$exception = EmptyFilePathException::create();
static::assertEquals('Path of the file is empty. Did you provide path of proper file?', $exception->getMessage());
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\File;
use Generator;
use Meritoo\Common\Exception\File\NotExistingFileException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while file with given path does not exist
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class NotExistingFileExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(NotExistingFileException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param string $notExistingFilePath Path of not existing (or not readable) file
* @param string $expectedMessage Expected exception's message
*
* @dataProvider providePathOfFile
*/
public function testConstructorMessage($notExistingFilePath, $expectedMessage)
{
$exception = NotExistingFileException::create($notExistingFilePath);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides path of not existing file and expected exception's message
*
* @return Generator
*/
public function providePathOfFile()
{
$template = 'File with path \'%s\' does not exist (or is not readable). Did you provide path of proper file?';
yield[
'aa/bb/cc',
sprintf($template, 'aa/bb/cc'),
];
yield[
'images/show/car.jpg',
sprintf($template, 'images/show/car.jpg'),
];
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Method;
use Generator;
use Meritoo\Common\Exception\Method\DisabledMethodException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while method cannot be called, because is disabled
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class DisabledMethodExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(DisabledMethodException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param string $disabledMethod Name of the disabled method
* @param string $alternativeMethod Name of the alternative method
* @param string $expectedMessage Expected exception's message
*
* @internal param string $emptyFilePath Path of the empty file
* @dataProvider provideMethodsNames
*/
public function testConstructorMessage($disabledMethod, $alternativeMethod, $expectedMessage)
{
$exception = DisabledMethodException::create($disabledMethod, $alternativeMethod);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides name of the disabled method, name of the alternative method and expected exception's message
*
* @return Generator
*/
public function provideMethodsNames()
{
$templateShort = 'Method %s() cannot be called, because is disabled.';
$templateLong = $templateShort . ' Use %s() instead.';
yield[
'FooBar::loremIpsum',
'',
sprintf($templateShort, 'FooBar::loremIpsum'),
];
yield[
'FooBar::loremIpsum',
'AnotherClass::alternativeMethod',
sprintf($templateLong, 'FooBar::loremIpsum', 'AnotherClass::alternativeMethod'),
];
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Reflection;
use Generator;
use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while name of class or trait cannot be resolved
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class CannotResolveClassNameExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(CannotResolveClassNameException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @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 If is set to true, message of this exception for class is prepared.
* Otherwise - for trait.
* @param string $expectedMessage Expected exception's message
*
* @dataProvider provideClassName
*/
public function testConstructorMessage($source, $forClass, $expectedMessage)
{
$exception = CannotResolveClassNameException::create($source, $forClass);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides source of the class's / trait's name, information if message of this exception should be prepared for
* class and the expected exception's message
*
* @return Generator
*/
public function provideClassName()
{
yield[
'Not\Existing\Class',
true,
'Name of class from given \'string\' Not\Existing\Class cannot be resolved. Is there everything ok?',
];
yield[
'Not\Existing\Trait',
false,
'Name of trait from given \'string\' Not\Existing\Trait cannot be resolved. Is there everything ok?',
];
yield[
[
new \stdClass(),
new \stdClass(),
],
true,
'Name of class from given \'array\' cannot be resolved. Is there everything ok?',
];
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Reflection;
use Generator;
use Meritoo\Common\Exception\Reflection\MissingChildClassesException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while given class has no child classes
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class MissingChildClassesExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(MissingChildClassesException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param array|object|string $parentClass Class that hasn't child classes, but it should. An array of objects,
* strings, object or string.
* @param string $expectedMessage Expected exception's message
*
* @dataProvider provideParentClass
*/
public function testConstructorMessage($parentClass, $expectedMessage)
{
$exception = MissingChildClassesException::create($parentClass);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides name of class that hasn't child classes, but it should, and expected exception's message
*
* @return Generator
*/
public function provideParentClass()
{
$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?';
yield[
MissingChildClassesException::class,
sprintf($template, MissingChildClassesException::class),
];
yield[
[
new \stdClass(),
new \stdClass(),
],
sprintf($template, \stdClass::class),
];
}
}

View File

@@ -0,0 +1,74 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Reflection;
use Generator;
use Meritoo\Common\Exception\Reflection\TooManyChildClassesException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while given class has more than one child class
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class TooManyChildClassesExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(TooManyChildClassesException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @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
* @param string $expectedMessage Expected exception's message
*
* @dataProvider provideParentAndChildClasses
*/
public function testConstructorMessage($parentClass, array $childClasses, $expectedMessage)
{
$exception = TooManyChildClassesException::create($parentClass, $childClasses);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides name of class that has more than one child class, but it shouldn't, child classes, and expected
* exception's message
*
* @return Generator
*/
public function provideParentAndChildClasses()
{
$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?";
yield[
BaseTestCase::class,
[
\stdClass::class,
OopVisibilityType::class,
],
sprintf($template, BaseTestCase::class, implode("\n- ", [
\stdClass::class,
OopVisibilityType::class,
]), BaseTestCase::class),
];
yield[
TooManyChildClassesException::class,
[
\stdClass::class,
],
sprintf($template, TooManyChildClassesException::class, implode("\n- ", [\stdClass::class]), TooManyChildClassesException::class),
];
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Regex;
use Generator;
use Meritoo\Common\Exception\Regex\IncorrectColorHexLengthException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while length of given hexadecimal value of color is incorrect
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class IncorrectColorHexLengthExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(IncorrectColorHexLengthException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param string $color Incorrect hexadecimal value of color
* @param string $expectedMessage Expected exception's message
*
* @dataProvider provideColor
*/
public function testConstructorMessage($color, $expectedMessage)
{
$exception = IncorrectColorHexLengthException::create($color);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides incorrect hexadecimal value of color and expected exception's message
*
* @return Generator
*/
public function provideColor()
{
$template = 'Length of hexadecimal value of color \'%s\' is incorrect. It\'s %d, but it should be 3 or 6. Is there everything ok?';
yield[
'',
sprintf($template, '', strlen('')),
];
yield[
'aa-bb-cc',
sprintf($template, 'aa-bb-cc', strlen('aa-bb-cc')),
];
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Regex;
use Generator;
use Meritoo\Common\Exception\Regex\InvalidColorHexValueException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while given hexadecimal value of color is invalid
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class InvalidColorHexValueExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(InvalidColorHexValueException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param string $color Invalid hexadecimal value of color
* @param string $expectedMessage Expected exception's message
*
* @dataProvider provideColor
*/
public function testConstructorMessage($color, $expectedMessage)
{
$exception = InvalidColorHexValueException::create($color);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides invalid hexadecimal value of color and expected exception's message
*
* @return Generator
*/
public function provideColor()
{
$template = 'Hexadecimal value of color \'%s\' is invalid. Is there everything ok?';
yield[
'',
sprintf($template, ''),
];
yield[
'aa-bb-cc',
sprintf($template, 'aa-bb-cc'),
];
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Regex;
use Generator;
use Meritoo\Common\Exception\Regex\InvalidHtmlAttributesException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while html attributes are invalid
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
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'),
];
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Regex;
use Generator;
use Meritoo\Common\Exception\Regex\InvalidUrlException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
/**
* Test case of an exception used while url is invalid
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class InvalidUrlExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(InvalidUrlException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param string $url Invalid url
* @param string $expectedMessage Expected exception's message
*
* @dataProvider provideUrl
*/
public function testConstructorMessage($url, $expectedMessage)
{
$exception = InvalidUrlException::create($url);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides invalid url and expected exception's message
*
* @return Generator
*/
public function provideUrl()
{
$template = 'Url \'%s\' is invalid. Is there everything ok?';
yield[
'aa/bb/cc',
sprintf($template, 'aa/bb/cc'),
];
yield[
'http:/images\show\car.jpg',
sprintf($template, 'http:/images\show\car.jpg'),
];
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Exception\Type;
use Generator;
use Meritoo\Common\Exception\Type\UnknownOopVisibilityTypeException;
use Meritoo\Common\Test\Base\BaseTestCase;
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 Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class UnknownOopVisibilityTypeExceptionTest extends BaseTestCase
{
public function testConstructorVisibilityAndArguments()
{
static::assertConstructorVisibilityAndArguments(UnknownOopVisibilityTypeException::class, OopVisibilityType::IS_PUBLIC, 3);
}
/**
* @param string $unknownType Unknown OOP-related visibility
* @param string $expectedMessage Expected exception's message
*
* @dataProvider provideUnknownType
*/
public function testConstructorMessage($unknownType, $expectedMessage)
{
$exception = UnknownOopVisibilityTypeException::createException($unknownType);
static::assertEquals($expectedMessage, $exception->getMessage());
}
/**
* Provides path of the empty file and expected exception's message
*
* @return Generator
*/
public function provideUnknownType()
{
$allTypes = (new OopVisibilityType())->getAll();
$template = 'The \'%s\' type of OOP-related visibility is unknown. Probably doesn\'t exist or there is a typo.'
. ' You should use one of these types: %s.';
yield[
'',
sprintf($template, '', implode(', ', $allTypes)),
];
yield[
123,
sprintf($template, 123, implode(', ', $allTypes)),
];
}
}

View File

@@ -1,40 +0,0 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Utilities;
use Meritoo\Common\Utilities\Bundle;
use PHPUnit_Framework_TestCase;
/**
* Tests of the useful methods for bundle
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class BundleTest extends PHPUnit_Framework_TestCase
{
public function testGetBundleViewPathEmptyPathAndBundle()
{
self::assertNull(Bundle::getBundleViewPath('', ''));
self::assertNull(Bundle::getBundleViewPath('test', ''));
self::assertNull(Bundle::getBundleViewPath('', 'test'));
}
public function testGetBundleViewPathWithDefaultExtension()
{
self::assertEquals('Lorem:Ipsum.html.twig', Bundle::getBundleViewPath('Ipsum', 'Lorem'));
self::assertEquals('LobortisTincidunt:FusceElementum.html.twig', Bundle::getBundleViewPath('FusceElementum', 'LobortisTincidunt'));
}
public function testGetBundleViewPathWithCustomExtension()
{
self::assertNull(Bundle::getBundleViewPath('Ipsum', 'Lorem', ''));
self::assertEquals('Lorem:Ipsum.js.twig', Bundle::getBundleViewPath('Ipsum', 'Lorem', 'js.twig'));
}
}

View File

@@ -1,129 +0,0 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Utilities;
use Generator;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Utilities\Locale;
/**
* Tests of the useful locale methods
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class LocaleTest extends BaseTestCase
{
/**
* @param mixed $languageCode Empty value, e.g. ""
* @dataProvider provideEmptyValue
*/
public function testGetLongFormEmptyLanguageCode($languageCode)
{
self::assertEquals('', Locale::getLongForm($languageCode));
}
/**
* @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 $encoding Encoding of the final locale
* @param string $expected Expected long form of the locale
*
* @dataProvider provideLanguageAndCountryCode
*/
public function testGetLongForm($languageCode, $countryCode, $encoding, $expected)
{
self::assertEquals($expected, Locale::getLongForm($languageCode, $countryCode, $encoding));
}
/**
* @param mixed $emptyValue Empty value, e.g. ""
* @dataProvider provideEmptyValue
*/
public function testSetLocaleEmptyCategoryAndLanguageCode($emptyValue)
{
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)
{
self::assertTrue(Locale::setLocale($category, $languageCode));
}
/**
* Provides language and country code
*
* @return Generator
*/
public function provideLanguageAndCountryCode()
{
yield[
'fr',
'',
'',
'fr_FR',
];
yield[
'fr',
'',
'UTF-8',
'fr_FR.UTF-8',
];
yield[
'fr',
'FR',
'',
'fr_FR',
];
yield[
'fr',
'FR',
'UTF-8',
'fr_FR.UTF-8',
];
}
/**
* Provides category and language
*
* @return Generator
*/
public function provideCategoryAndLanguageCode()
{
yield[
LC_ALL,
'fr',
];
yield[
LC_COLLATE,
'fr',
];
yield[
LC_CTYPE,
'en',
];
yield[
LC_NUMERIC,
'en',
];
}
}

View File

@@ -1,246 +0,0 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Utilities;
use DateTime;
use Generator;
use Meritoo\Common\Exception\Reflection\CannotResolveClassNameException;
use Meritoo\Common\Exception\Reflection\MissingChildClassesException;
use Meritoo\Common\Exception\Reflection\TooManyChildClassesException;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Test\Utilities\Reflection\A;
use Meritoo\Common\Test\Utilities\Reflection\B;
use Meritoo\Common\Test\Utilities\Reflection\C;
use Meritoo\Common\Test\Utilities\Reflection\D;
use Meritoo\Common\Test\Utilities\Reflection\E;
use Meritoo\Common\Utilities\Reflection;
/**
* Tests of the useful reflection methods
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class ReflectionTest extends BaseTestCase
{
/**
* @param mixed $invalidClass Empty value, e.g. ""
* @dataProvider provideEmptyValue
*/
public function testGetClassNameInvalidClass($invalidClass)
{
self::assertNull(Reflection::getClassName($invalidClass));
self::assertNull(Reflection::getClassName(123));
}
public function testGetClassNameNotExistingClass()
{
/*
* Not existing class
*/
self::assertEquals('', Reflection::getClassName('xyz'));
self::assertEquals('', Reflection::getClassName('xyz', true));
}
public function testGetClassNameExistingClass()
{
/*
* Existing class
*/
self::assertEquals(self::class, Reflection::getClassName(self::class));
self::assertEquals('ReflectionTest', Reflection::getClassName(self::class, true));
self::assertEquals(DateTime::class, Reflection::getClassName(new DateTime()));
self::assertEquals(DateTime::class, Reflection::getClassName(new DateTime(), true));
self::assertEquals(DateTime::class, Reflection::getClassName([
new DateTime(),
new DateTime('yesterday'),
]));
}
public function testGetClassNameDuplicatedName()
{
/*
* Class with namespace containing name of class (duplicated string)
*/
if (class_exists('Symfony\Bundle\SecurityBundle\SecurityBundle')) {
self::assertEquals('Symfony\Bundle\SecurityBundle\SecurityBundle', Reflection::getClassName('Symfony\Bundle\SecurityBundle\SecurityBundle'));
self::assertEquals('SecurityBundle', Reflection::getClassName('Symfony\Bundle\SecurityBundle\SecurityBundle', true));
}
}
public function testGetClassNamespaceNotExistingClass()
{
/*
* Not existing class
*/
self::assertEquals('', Reflection::getClassNamespace('xyz'));
}
public function testGetClassNamespaceExistingClass()
{
/*
* Existing class
*/
self::assertEquals('Meritoo\Common\Test\Utilities', Reflection::getClassNamespace(self::class));
self::assertEquals(DateTime::class, Reflection::getClassNamespace(new DateTime()));
self::assertEquals(DateTime::class, Reflection::getClassNamespace([
new DateTime(),
new DateTime('yesterday'),
]));
}
public function testGetClassNamespaceDuplicatedName()
{
/*
* Class with namespace containing name of class (duplicated string)
*/
if (class_exists('Symfony\Bundle\SecurityBundle\SecurityBundle')) {
self::assertEquals('Symfony\Bundle\SecurityBundle', Reflection::getClassNamespace('Symfony\Bundle\SecurityBundle\SecurityBundle'));
}
}
/**
* @param mixed $invalidClass Empty value, e.g. ""
* @dataProvider provideEmptyValue
*/
public function testGetChildClassesInvalidClass($invalidClass)
{
$this->expectException(CannotResolveClassNameException::class);
self::assertNull(Reflection::getChildClasses($invalidClass));
self::assertNull(Reflection::getChildClasses(123));
}
public function testGetChildClassesNotExistingClass()
{
$this->expectException(CannotResolveClassNameException::class);
self::assertEquals('', Reflection::getChildClasses('xyz'));
}
public function testGetChildClassesExistingClass()
{
/*
* Attention. I have to create instances of these classes to load them and be available while using
* get_declared_classes() function in the Reflection::getChildClasses() method. Without these instances the
* Reflection::getChildClasses() method returns an empty array even if given class has child classes.
*/
new A();
new B();
new C();
$effect = [
C::class,
];
self::assertEquals($effect, Reflection::getChildClasses(B::class));
$effect = [
B::class,
C::class,
];
self::assertEquals($effect, Reflection::getChildClasses(A::class));
}
public function testGetOneChildClassWithMissingChildClasses()
{
$this->expectException(MissingChildClassesException::class);
self::assertEquals('LoremIpsum', Reflection::getOneChildClass(C::class));
}
public function testGetOneChildClassWithTooManyChildClasses()
{
$this->expectException(TooManyChildClassesException::class);
self::assertEquals(B::class, Reflection::getOneChildClass(A::class));
self::assertEquals(C::class, Reflection::getOneChildClass(A::class));
}
public function testGetOneChildClass()
{
self::assertEquals(C::class, Reflection::getOneChildClass(B::class));
}
public function testGetMethods()
{
self::assertEquals(0, count(Reflection::getMethods(B::class, true)));
self::assertEquals(1, count(Reflection::getMethods(B::class)));
self::assertEquals(1, count(Reflection::getMethods(A::class)));
self::assertEquals(2, count(Reflection::getMethods(C::class, true)));
self::assertEquals(3, count(Reflection::getMethods(C::class)));
}
/**
* @param array|object|string $class An array of objects, namespaces, object or namespace
* @param array|string $trait An array of strings or string
*
* @dataProvider provideInvalidClassAndTrait
*/
public function testUsesTraitInvalidClass($class, $trait)
{
$this->expectException(CannotResolveClassNameException::class);
self::assertNull(Reflection::usesTrait($class, $trait));
}
/**
* @param mixed $trait Empty value, e.g. ""
* @dataProvider provideEmptyValue
*/
public function testUsesTraitInvalidTrait($trait)
{
$this->expectException(CannotResolveClassNameException::class);
self::assertNull(Reflection::usesTrait(DateTime::class, $trait));
}
public function testUsesTraitExistingClass()
{
self::assertTrue(Reflection::usesTrait(A::class, E::class));
self::assertFalse(Reflection::usesTrait(B::class, E::class));
self::assertFalse(Reflection::usesTrait(C::class, E::class));
self::assertFalse(Reflection::usesTrait(D::class, E::class));
}
public function testUsesTraitExistingClassAndVerifyParents()
{
self::assertTrue(Reflection::usesTrait(A::class, E::class, true));
self::assertTrue(Reflection::usesTrait(B::class, E::class, true));
self::assertTrue(Reflection::usesTrait(C::class, E::class, true));
self::assertFalse(Reflection::usesTrait(D::class, E::class, true));
}
/**
* Provides invalid class and trait
*
* @return Generator
*/
public function provideInvalidClassAndTrait()
{
yield[
'',
'',
];
yield[
null,
null,
];
yield[
0,
0,
];
yield[
[],
[],
];
}
}

View File

@@ -1,291 +0,0 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Utilities;
/**
* Tests of the useful regular expressions methods
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class RegexTest extends \PHPUnit_Framework_TestCase
{
private $simpleText;
private $camelCaseText;
public function testGetCamelCaseParts()
{
$parts = [];
self::assertEquals($parts, Regex::getCamelCaseParts(''));
$parts = [
'lorem',
];
self::assertEquals($parts, Regex::getCamelCaseParts('lorem'));
$parts = [
'lorem',
'Ipsum',
'Dolor',
'Sit',
];
self::assertEquals($parts, Regex::getCamelCaseParts($this->camelCaseText));
$parts = [
'Lorem',
'Ipsum',
'Dolor',
'Sit',
];
$string = ucfirst($this->camelCaseText); // 'LoremIpsumDolorSit'
self::assertEquals($parts, Regex::getCamelCaseParts($string));
}
public function testCamelCase2humanReadable()
{
self::assertEquals('', Regex::camelCase2humanReadable(''));
self::assertEquals('lorem', Regex::camelCase2humanReadable('lorem'));
self::assertEquals($this->simpleText, Regex::camelCase2humanReadable($this->camelCaseText));
self::assertEquals(ucfirst($this->simpleText), Regex::camelCase2humanReadable($this->camelCaseText, true));
}
public function testCamelCase2simpleLowercase()
{
self::assertEquals('', Regex::camelCase2simpleLowercase(''));
self::assertEquals('lorem', Regex::camelCase2simpleLowercase('lorem'));
self::assertEquals('Lorem', Regex::camelCase2simpleLowercase('Lorem', '', false));
self::assertEquals('lorem-ipsum-dolor-sit', Regex::camelCase2simpleLowercase($this->camelCaseText, '-'));
self::assertEquals('lorem-Ipsum-Dolor-Sit', Regex::camelCase2simpleLowercase($this->camelCaseText, '-', false));
}
public function testIsValidUrl()
{
$validUrls = [
'http://php.net',
'http://php.net/',
'http://php.net/docs.php',
'http://php.net/get-involved.php',
'http://php.net/manual/en/function.preg-match.php',
'http://domain.com/BigLetters',
'http://domain.com/Another-Big-Letters',
'http://domain.com/?a=1&b=c2d',
'http://domAin.COM/?a=1&B=c2D',
'http://domain.com/index.php?a=1&b=c2d',
'http://domain.com/another-page-2.php?a=1&b=c2d',
'https://domain.com',
'https://domain.com/',
];
$invalidUrls = [
'',
null,
false,
true,
0,
1,
123,
'123',
'http:',
'http://',
'http://abc',
'ftp://def',
];
foreach ($validUrls as $url) {
self::assertTrue(Regex::isValidUrl($url));
}
foreach ($invalidUrls as $url) {
self::assertFalse(Regex::isValidUrl($url));
}
}
public function testIsSubPathOf()
{
self::assertFalse(Regex::isSubPathOf(null, null));
self::assertFalse(Regex::isSubPathOf('', ''));
self::assertFalse(Regex::isSubPathOf('', '/my/directory'));
self::assertFalse(Regex::isSubPathOf('/my/file', ''));
self::assertFalse(Regex::isSubPathOf('/my/file', '/my/directory'));
self::assertTrue(Regex::isSubPathOf('/my/directory', '/my/directory'));
self::assertTrue(Regex::isSubPathOf('/my/directory/', '/my/directory'));
self::assertTrue(Regex::isSubPathOf('/my/directory', '/my/directory/'));
self::assertTrue(Regex::isSubPathOf('/my/directory/', '/my/directory/'));
self::assertTrue(Regex::isSubPathOf('/my/another/directory/another/file', '/my/another/directory'));
}
public function testIsLetterOrDigit()
{
self::assertTrue(Regex::isLetterOrDigit('a'));
self::assertTrue(Regex::isLetterOrDigit(10));
self::assertFalse(Regex::isLetterOrDigit(';'));
}
public function testStartsWith()
{
$string = 'Lorem ipsum dolor sit amet';
$beginning = 'Lor';
self::assertTrue(Regex::startsWith($string, $beginning));
$beginning = 'L';
self::assertTrue(Regex::startsWith($string, $beginning));
$beginning = 'X';
self::assertFalse(Regex::startsWith($string, $beginning));
$string = '1234567890';
$beginning = '1';
self::assertTrue(Regex::startsWith($string, $beginning));
$beginning = ';';
self::assertFalse(Regex::startsWith($string, $beginning));
}
public function testStartsWithDirectorySeparator()
{
/*
* Slash as separator
*/
$separatorSlash = '/';
self::assertTrue(Regex::startsWithDirectorySeparator('/my/extra/directory', $separatorSlash));
self::assertFalse(Regex::startsWithDirectorySeparator('my/extra/directory', $separatorSlash));
/*
* Backslash as separator
*/
$separatorBackslash = '\\';
self::assertTrue(Regex::startsWithDirectorySeparator('\my\extra\directory', $separatorBackslash));
self::assertFalse(Regex::startsWithDirectorySeparator('my\extra\directory', $separatorBackslash));
}
public function testEndsWithDirectorySeparator()
{
/*
* Slash as separator
*/
$separatorSlash = '/';
self::assertTrue(Regex::endsWithDirectorySeparator('my simple text/', $separatorSlash));
self::assertFalse(Regex::endsWithDirectorySeparator('my simple text', $separatorSlash));
/*
* Backslash as separator
*/
$separatorBackslash = '\\';
self::assertTrue(Regex::endsWithDirectorySeparator('my simple text\\', $separatorBackslash));
self::assertFalse(Regex::endsWithDirectorySeparator('my simple text', $separatorBackslash));
}
public function testEndsWith()
{
self::assertFalse(Regex::endsWith($this->simpleText, '\.\.\.'));
self::assertFalse(Regex::endsWith($this->simpleText, '\.'));
self::assertTrue(Regex::endsWith($this->simpleText, 't'));
}
public function testIsSetUriParameter()
{
$uri = 'www.domain.com/?name=phil&type=4';
$parameterName = 'type';
self::assertTrue(Regex::isSetUriParameter($uri, $parameterName));
$parameterName = 'color';
self::assertFalse(Regex::isSetUriParameter($uri, $parameterName));
}
public function testContainsEntities()
{
self::assertFalse(Regex::containsEntities('Lorem ipsum'));
self::assertTrue(Regex::containsEntities('Lorem ipsum &raquo;'));
}
public function testContains()
{
self::assertTrue(Regex::contains($this->simpleText, 'ipsum'));
self::assertFalse(Regex::contains($this->simpleText, 'neque'));
}
public function testIsFileName()
{
$filePath = __FILE__;
$directoryPath = dirname($filePath);
self::assertTrue(Regex::isFileName($filePath));
self::assertFalse(Regex::isFileName($directoryPath));
}
public function testIsQuoted()
{
self::assertTrue(Regex::isQuoted('\'lorem ipsum\''));
self::assertTrue(Regex::isQuoted('"lorem ipsum"'));
self::assertFalse(Regex::isQuoted('lorem ipsum'));
self::assertFalse(Regex::isQuoted(new \stdClass()));
}
public function testIsWindowsBasedPath()
{
self::assertTrue(Regex::isWindowsBasedPath('C:\path\to\directory'));
self::assertTrue(Regex::isWindowsBasedPath('C:\path\to\file.jpg'));
self::assertFalse(Regex::isWindowsBasedPath('/path/to/directory'));
self::assertFalse(Regex::isWindowsBasedPath('/path/to/file.jpg'));
}
public function testIsValidNip()
{
self::assertFalse(Regex::isValidNip(null));
self::assertFalse(Regex::isValidNip(''));
self::assertFalse(Regex::isValidNip(1234));
self::assertFalse(Regex::isValidNip(1234567890));
self::assertFalse(Regex::isValidNip(0000000000));
self::assertFalse(Regex::isValidNip('1234567890'));
self::assertFalse(Regex::isValidNip('0000000000'));
self::assertFalse(Regex::isValidNip('abc'));
self::assertFalse(Regex::isValidNip($this->simpleText));
self::assertTrue(Regex::isValidNip('7340009469')); // Onet S.A.
self::assertTrue(Regex::isValidNip('5252530705')); // Facebook Poland sp. z o.o.
}
/**
* {@inheritdoc}
*/
protected function setUp()
{
parent::setUp();
$this->simpleText = 'lorem ipsum dolor sit';
$this->camelCaseText = str_replace(' ', '', lcfirst(ucwords($this->simpleText))); // 'loremIpsumDolorSit'
}
/**
* {@inheritdoc}
*/
protected function tearDown()
{
parent::tearDown();
unset($this->simpleText);
unset($this->camelCaseText);
}
}

View File

@@ -1,79 +0,0 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Utilities;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Utilities\Uri;
/**
* Tests of the useful uri methods (only static functions)
*
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl>
* @copyright Meritoo.pl
*/
class UriTest extends BaseTestCase
{
public function testAddProtocolToUrl()
{
$http = 'http';
$https = 'https';
$url = 'my.domain/some/url';
$httpUrl = sprintf('%s://%s', $http, $url);
$httpsUrl = sprintf('%s://%s', $https, $url);
self::assertEquals($httpUrl, Uri::addProtocolToUrl($httpUrl));
self::assertEquals($httpUrl, Uri::addProtocolToUrl($url));
self::assertEquals($httpsUrl, Uri::addProtocolToUrl($url, $https));
self::assertEquals($httpsUrl, Uri::addProtocolToUrl($httpsUrl, $http));
}
/**
* @param mixed $url Empty value, e.g. ""
* @dataProvider provideEmptyValue
*/
public function testReplenishProtocolEmptyUrl($url)
{
self::assertEquals('', Uri::replenishProtocol($url));
}
/**
* @param string $expected Expected result
* @param string $url The url to check and replenish
* @param string $protocol (optional) The protocol which is replenished. If is empty, protocol of current request
* is used.
*
* @dataProvider provideUrlsToReplenishProtocol
*/
public function testReplenishProtocol($expected, $url, $protocol = '')
{
self::assertSame($expected, Uri::replenishProtocol($url, $protocol));
}
/**
* Provides urls to replenish protocol
*
* @return \Generator
*/
public function provideUrlsToReplenishProtocol()
{
yield[
'://test',
'test',
'',
];
yield[
'ftp://lorem.ipsum',
'lorem.ipsum',
'ftp',
];
}
}

0
tests/Resources/var/cache/.gitkeep vendored Normal file
View File

View File

View File

View File

@@ -0,0 +1,176 @@
<?php
/**
* (c) Meritoo.pl, http://www.meritoo.pl
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Meritoo\Common\Test\Test\Base;
use DateTime;
use Generator;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\OopVisibilityType;
use Meritoo\Common\Utilities\GeneratorUtility;
/**
* Test case of the base test case with common methods and data providers
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class BaseTestCaseTest extends BaseTestCase
{
public function testConstructor()
{
static::assertConstructorVisibilityAndArguments(BaseTestCase::class, OopVisibilityType::IS_PUBLIC, 3);
}
public function testProvideEmptyValue()
{
$elements = [
[''],
[' '],
[null],
[0],
[false],
[[]],
];
$generator = (new SimpleTestCase())->provideEmptyValue();
self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator));
}
public function testProvideBooleanValue()
{
$elements = [
[false],
[true],
];
$generator = (new SimpleTestCase())->provideBooleanValue();
self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator));
}
public function testProvideDateTimeInstance()
{
$dateFormat = 'Y-m-d H:i';
$expectedElements = [
[new DateTime()],
[new DateTime('yesterday')],
[new DateTime('now')],
[new DateTime('tomorrow')],
];
$generator = (new SimpleTestCase())->provideDateTimeInstance();
$generatedElements = GeneratorUtility::getGeneratorElements($generator);
/* @var DateTime $instance1 */
$instance1 = $generatedElements[0][0];
/* @var DateTime $instance2 */
$instance2 = $generatedElements[1][0];
/* @var DateTime $instance3 */
$instance3 = $generatedElements[2][0];
/* @var DateTime $instance4 */
$instance4 = $generatedElements[3][0];
self::assertCount(count($expectedElements), $generatedElements);
self::assertEquals($instance1->format($dateFormat), (new DateTime())->format($dateFormat));
self::assertEquals($instance2->format($dateFormat), (new DateTime('yesterday'))->format($dateFormat));
self::assertEquals($instance3->format($dateFormat), (new DateTime('now'))->format($dateFormat));
self::assertEquals($instance4->format($dateFormat), (new DateTime('tomorrow'))->format($dateFormat));
}
public function testProvideDateTimeRelativeFormat()
{
$elements = [
['now'],
['yesterday'],
['tomorrow'],
['back of 10'],
['front of 10'],
['last day of February'],
['first day of next month'],
['last day of previous month'],
['last day of next month'],
['Y-m-d'],
['Y-m-d 10:00'],
];
$generator = (new SimpleTestCase())->provideDateTimeRelativeFormat();
self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator));
}
public function testProvideNotExistingFilePath()
{
$elements = [
['lets-test.doc'],
['lorem/ipsum.jpg'],
['surprise/me/one/more/time.txt'],
];
$generator = (new SimpleTestCase())->provideNotExistingFilePath();
self::assertEquals($elements, GeneratorUtility::getGeneratorElements($generator));
}
/**
* @param string $fileName Name of file
* @param string $directoryPath Path of directory containing the file
*
* @dataProvider provideFileNameAndDirectoryPath
*/
public function testGetFilePathForTesting($fileName, $directoryPath)
{
$path = (new SimpleTestCase())->getFilePathForTesting($fileName, $directoryPath);
if (!empty($directoryPath)) {
$directoryPath .= '/';
}
$expectedContains = sprintf('/data/tests/%s%s', $directoryPath, $fileName);
static::assertContains($expectedContains, $path);
}
/**
* Provides name of file and path of directory containing the file
*
* @return Generator
*/
public function provideFileNameAndDirectoryPath()
{
yield[
'abc.jpg',
'',
];
yield[
'abc.def.jpg',
'',
];
yield[
'abc.jpg',
'def',
];
yield[
'abc.def.jpg',
'def',
];
}
}
/**
* Simple test case
*
* @author Meritoo <github@meritoo.pl>
* @copyright Meritoo <http://www.meritoo.pl>
*/
class SimpleTestCase extends BaseTestCase
{
}

View File

@@ -9,17 +9,22 @@
namespace Meritoo\Common\Test\Type\Base; namespace Meritoo\Common\Test\Type\Base;
use Generator; use Generator;
use Meritoo\Common\Test\Base\BaseTestCase;
use Meritoo\Common\Type\Base\BaseType; use Meritoo\Common\Type\Base\BaseType;
use PHPUnit_Framework_TestCase;
/** /**
* Tests of the base / abstract type of something * Test case of the base / abstract type of something
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class BaseTypeTest extends PHPUnit_Framework_TestCase class BaseTypeTest extends BaseTestCase
{ {
public function testConstructor()
{
static::assertHasNoConstructor(BaseType::class);
}
/** /**
* @param BaseType $type Type of something * @param BaseType $type Type of something
* @param array $expectedTypes Expected concrete types of given instance of type * @param array $expectedTypes Expected concrete types of given instance of type
@@ -179,8 +184,8 @@ class BaseTypeTest extends PHPUnit_Framework_TestCase
/** /**
* Empty type of something used for testing * Empty type of something used for testing
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class TestEmptyType extends BaseType class TestEmptyType extends BaseType
{ {
@@ -189,8 +194,8 @@ class TestEmptyType extends BaseType
/** /**
* Type of something used for testing * Type of something used for testing
* *
* @author Krzysztof Niziol <krzysztof.niziol@meritoo.pl> * @author Meritoo <github@meritoo.pl>
* @copyright Meritoo.pl * @copyright Meritoo <http://www.meritoo.pl>
*/ */
class TestType extends BaseType class TestType extends BaseType
{ {

Some files were not shown because too many files have changed in this diff Show More