diff --git a/.scrutinizer.yml b/.scrutinizer.yml
new file mode 100644
index 0000000..ee18d45
--- /dev/null
+++ b/.scrutinizer.yml
@@ -0,0 +1,43 @@
+filter:
+ excluded_paths:
+ - tests/*
+checks:
+ php:
+ code_rating: true
+ duplication: false
+ unused_methods: true
+ unused_parameters: true
+ argument_type_checks: true
+ verify_property_names: true
+ method_calls_on_non_object: false
+ fix_doc_comments: true
+ instanceof_class_exists: true
+ catch_class_exists: true
+ assignment_of_null_return: false
+ use_statement_alias_conflict: false
+ simplify_boolean_return: true
+ return_doc_comments: true
+ return_doc_comment_if_not_inferrable: true
+ remove_extra_empty_lines: true
+ remove_php_closing_tag: true
+ parameters_in_camelcaps: true
+ parameter_doc_comments: true
+ param_doc_comment_if_not_inferrable: true
+ properties_in_camelcaps: true
+ no_long_variable_names:
+ maximum: '27'
+ no_goto: true
+ more_specific_types_in_doc_comments: true
+ fix_use_statements:
+ remove_unused: true
+ preserve_multiple: false
+ preserve_blanklines: true
+ order_alphabetically: false
+ fix_line_ending: true
+ fix_php_opening_tag: true
+
+coding_style:
+ php:
+ spaces:
+ around_operators:
+ concatenation: true
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..54471ff
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,30 @@
+language: php
+
+php:
+ - 5.5
+ - 5.6
+ - 7.0
+ - 7.1
+ - 7.2
+
+# environment variable used in test suite
+env: TEST_ENVIRONMENT=travis
+
+# faster builds on new travis setup not using sudo
+sudo: false
+
+# cache vendor dirs
+cache:
+ directories:
+ - vendor
+ - $HOME/.composer/cache
+
+# install dependencies
+install:
+ - travis_retry composer self-update && composer --version
+ - travis_retry composer update --prefer-dist --no-interaction
+
+# run tests
+script:
+ - composer validate --no-check-lock
+ - composer test
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3db114d..e2024ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,8 @@
Translatable Behavior Change Log
--------------------------------
-1.0.0 Under development
------------------------
+1.0.0 April 22, 2018
+--------------------
* Initial release (greeflas)
Development started March 18, 2018
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..eb4ade8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,134 @@
+
+
+
+
+
Translatable behavior
+
+
+[![Build Status](https://travis-ci.org/yiimaker/yii2-translatable.svg?branch=master)](https://travis-ci.org/yiimaker/yii2-translatable)
+[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/yiimaker/yii2-translatable/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/yiimaker/yii2-translatable/?branch=master)
+[![Total Downloads](https://poser.pugx.org/yiimaker/yii2-translatable/downloads)](https://packagist.org/packages/yiimaker/yii2-translatable)
+[![Latest Stable Version](https://poser.pugx.org/yiimaker/yii2-translatable/v/stable)](https://packagist.org/packages/yiimaker/yii2-translatable)
+[![Latest Unstable Version](https://poser.pugx.org/yiimaker/yii2-translatable/v/unstable)](https://packagist.org/packages/yiimaker/yii2-translatable)
+
+Translatable behavior aggregates logic of linking translations to the primary model.
+
+Installation
+------------
+
+The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
+
+Either run
+
+```
+$ composer require yiimaker/yii2-translatable
+```
+
+or add
+
+```
+"yiimaker/yii2-translatable": "~1.0"
+```
+
+to the `require` section of your `composer.json`.
+
+Usage
+-----
+
+1. Add behavior to the your primary model
+
+```php
+public function behaviors()
+{
+ return [
+ // ...
+ 'translatable' => [
+ 'class' => TranslatableBehavior::className(),
+ // 'translationRelationName' => 'translations',
+ // 'translationLanguageAttrName' => 'language',
+ // 'attributeNamePattern' => '%name% [%language%]',
+ 'translationAttributeList' => [
+ 'title',
+ 'description',
+ ],
+ ],
+ ];
+}
+```
+
+2. And use `getTranslation()` or `translateTo()` methods
+
+```php
+// product is an active record model with translatable behavior
+$product = new Product();
+
+// sets translation for default application language
+$product->title = 'PhpStrom 2018.1';
+$product->description = 'Лицензия PhpStrom IDE версия 2018.1';
+
+// gets translation for English language
+$translation = $product->getTranslation('en');
+$translation->title = 'PhpStrom 2018.1';
+$translation->description = 'License of the PhpStrom IDE version 2018.1';
+
+// sets description for French language
+$product->translateTo('fr')->description = 'La licence de PhpStorm IDE la version 2018.1';
+
+$product->insert();
+```
+
+`translateTo()` it's just an alias for `getTranslation()` method.
+
+After saving the model you can fetch this model from the database and translatable behavior will fetch all translations automatically.
+
+```php
+$product = Product::find()
+ ->where(['id' => 1])
+ ->with('translations')
+ ->one()
+;
+
+// gets translation for English language
+$product->translateTo('en')->description; // License of the PhpStrom IDE version 2018.1
+// gets translation for French language
+$product->translateTo('fr')->description; // La licence de PhpStorm IDE la version 2018.1
+
+// check whether Ukrainian translation not exists
+if (!$product->hasTranslation('uk')) {
+ $product->translateTo('uk')->description = 'Ліцензія PhpStrom IDE версія 2018.1';
+}
+
+// update Enlish translation
+$product->translateTo('en')->title = 'PhpStorm IDE';
+
+$product->update();
+```
+
+Tests
+-----
+
+You can run tests with composer command
+
+```
+$ composer test
+```
+
+or using following command
+
+```
+$ codecept build && codecept run
+```
+
+Contributing
+------------
+
+For information about contributing please read [CONTRIBUTING.md](CONTRIBUTING.md).
+
+License
+-------
+
+[![License](https://poser.pugx.org/yiimaker/yii2-translatable/license)](https://packagist.org/packages/yiimaker/yii2-translatable)
+
+This project is released under the terms of the BSD-3-Clause [license](LICENSE).
+
+Copyright (c) 2017-2018, Yii Maker
diff --git a/codeception.yml b/codeception.yml
new file mode 100644
index 0000000..af78aa4
--- /dev/null
+++ b/codeception.yml
@@ -0,0 +1,26 @@
+actor: Tester
+paths:
+ tests: tests
+ log: tests/_output
+ data: tests/_data
+ support: tests/_support
+settings:
+ bootstrap: _bootstrap.php
+ colors: true
+ memory_limit: 1024M
+extensions:
+ enabled:
+ - Codeception\Extension\RunFailed
+modules:
+ config:
+ Yii2:
+ cleanup: false
+ configFile: 'tests/_config/app.php'
+ Db:
+ dsn: 'sqlite:tests/_output/test.db'
+ user: ''
+ password: ''
+ dump: 'tests/_data/dump.sql'
+ cleanup: true,
+ populate: true,
+ reconnect: false
diff --git a/composer.json b/composer.json
index fcde585..f9e2123 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "yiimaker/yii2-translatable",
- "description": "",
+ "description": "Translatable behavior aggregates logic of linking translations to the primary model",
"keywords": ["yii2", "behavior", "translatable", "translation", "translations", "ar"],
"type": "yii2-extension",
"license": "BSD-3-Clause",
diff --git a/composer.lock b/composer.lock
index 11281cb..f32566c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -194,16 +194,16 @@
},
{
"name": "yiisoft/yii2",
- "version": "2.0.14.2",
+ "version": "2.0.15.1",
"source": {
"type": "git",
"url": "https://github.com/yiisoft/yii2-framework.git",
- "reference": "ef74f3783e964cea477f06e6d6ce209df1f37881"
+ "reference": "ed3a9e1c4abe206e1c3ce48a6b3624119b79850d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/ef74f3783e964cea477f06e6d6ce209df1f37881",
- "reference": "ef74f3783e964cea477f06e6d6ce209df1f37881",
+ "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/ed3a9e1c4abe206e1c3ce48a6b3624119b79850d",
+ "reference": "ed3a9e1c4abe206e1c3ce48a6b3624119b79850d",
"shasum": ""
},
"require": {
@@ -290,20 +290,20 @@
"framework",
"yii2"
],
- "time": "2018-03-13T14:15:01+00:00"
+ "time": "2018-03-21T18:36:53+00:00"
},
{
"name": "yiisoft/yii2-composer",
- "version": "2.0.5",
+ "version": "2.0.6",
"source": {
"type": "git",
"url": "https://github.com/yiisoft/yii2-composer.git",
- "reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2"
+ "reference": "163419f1f197e02f015713b0d4f85598d8f8aa80"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2",
- "reference": "3f4923c2bde6caf3f5b88cc22fdd5770f52f8df2",
+ "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/163419f1f197e02f015713b0d4f85598d8f8aa80",
+ "reference": "163419f1f197e02f015713b0d4f85598d8f8aa80",
"shasum": ""
},
"require": {
@@ -332,6 +332,10 @@
{
"name": "Qiang Xue",
"email": "qiang.xue@gmail.com"
+ },
+ {
+ "name": "Carsten Brandt",
+ "email": "mail@cebe.cc"
}
],
"description": "The composer plugin for Yii extension installer",
@@ -340,22 +344,22 @@
"extension installer",
"yii2"
],
- "time": "2016-12-20T13:26:02+00:00"
+ "time": "2018-03-21T16:15:55+00:00"
}
],
"packages-dev": [
{
"name": "behat/gherkin",
- "version": "v4.5.1",
+ "version": "v4.4.5",
"source": {
"type": "git",
"url": "https://github.com/Behat/Gherkin.git",
- "reference": "74ac03d52c5e23ad8abd5c5cce4ab0e8dc1b530a"
+ "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Behat/Gherkin/zipball/74ac03d52c5e23ad8abd5c5cce4ab0e8dc1b530a",
- "reference": "74ac03d52c5e23ad8abd5c5cce4ab0e8dc1b530a",
+ "url": "https://api.github.com/repos/Behat/Gherkin/zipball/5c14cff4f955b17d20d088dec1bde61c0539ec74",
+ "reference": "5c14cff4f955b17d20d088dec1bde61c0539ec74",
"shasum": ""
},
"require": {
@@ -401,62 +405,66 @@
"gherkin",
"parser"
],
- "time": "2017-08-30T11:04:43+00:00"
+ "time": "2016-10-30T11:50:56+00:00"
},
{
"name": "codeception/codeception",
- "version": "2.4.0",
+ "version": "2.3.4",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
- "reference": "c50789a9a62cc0eefc0252e88a5f04f8c47b55f4"
+ "reference": "b5391497f9a3c9d0a9c02ae39b53441e413e35a8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Codeception/Codeception/zipball/c50789a9a62cc0eefc0252e88a5f04f8c47b55f4",
- "reference": "c50789a9a62cc0eefc0252e88a5f04f8c47b55f4",
+ "url": "https://api.github.com/repos/Codeception/Codeception/zipball/b5391497f9a3c9d0a9c02ae39b53441e413e35a8",
+ "reference": "b5391497f9a3c9d0a9c02ae39b53441e413e35a8",
"shasum": ""
},
"require": {
- "behat/gherkin": "^4.4.0",
- "codeception/phpunit-wrapper": "^6.0|^7.0",
- "codeception/stub": "^1.0",
+ "behat/gherkin": "~4.4.0",
"ext-json": "*",
"ext-mbstring": "*",
- "facebook/webdriver": ">=1.1.3 <2.0",
+ "facebook/webdriver": ">=1.0.1 <2.0",
"guzzlehttp/guzzle": ">=4.1.4 <7.0",
"guzzlehttp/psr7": "~1.0",
"php": ">=5.4.0 <8.0",
- "symfony/browser-kit": ">=2.7 <5.0",
- "symfony/console": ">=2.7 <5.0",
- "symfony/css-selector": ">=2.7 <5.0",
- "symfony/dom-crawler": ">=2.7 <5.0",
- "symfony/event-dispatcher": ">=2.7 <5.0",
- "symfony/finder": ">=2.7 <5.0",
- "symfony/yaml": ">=2.7 <5.0"
+ "phpunit/php-code-coverage": ">=2.2.4 <6.0",
+ "phpunit/phpunit": ">4.8.20 <7.0",
+ "phpunit/phpunit-mock-objects": ">2.3 <5.0",
+ "sebastian/comparator": ">1.1 <3.0",
+ "sebastian/diff": "^1.4",
+ "stecman/symfony-console-completion": "^0.7.0",
+ "symfony/browser-kit": ">=2.7 <4.0",
+ "symfony/console": ">=2.7 <4.0",
+ "symfony/css-selector": ">=2.7 <4.0",
+ "symfony/dom-crawler": ">=2.7.5 <4.0",
+ "symfony/event-dispatcher": ">=2.7 <4.0",
+ "symfony/finder": ">=2.7 <4.0",
+ "symfony/yaml": ">=2.7 <4.0"
},
"require-dev": {
"codeception/specify": "~0.3",
"facebook/graph-sdk": "~5.3",
"flow/jsonpath": "~0.2",
+ "league/factory-muffin": "^3.0",
+ "league/factory-muffin-faker": "^1.0",
+ "mongodb/mongodb": "^1.0",
"monolog/monolog": "~1.8",
"pda/pheanstalk": "~3.0",
"php-amqplib/php-amqplib": "~2.4",
"predis/predis": "^1.0",
"squizlabs/php_codesniffer": "~2.0",
- "symfony/process": ">=2.7 <5.0",
+ "symfony/process": ">=2.7 <4.0",
"vlucas/phpdotenv": "^2.4.0"
},
"suggest": {
- "aws/aws-sdk-php": "For using AWS Auth in REST module and Queue module",
- "codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests",
"codeception/specify": "BDD-style code blocks",
"codeception/verify": "BDD-style assertions",
"flow/jsonpath": "For using JSONPath in REST module",
"league/factory-muffin": "For DataFactory module",
"league/factory-muffin-faker": "For Faker support in DataFactory module",
"phpseclib/phpseclib": "for SFTP option in FTP Module",
- "stecman/symfony-console-completion": "For BASH autocompletion",
"symfony/phpunit-bridge": "For phpunit-bridge support"
},
"bin": [
@@ -492,83 +500,7 @@
"functional testing",
"unit testing"
],
- "time": "2018-02-27T00:09:12+00:00"
- },
- {
- "name": "codeception/phpunit-wrapper",
- "version": "7.0.5",
- "source": {
- "type": "git",
- "url": "https://github.com/Codeception/phpunit-wrapper.git",
- "reference": "42c8fdbf301ee36f6b58cb154972f9148fdcb7d4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Codeception/phpunit-wrapper/zipball/42c8fdbf301ee36f6b58cb154972f9148fdcb7d4",
- "reference": "42c8fdbf301ee36f6b58cb154972f9148fdcb7d4",
- "shasum": ""
- },
- "require": {
- "phpunit/php-code-coverage": "^6.0",
- "phpunit/phpunit": "^7.0",
- "sebastian/comparator": "^2.0",
- "sebastian/diff": "^3.0"
- },
- "require-dev": {
- "codeception/specify": "*",
- "vlucas/phpdotenv": "^2.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Codeception\\PHPUnit\\": "src\\"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Davert",
- "email": "davert.php@resend.cc"
- }
- ],
- "description": "PHPUnit classes used by Codeception",
- "time": "2018-03-16T10:18:33+00:00"
- },
- {
- "name": "codeception/stub",
- "version": "1.0.2",
- "source": {
- "type": "git",
- "url": "https://github.com/Codeception/Stub.git",
- "reference": "95fb7a36b81890dd2e5163e7ab31310df6f1bb99"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Codeception/Stub/zipball/95fb7a36b81890dd2e5163e7ab31310df6f1bb99",
- "reference": "95fb7a36b81890dd2e5163e7ab31310df6f1bb99",
- "shasum": ""
- },
- "require": {
- "phpunit/phpunit-mock-objects": ">2.3 <7.0"
- },
- "require-dev": {
- "phpunit/phpunit": ">=4.8 <8.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Codeception\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Flexible Stub wrapper for PHPUnit's Mock Builder",
- "time": "2018-02-18T13:56:56+00:00"
+ "time": "2017-07-10T19:45:09+00:00"
},
{
"name": "doctrine/instantiator",
@@ -626,40 +558,28 @@
},
{
"name": "facebook/webdriver",
- "version": "1.5.0",
+ "version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/facebook/php-webdriver.git",
- "reference": "86b5ca2f67173c9d34340845dd690149c886a605"
+ "reference": "1c98108ba3eb435b681655764de11502a0653705"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/86b5ca2f67173c9d34340845dd690149c886a605",
- "reference": "86b5ca2f67173c9d34340845dd690149c886a605",
+ "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/1c98108ba3eb435b681655764de11502a0653705",
+ "reference": "1c98108ba3eb435b681655764de11502a0653705",
"shasum": ""
},
"require": {
- "ext-curl": "*",
- "ext-zip": "*",
- "php": "^5.6 || ~7.0",
- "symfony/process": "^2.8 || ^3.1 || ^4.0"
+ "php": ">=5.3.19"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^2.0",
- "guzzle/guzzle": "^3.4.1",
- "php-coveralls/php-coveralls": "^1.0.2",
- "php-mock/php-mock-phpunit": "^1.1",
- "phpunit/phpunit": "^5.7",
- "sebastian/environment": "^1.3.4 || ^2.0 || ^3.0",
- "squizlabs/php_codesniffer": "^2.6",
- "symfony/var-dumper": "^3.3 || ^4.0"
+ "phpunit/phpunit": "4.6.*"
},
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-community": "1.5-dev"
- }
+ "suggest": {
+ "phpdocumentor/phpdocumentor": "2.*"
},
+ "type": "library",
"autoload": {
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
@@ -669,7 +589,7 @@
"license": [
"Apache-2.0"
],
- "description": "A PHP client for Selenium WebDriver",
+ "description": "A PHP client for WebDriver",
"homepage": "https://github.com/facebook/php-webdriver",
"keywords": [
"facebook",
@@ -677,20 +597,20 @@
"selenium",
"webdriver"
],
- "time": "2017-11-15T11:08:09+00:00"
+ "time": "2015-12-31T15:58:49+00:00"
},
{
"name": "guzzlehttp/guzzle",
- "version": "6.3.0",
+ "version": "6.3.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
- "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699"
+ "reference": "68d0ea14d5a3f42a20e87632a5f84931e2709c90"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699",
- "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/68d0ea14d5a3f42a20e87632a5f84931e2709c90",
+ "reference": "68d0ea14d5a3f42a20e87632a5f84931e2709c90",
"shasum": ""
},
"require": {
@@ -700,7 +620,7 @@
},
"require-dev": {
"ext-curl": "*",
- "phpunit/phpunit": "^4.0 || ^5.0",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4",
"psr/log": "^1.0"
},
"suggest": {
@@ -709,7 +629,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "6.2-dev"
+ "dev-master": "6.3-dev"
}
},
"autoload": {
@@ -742,7 +662,7 @@
"rest",
"web service"
],
- "time": "2017-06-22T18:50:49+00:00"
+ "time": "2018-03-26T16:33:04+00:00"
},
{
"name": "guzzlehttp/promises",
@@ -1161,23 +1081,23 @@
},
{
"name": "phpspec/prophecy",
- "version": "1.7.5",
+ "version": "1.7.6",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
- "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401"
+ "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401",
- "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
+ "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
- "sebastian/comparator": "^1.1|^2.0",
+ "sebastian/comparator": "^1.1|^2.0|^3.0",
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
},
"require-dev": {
@@ -1220,44 +1140,44 @@
"spy",
"stub"
],
- "time": "2018-02-19T10:16:54+00:00"
+ "time": "2018-04-18T13:57:24+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "6.0.1",
+ "version": "5.3.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba"
+ "reference": "c89677919c5dd6d3b3852f230a663118762218ac"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f8ca4b604baf23dab89d87773c28cc07405189ba",
- "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac",
+ "reference": "c89677919c5dd6d3b3852f230a663118762218ac",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-xmlwriter": "*",
- "php": "^7.1",
+ "php": "^7.0",
"phpunit/php-file-iterator": "^1.4.2",
"phpunit/php-text-template": "^1.2.1",
- "phpunit/php-token-stream": "^3.0",
+ "phpunit/php-token-stream": "^2.0.1",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.0",
"sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1"
},
"require-dev": {
- "phpunit/phpunit": "^7.0"
+ "phpunit/phpunit": "^6.0"
},
"suggest": {
- "ext-xdebug": "^2.6.0"
+ "ext-xdebug": "^2.5.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "6.0-dev"
+ "dev-master": "5.3.x-dev"
}
},
"autoload": {
@@ -1283,7 +1203,7 @@
"testing",
"xunit"
],
- "time": "2018-02-02T07:01:41+00:00"
+ "time": "2018-04-06T15:36:58+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1375,28 +1295,28 @@
},
{
"name": "phpunit/php-timer",
- "version": "2.0.0",
+ "version": "1.0.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f"
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f",
- "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
+ "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "php": "^5.3.3 || ^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^7.0"
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-master": "1.0-dev"
}
},
"autoload": {
@@ -1411,7 +1331,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
+ "email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
@@ -1420,33 +1340,33 @@
"keywords": [
"timer"
],
- "time": "2018-02-01T13:07:23+00:00"
+ "time": "2017-02-26T11:10:40+00:00"
},
{
"name": "phpunit/php-token-stream",
- "version": "3.0.0",
+ "version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace"
+ "reference": "791198a2c6254db10131eecfe8c06670700904db"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace",
- "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
+ "reference": "791198a2c6254db10131eecfe8c06670700904db",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
- "php": "^7.1"
+ "php": "^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^7.0"
+ "phpunit/phpunit": "^6.2.4"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "2.0-dev"
}
},
"autoload": {
@@ -1469,20 +1389,20 @@
"keywords": [
"tokenizer"
],
- "time": "2018-02-01T13:16:43+00:00"
+ "time": "2017-11-27T05:48:46+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "7.0.2",
+ "version": "6.2.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9"
+ "reference": "ff3a76a58ac293657808aefd58c8aaf05945f4d9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9",
- "reference": "e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ff3a76a58ac293657808aefd58c8aaf05945f4d9",
+ "reference": "ff3a76a58ac293657808aefd58c8aaf05945f4d9",
"shasum": ""
},
"require": {
@@ -1491,31 +1411,35 @@
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
- "myclabs/deep-copy": "^1.6.1",
+ "myclabs/deep-copy": "^1.3",
"phar-io/manifest": "^1.0.1",
"phar-io/version": "^1.0",
- "php": "^7.1",
+ "php": "^7.0",
"phpspec/prophecy": "^1.7",
- "phpunit/php-code-coverage": "^6.0",
- "phpunit/php-file-iterator": "^1.4.3",
- "phpunit/php-text-template": "^1.2.1",
- "phpunit/php-timer": "^2.0",
- "phpunit/phpunit-mock-objects": "^6.0",
- "sebastian/comparator": "^2.1",
- "sebastian/diff": "^3.0",
- "sebastian/environment": "^3.1",
+ "phpunit/php-code-coverage": "^5.2",
+ "phpunit/php-file-iterator": "^1.4",
+ "phpunit/php-text-template": "^1.2",
+ "phpunit/php-timer": "^1.0.6",
+ "phpunit/phpunit-mock-objects": "^4.0",
+ "sebastian/comparator": "^2.0",
+ "sebastian/diff": "^1.4.3",
+ "sebastian/environment": "^3.0.2",
"sebastian/exporter": "^3.1",
- "sebastian/global-state": "^2.0",
- "sebastian/object-enumerator": "^3.0.3",
+ "sebastian/global-state": "^1.1 || ^2.0",
+ "sebastian/object-enumerator": "^3.0.2",
"sebastian/resource-operations": "^1.0",
- "sebastian/version": "^2.0.1"
+ "sebastian/version": "^2.0"
+ },
+ "conflict": {
+ "phpdocumentor/reflection-docblock": "3.0.2",
+ "phpunit/dbunit": "<3.0"
},
"require-dev": {
"ext-pdo": "*"
},
"suggest": {
"ext-xdebug": "*",
- "phpunit/php-invoker": "^2.0"
+ "phpunit/php-invoker": "^1.1"
},
"bin": [
"phpunit"
@@ -1523,7 +1447,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "7.0-dev"
+ "dev-master": "6.2.x-dev"
}
},
"autoload": {
@@ -1549,30 +1473,33 @@
"testing",
"xunit"
],
- "time": "2018-02-26T07:03:12+00:00"
+ "time": "2017-08-03T13:59:28+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
- "version": "6.0.1",
+ "version": "4.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
- "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53"
+ "reference": "2f789b59ab89669015ad984afa350c4ec577ade0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/e3249dedc2d99259ccae6affbc2684eac37c2e53",
- "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/2f789b59ab89669015ad984afa350c4ec577ade0",
+ "reference": "2f789b59ab89669015ad984afa350c4ec577ade0",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.5",
- "php": "^7.1",
+ "php": "^7.0",
"phpunit/php-text-template": "^1.2.1",
- "sebastian/exporter": "^3.1"
+ "sebastian/exporter": "^3.0"
+ },
+ "conflict": {
+ "phpunit/phpunit": "<6.0"
},
"require-dev": {
- "phpunit/phpunit": "^7.0"
+ "phpunit/phpunit": "^6.0"
},
"suggest": {
"ext-soap": "*"
@@ -1580,7 +1507,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "6.0.x-dev"
+ "dev-master": "4.0.x-dev"
}
},
"autoload": {
@@ -1595,7 +1522,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de",
+ "email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
@@ -1605,7 +1532,7 @@
"mock",
"xunit"
],
- "time": "2018-02-15T05:27:38+00:00"
+ "time": "2017-08-03T14:08:16+00:00"
},
{
"name": "psr/http-message",
@@ -1657,6 +1584,53 @@
],
"time": "2016-08-06T14:39:51+00:00"
},
+ {
+ "name": "psr/log",
+ "version": "1.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+ "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "time": "2016-10-10T12:19:37+00:00"
+ },
{
"name": "sebastian/code-unit-reverse-lookup",
"version": "1.0.1",
@@ -1704,30 +1678,30 @@
},
{
"name": "sebastian/comparator",
- "version": "2.1.3",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9"
+ "reference": "20f84f468cb67efee293246e6a09619b891f55f0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9",
- "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/20f84f468cb67efee293246e6a09619b891f55f0",
+ "reference": "20f84f468cb67efee293246e6a09619b891f55f0",
"shasum": ""
},
"require": {
"php": "^7.0",
- "sebastian/diff": "^2.0 || ^3.0",
- "sebastian/exporter": "^3.1"
+ "sebastian/diff": "^1.2",
+ "sebastian/exporter": "^3.0"
},
"require-dev": {
- "phpunit/phpunit": "^6.4"
+ "phpunit/phpunit": "^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.1.x-dev"
+ "dev-master": "2.0.x-dev"
}
},
"autoload": {
@@ -1758,39 +1732,38 @@
}
],
"description": "Provides the functionality to compare PHP values for equality",
- "homepage": "https://github.com/sebastianbergmann/comparator",
+ "homepage": "http://www.github.com/sebastianbergmann/comparator",
"keywords": [
"comparator",
"compare",
"equality"
],
- "time": "2018-02-01T13:46:46+00:00"
+ "time": "2017-03-03T06:26:08+00:00"
},
{
"name": "sebastian/diff",
- "version": "3.0.0",
+ "version": "1.4.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8"
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8",
- "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
+ "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
"shasum": ""
},
"require": {
- "php": "^7.1"
+ "php": "^5.3.3 || ^7.0"
},
"require-dev": {
- "phpunit/phpunit": "^7.0",
- "symfony/process": "^2 || ^3.3 || ^4"
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "1.4-dev"
}
},
"autoload": {
@@ -1815,12 +1788,9 @@
"description": "Diff implementation",
"homepage": "https://github.com/sebastianbergmann/diff",
"keywords": [
- "diff",
- "udiff",
- "unidiff",
- "unified diff"
+ "diff"
],
- "time": "2018-02-01T13:45:15+00:00"
+ "time": "2017-05-22T07:24:03+00:00"
},
{
"name": "sebastian/environment",
@@ -2220,27 +2190,72 @@
"homepage": "https://github.com/sebastianbergmann/version",
"time": "2016-10-03T07:35:21+00:00"
},
+ {
+ "name": "stecman/symfony-console-completion",
+ "version": "0.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/stecman/symfony-console-completion.git",
+ "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/stecman/symfony-console-completion/zipball/5461d43e53092b3d3b9dbd9d999f2054730f4bbb",
+ "reference": "5461d43e53092b3d3b9dbd9d999f2054730f4bbb",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2",
+ "symfony/console": "~2.3 || ~3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Stecman\\Component\\Symfony\\Console\\BashCompletion\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Stephen Holdaway",
+ "email": "stephen@stecman.co.nz"
+ }
+ ],
+ "description": "Automatic BASH completion for Symfony Console Component based applications.",
+ "time": "2016-02-24T05:08:54+00:00"
+ },
{
"name": "symfony/browser-kit",
- "version": "v4.0.6",
+ "version": "v3.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
- "reference": "fee0fcd501304b1c3190f6293f650cceb738a353"
+ "reference": "840bb6f0d5b3701fd768b68adf7193c2d0f98f79"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/browser-kit/zipball/fee0fcd501304b1c3190f6293f650cceb738a353",
- "reference": "fee0fcd501304b1c3190f6293f650cceb738a353",
+ "url": "https://api.github.com/repos/symfony/browser-kit/zipball/840bb6f0d5b3701fd768b68adf7193c2d0f98f79",
+ "reference": "840bb6f0d5b3701fd768b68adf7193c2d0f98f79",
"shasum": ""
},
"require": {
- "php": "^7.1.3",
- "symfony/dom-crawler": "~3.4|~4.0"
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/dom-crawler": "~2.8|~3.0|~4.0"
},
"require-dev": {
- "symfony/css-selector": "~3.4|~4.0",
- "symfony/process": "~3.4|~4.0"
+ "symfony/css-selector": "~2.8|~3.0|~4.0",
+ "symfony/process": "~2.8|~3.0|~4.0"
},
"suggest": {
"symfony/process": ""
@@ -2248,7 +2263,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2275,24 +2290,25 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com",
- "time": "2018-01-03T07:38:00+00:00"
+ "time": "2018-03-19T22:32:39+00:00"
},
{
"name": "symfony/console",
- "version": "v4.0.6",
+ "version": "v3.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "555c8dbe0ae9e561740451eabdbed2cc554b6a51"
+ "reference": "d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/555c8dbe0ae9e561740451eabdbed2cc554b6a51",
- "reference": "555c8dbe0ae9e561740451eabdbed2cc554b6a51",
+ "url": "https://api.github.com/repos/symfony/console/zipball/d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf",
+ "reference": "d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf",
"shasum": ""
},
"require": {
- "php": "^7.1.3",
+ "php": "^5.5.9|>=7.0.8",
+ "symfony/debug": "~2.8|~3.0|~4.0",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
@@ -2301,11 +2317,11 @@
},
"require-dev": {
"psr/log": "~1.0",
- "symfony/config": "~3.4|~4.0",
+ "symfony/config": "~3.3|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
- "symfony/event-dispatcher": "~3.4|~4.0",
+ "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
"symfony/lock": "~3.4|~4.0",
- "symfony/process": "~3.4|~4.0"
+ "symfony/process": "~3.3|~4.0"
},
"suggest": {
"psr/log": "For using the console logger",
@@ -2316,7 +2332,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2343,29 +2359,29 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2018-02-26T15:55:47+00:00"
+ "time": "2018-04-03T05:22:50+00:00"
},
{
"name": "symfony/css-selector",
- "version": "v4.0.6",
+ "version": "v3.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "c69f1e93aa898fd9fec627ebef467188151c8dc2"
+ "reference": "519a80d7c1d95c6cc0b67f686d15fe27c6910de0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/c69f1e93aa898fd9fec627ebef467188151c8dc2",
- "reference": "c69f1e93aa898fd9fec627ebef467188151c8dc2",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/519a80d7c1d95c6cc0b67f686d15fe27c6910de0",
+ "reference": "519a80d7c1d95c6cc0b67f686d15fe27c6910de0",
"shasum": ""
},
"require": {
- "php": "^7.1.3"
+ "php": "^5.5.9|>=7.0.8"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2396,28 +2412,84 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
- "time": "2018-02-03T14:58:37+00:00"
+ "time": "2018-03-19T22:32:39+00:00"
+ },
+ {
+ "name": "symfony/debug",
+ "version": "v4.0.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/debug.git",
+ "reference": "5961d02d48828671f5d8a7805e06579d692f6ede"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/debug/zipball/5961d02d48828671f5d8a7805e06579d692f6ede",
+ "reference": "5961d02d48828671f5d8a7805e06579d692f6ede",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1.3",
+ "psr/log": "~1.0"
+ },
+ "conflict": {
+ "symfony/http-kernel": "<3.4"
+ },
+ "require-dev": {
+ "symfony/http-kernel": "~3.4|~4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Debug\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Debug Component",
+ "homepage": "https://symfony.com",
+ "time": "2018-04-03T05:24:00+00:00"
},
{
"name": "symfony/dom-crawler",
- "version": "v4.0.6",
+ "version": "v3.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "26726ddc01601dc9393f2afc3369ce1ca64e4537"
+ "reference": "1a4cffeb059226ff6bee9f48acb388faf674afff"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/26726ddc01601dc9393f2afc3369ce1ca64e4537",
- "reference": "26726ddc01601dc9393f2afc3369ce1ca64e4537",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/1a4cffeb059226ff6bee9f48acb388faf674afff",
+ "reference": "1a4cffeb059226ff6bee9f48acb388faf674afff",
"shasum": ""
},
"require": {
- "php": "^7.1.3",
+ "php": "^5.5.9|>=7.0.8",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
- "symfony/css-selector": "~3.4|~4.0"
+ "symfony/css-selector": "~2.8|~3.0|~4.0"
},
"suggest": {
"symfony/css-selector": ""
@@ -2425,7 +2497,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2452,34 +2524,34 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
- "time": "2018-02-22T10:50:29+00:00"
+ "time": "2018-03-19T22:32:39+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v4.0.6",
+ "version": "v3.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "85eaf6a8ec915487abac52e133efc4a268204428"
+ "reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/85eaf6a8ec915487abac52e133efc4a268204428",
- "reference": "85eaf6a8ec915487abac52e133efc4a268204428",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fdd5abcebd1061ec647089c6c41a07ed60af09f8",
+ "reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8",
"shasum": ""
},
"require": {
- "php": "^7.1.3"
+ "php": "^5.5.9|>=7.0.8"
},
"conflict": {
- "symfony/dependency-injection": "<3.4"
+ "symfony/dependency-injection": "<3.3"
},
"require-dev": {
"psr/log": "~1.0",
- "symfony/config": "~3.4|~4.0",
- "symfony/dependency-injection": "~3.4|~4.0",
- "symfony/expression-language": "~3.4|~4.0",
- "symfony/stopwatch": "~3.4|~4.0"
+ "symfony/config": "~2.8|~3.0|~4.0",
+ "symfony/dependency-injection": "~3.3|~4.0",
+ "symfony/expression-language": "~2.8|~3.0|~4.0",
+ "symfony/stopwatch": "~2.8|~3.0|~4.0"
},
"suggest": {
"symfony/dependency-injection": "",
@@ -2488,7 +2560,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2515,29 +2587,29 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
- "time": "2018-02-14T14:11:10+00:00"
+ "time": "2018-04-06T07:35:25+00:00"
},
{
"name": "symfony/finder",
- "version": "v4.0.6",
+ "version": "v3.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f"
+ "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/44a796d2ecc2a16a5fc8f2956a34ee617934d55f",
- "reference": "44a796d2ecc2a16a5fc8f2956a34ee617934d55f",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/bd14efe8b1fabc4de82bf50dce62f05f9a102433",
+ "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433",
"shasum": ""
},
"require": {
- "php": "^7.1.3"
+ "php": "^5.5.9|>=7.0.8"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2564,7 +2636,7 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2018-03-05T18:28:26+00:00"
+ "time": "2018-04-04T05:07:11+00:00"
},
{
"name": "symfony/polyfill-mbstring",
@@ -2625,71 +2697,22 @@
],
"time": "2018-01-30T19:27:44+00:00"
},
- {
- "name": "symfony/process",
- "version": "v4.0.6",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/process.git",
- "reference": "6ed08502a7c9559da8e60ea343bdbd19c3350b3e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/6ed08502a7c9559da8e60ea343bdbd19c3350b3e",
- "reference": "6ed08502a7c9559da8e60ea343bdbd19c3350b3e",
- "shasum": ""
- },
- "require": {
- "php": "^7.1.3"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "4.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Process\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony Process Component",
- "homepage": "https://symfony.com",
- "time": "2018-02-19T12:18:43+00:00"
- },
{
"name": "symfony/yaml",
- "version": "v4.0.6",
+ "version": "v3.4.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "de5f125ea39de846b90b313b2cfb031a0152d223"
+ "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/de5f125ea39de846b90b313b2cfb031a0152d223",
- "reference": "de5f125ea39de846b90b313b2cfb031a0152d223",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/a42f9da85c7c38d59f5e53f076fe81a091f894d0",
+ "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0",
"shasum": ""
},
"require": {
- "php": "^7.1.3"
+ "php": "^5.5.9|>=7.0.8"
},
"conflict": {
"symfony/console": "<3.4"
@@ -2703,7 +2726,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -2730,7 +2753,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2018-02-19T20:08:53+00:00"
+ "time": "2018-04-03T05:14:20+00:00"
},
{
"name": "theseer/tokenizer",
diff --git a/src/TranslatableBehavior.php b/src/TranslatableBehavior.php
new file mode 100644
index 0000000..63935d1
--- /dev/null
+++ b/src/TranslatableBehavior.php
@@ -0,0 +1,239 @@
+
+ * @since 1.0
+ */
+class TranslatableBehavior extends Behavior
+{
+ /**
+ * The owner of this behavior.
+ *
+ * @var BaseActiveRecord
+ */
+ public $owner;
+
+ /**
+ * Name of translation relation in main model.
+ *
+ * @var string
+ */
+ public $translationRelationName = 'translations';
+
+ /**
+ * Name of attribute in translation model that contains language.
+ *
+ * @var string
+ */
+ public $translationLanguageAttrName = 'language';
+
+ /**
+ * List of attribute names from translation model that should be translated.
+ *
+ * @var string[]
+ */
+ public $translationAttributeList;
+
+ /**
+ * Patter for the attribute name in validation errors list.
+ *
+ * @var string
+ */
+ public $attributeNamePattern = '%name% [%language%]';
+
+ /**
+ * Temp storage for translation entity objects.
+ *
+ * @var array
+ */
+ protected $translationsBuffer = [];
+
+
+ /**
+ * Translate model to needed language.
+ *
+ * Alias for @see getTranslation() method.
+ *
+ * @param null|string $language
+ *
+ * @return \yii\db\ActiveRecord|BaseActiveRecord
+ */
+ final public function translateTo($language = null)
+ {
+ return $this->getTranslation($language);
+ }
+
+ /**
+ * Returns translation entity object for needed language.
+ *
+ * @param null|string $language By default uses application current language.
+ *
+ * @return \yii\db\ActiveRecord|BaseActiveRecord
+ */
+ public function getTranslation($language = null)
+ {
+ $language = $language ?: Yii::$app->language;
+ $translations = $this->getModelTranslations();
+
+ // search translation by language in exists translations
+ foreach ($translations as $translation) {
+ // if translation exists - return it
+ if ($translation->getAttribute($this->translationLanguageAttrName) === $language) {
+ $this->translationsBuffer[] = $translation;
+
+ return $translation;
+ }
+ }
+
+ // if translation doesn't exist - create and return
+ $translationEntityClass = $this->owner->getRelation($this->translationRelationName)->modelClass;
+
+ /* @var BaseActiveRecord $translation */
+ $translation = new $translationEntityClass();
+ $translation->setAttribute($this->translationLanguageAttrName, $language);
+ $translations[] = $translation;
+ $this->translationsBuffer = $translations;
+ $this->owner->populateRelation($this->translationRelationName, $translations);
+
+ return $translation;
+ }
+
+ /**
+ * Check whether translation exists.
+ *
+ * @param null|string $language By default uses application current language.
+ *
+ * @return bool
+ */
+ public function hasTranslation($language = null)
+ {
+ $language = $language ?: Yii::$app->language;
+
+ foreach ($this->getModelTranslations() as $translation) {
+ if ($translation->getAttribute($this->translationLanguageAttrName) === $language) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function events()
+ {
+ return [
+ BaseActiveRecord::EVENT_AFTER_VALIDATE => 'afterValidate',
+ BaseActiveRecord::EVENT_AFTER_INSERT => 'afterSave',
+ BaseActiveRecord::EVENT_AFTER_UPDATE => 'afterSave',
+ ];
+ }
+
+ /**
+ * Triggers after validation of the main model.
+ */
+ public function afterValidate()
+ {
+ $translations = $this->getModelTranslations();
+
+ $isValid = Model::validateMultiple($translations, $this->translationAttributeList);
+
+ if (!$isValid) {
+ foreach ($translations as $translation) {
+ foreach ($translation->getErrors() as $attribute => $errors) {
+ $attribute = strtr($this->attributeNamePattern, [
+ '%name%' => $attribute,
+ '%language%' => $translation->{$this->translationLanguageAttrName},
+ ]);
+
+ if (is_array($errors)) {
+ foreach ($errors as $error) {
+ $this->owner->addError($attribute, $error);
+ }
+ } else {
+ $this->owner->addError($attribute, $errors);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Triggers after saving of the main model.
+ */
+ public function afterSave()
+ {
+ foreach ($this->translationsBuffer as $translation) {
+ $this->owner->link($this->translationRelationName, $translation);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canGetProperty($name, $checkVars = true)
+ {
+ return in_array($name, $this->translationAttributeList)
+ ?: $this->owner->canGetProperty($name, $checkVars);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function canSetProperty($name, $checkVars = true)
+ {
+ return in_array($name, $this->translationAttributeList)
+ ?: $this->owner->canSetProperty($name, $checkVars);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __get($name)
+ {
+ $translation = $this->getTranslation();
+
+ if ($translation->hasAttribute($name)) {
+ return $translation->getAttribute($name);
+ }
+
+ return $this->owner->$name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __set($name, $value)
+ {
+ $translation = $this->getTranslation();
+
+ if ($translation->hasAttribute($name)) {
+ $translation->setAttribute($name, $value);
+ }
+
+ $this->owner->$name = $value;
+ }
+
+ /**
+ * @return \yii\db\ActiveRecord[]
+ */
+ protected function getModelTranslations()
+ {
+ return $this->owner->{$this->translationRelationName};
+ }
+}
diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php
new file mode 100644
index 0000000..9d4be9a
--- /dev/null
+++ b/tests/_bootstrap.php
@@ -0,0 +1,15 @@
+ 'test-app',
+ 'class' => yii\console\Application::className(),
+ 'language' => 'en',
+
+ 'basePath' => Yii::getAlias('@tests'),
+ 'vendorPath' => Yii::getAlias('@vendor'),
+ 'runtimePath' => Yii::getAlias('@tests/_output'),
+
+ 'bootstrap' => [],
+ 'components' => [
+ 'db' => require __DIR__ . '/db.php',
+ ],
+ 'params' => [],
+];
diff --git a/tests/_config/db.php b/tests/_config/db.php
new file mode 100644
index 0000000..ca32fc8
--- /dev/null
+++ b/tests/_config/db.php
@@ -0,0 +1,9 @@
+ yii\db\Connection::className(),
+ 'dsn' => 'sqlite:' . Yii::getAlias('@tests/_output/test.db'),
+ 'username' => '',
+ 'password' => '',
+ 'charset' => 'utf8',
+];
diff --git a/tests/_data/dump.sql b/tests/_data/dump.sql
new file mode 100644
index 0000000..8df21f8
--- /dev/null
+++ b/tests/_data/dump.sql
@@ -0,0 +1,21 @@
+PRAGMA foreign_keys = on;
+BEGIN TRANSACTION;
+
+-- Table: product
+DROP TABLE IF EXISTS product;
+CREATE TABLE product(
+ id INTEGER PRIMARY KEY AUTOINCREMENT
+);
+
+-- Table: product_translation
+DROP TABLE IF EXISTS product_translation;
+CREATE TABLE product_translation(
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ product_id INTEGER NOT NULL,
+ language STING NOT NULL,
+ title STRING NOT NULL,
+ description TEXT NOT NULL
+);
+
+COMMIT TRANSACTION;
+PRAGMA foreign_keys = on;
diff --git a/tests/_output/.gitignore b/tests/_output/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/tests/_output/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/tests/_support/.gitignore b/tests/_support/.gitignore
new file mode 100644
index 0000000..36e264c
--- /dev/null
+++ b/tests/_support/.gitignore
@@ -0,0 +1 @@
+_generated
diff --git a/tests/_support/Helper/Unit.php b/tests/_support/Helper/Unit.php
new file mode 100644
index 0000000..4d27aa3
--- /dev/null
+++ b/tests/_support/Helper/Unit.php
@@ -0,0 +1,10 @@
+
+ * @since 1.0
+ */
+class Product extends ActiveRecord
+{
+ /**
+ * {@inheritdoc}
+ */
+ public static function tableName()
+ {
+ return 'product';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function behaviors()
+ {
+ return [
+ 'translatable' => [
+ 'class' => TranslatableBehavior::className(),
+ 'translationAttributeList' => [
+ 'title',
+ 'description',
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * Relations for translations.
+ *
+ * @return \yii\db\ActiveQuery
+ */
+ public function getTranslations()
+ {
+ return $this->hasMany(ProductTranslation::className(), ['product_id' => 'id']);
+ }
+}
diff --git a/tests/entities/ProductTranslation.php b/tests/entities/ProductTranslation.php
new file mode 100644
index 0000000..166d676
--- /dev/null
+++ b/tests/entities/ProductTranslation.php
@@ -0,0 +1,47 @@
+
+ * @since 1.0
+ */
+class ProductTranslation extends ActiveRecord
+{
+ /**
+ * {@inheritdoc}
+ */
+ public static function tableName()
+ {
+ return 'product_translation';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rules()
+ {
+ return [
+ ['title', 'required'],
+ ['title', 'string'],
+
+ ['description', 'required'],
+ ['description', 'string'],
+ ];
+ }
+}
diff --git a/tests/unit.suite.yml b/tests/unit.suite.yml
new file mode 100644
index 0000000..fbae2b6
--- /dev/null
+++ b/tests/unit.suite.yml
@@ -0,0 +1,7 @@
+class_name: UnitTester
+bootstrap: false
+modules:
+ enabled:
+ - Db
+ - Asserts
+ - Yii2
diff --git a/tests/unit/DbTestCase.php b/tests/unit/DbTestCase.php
new file mode 100644
index 0000000..d53fc10
--- /dev/null
+++ b/tests/unit/DbTestCase.php
@@ -0,0 +1,52 @@
+
+ * @since 1.0
+ */
+class DbTestCase extends TestCase
+{
+ use FixtureTrait;
+
+ /**
+ * @var \UnitTester
+ */
+ protected $tester;
+
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function _before()
+ {
+ parent::_before();
+ $this->loadFixtures();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function _after()
+ {
+ $this->unloadFixtures();
+ parent::_after();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function fixtures()
+ {
+ }
+}
diff --git a/tests/unit/TestCase.php b/tests/unit/TestCase.php
new file mode 100644
index 0000000..2717d8a
--- /dev/null
+++ b/tests/unit/TestCase.php
@@ -0,0 +1,22 @@
+
+ * @since 1.0
+ */
+class TestCase extends \Codeception\Test\Unit
+{
+ /**
+ * @var \UnitTester
+ */
+ protected $tester;
+}
diff --git a/tests/unit/TranslatableBehaviorTest.php b/tests/unit/TranslatableBehaviorTest.php
new file mode 100644
index 0000000..53b66d3
--- /dev/null
+++ b/tests/unit/TranslatableBehaviorTest.php
@@ -0,0 +1,130 @@
+
+ * @since 1.0
+ */
+class TranslatableBehaviorTest extends TestCase
+{
+ /**
+ * @var Product
+ */
+ private $product;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function _before()
+ {
+ $this->product = new Product();
+ }
+
+ public function testCreateModel()
+ {
+ // english
+ $this->product->title = '[en] Test title';
+ $this->product->description = '[en] Test description';
+
+ // french
+ $this->product->translateTo('fr')->title = '[fr] Test title';
+ $this->product->translateTo('fr')->description = '[fr] Test description';
+
+ $this->product->insert();
+
+ $this->tester->seeRecord(ProductTranslation::className(), [
+ 'language' => 'en',
+ 'title' => '[en] Test title',
+ 'description' => '[en] Test description',
+ ]);
+ $this->tester->seeRecord(ProductTranslation::className(), [
+ 'language' => 'fr',
+ 'title' => '[fr] Test title',
+ 'description' => '[fr] Test description'
+ ]);
+ }
+
+ public function testUpdateModel()
+ {
+ // english
+ $this->product->title = '[en] New product';
+ $this->product->description = '[en] This is new product';
+
+ // french
+ $this->product->translateTo('fr')->title = '[fr] New product';
+ $this->product->translateTo('fr')->description = '[fr] This is new product';
+
+ $this->product->insert();
+
+ $product = Product::findOne($this->product->id);
+
+ // english
+ $product->getTranslation()->title = '[en] Updated product';
+ $product->getTranslation()->description = '[en] This is updated product';
+
+ // french
+ $product->translateTo('fr')->title = '[fr] Updated product';
+ $product->translateTo('fr')->description = '[fr] This is updated product';
+
+ $product->update();
+
+ $this->tester->seeRecord(ProductTranslation::className(), [
+ 'language' => 'en',
+ 'title' => '[en] Updated product',
+ 'description' => '[en] This is updated product',
+ ]);
+ $this->tester->seeRecord(ProductTranslation::className(), [
+ 'language' => 'fr',
+ 'title' => '[fr] Updated product',
+ 'description' => '[fr] This is updated product',
+ ]);
+ }
+
+ public function testValidationErrors()
+ {
+ $this->product->title = null;
+ $this->product->description = null;
+ $this->product->translateTo('fr')->title = null;
+ $this->product->translateTo('fr')->description = null;
+ $this->product->validate();
+
+ $this->assertTrue($this->product->hasErrors());
+ $this->assertSame(
+ [
+ 'title [en]' => ['Title cannot be blank.'],
+ 'description [en]' => ['Description cannot be blank.'],
+
+ 'title [fr]' => ['Title cannot be blank.'],
+ 'description [fr]' => ['Description cannot be blank.'],
+ ],
+ $this->product->getErrors()
+ );
+ }
+
+ public function testModelHasProperty()
+ {
+ $this->assertTrue($this->product->hasProperty('title'));
+ $this->assertTrue($this->product->hasProperty('description'));
+ }
+
+ public function testHasTranslation()
+ {
+ $this->assertFalse($this->product->hasTranslation());
+ $this->assertFalse($this->product->hasTranslation('fr'));
+
+ $this->product->getTranslation('fr');
+ $this->assertFalse($this->product->hasTranslation());
+ $this->assertTrue($this->product->hasTranslation('fr'));
+ }
+}