diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..b59f569
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/.idea
+/vendor
+/coverage
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
new file mode 100644
index 0000000..94630ba
--- /dev/null
+++ b/.scrutinizer.yml
@@ -0,0 +1,29 @@
+build:
+ environment:
+ php:
+ version: 5.5.12
+ dependencies:
+ before:
+ - sudo composer self-update && composer --version
+ - composer global require "fxp/composer-asset-plugin:1.0.0-beta4"
+ tests:
+ override:
+ - phpunit
+imports:
+ - php
+checks:
+ php:
+ code_rating: true
+ duplication: true
+tools:
+ php_sim: false
+ php_cpd: false
+ php_pdepend: true
+ php_analyzer: true
+ php_changetracking: true
+ external_code_coverage:
+ timeout: 2100 # Timeout in seconds.
+filter:
+ excluded_paths:
+ - tests/*
+ - vendor/*
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..a16f5e0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,33 @@
+language: php
+
+php:
+ - 5.4
+ - 5.5
+ - 5.6
+ - hhvm
+ - hhvm-nightly
+
+matrix:
+ fast_finish: true
+ allow_failures:
+ - php: hhvm
+ - php: hhvm-nightly
+
+sudo: false
+
+cache:
+ directories:
+ - vendor
+
+install:
+ - travis_retry composer self-update && composer --version
+ - travis_retry composer global require "fxp/composer-asset-plugin:1.0.0-beta4"
+ - export PATH="$HOME/.composer/vendor/bin:$PATH"
+ - travis_retry composer install --prefer-dist --no-interaction
+
+script:
+ - phpunit --verbose --coverage-clover=coverage/coverage.clover
+
+after_script:
+ - travis_retry wget https://scrutinizer-ci.com/ocular.phar
+ - php ocular.phar code-coverage:upload --format=php-clover coverage/coverage.clover
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..460b28e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Revin Roman Borisovich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Module.php b/Module.php
new file mode 100755
index 0000000..55dfc1e
--- /dev/null
+++ b/Module.php
@@ -0,0 +1,39 @@
+getAuthManager();
+ $ItsMyCommentRule = new \rmrevin\yii\module\Comments\rbac\ItsMyComment();
+
+ $AuthManager->add($ItsMyCommentRule);
+
+ $AuthManager->add(new \yii\rbac\Role(['name' => Permission::CREATE]));
+ $AuthManager->add(new \yii\rbac\Role(['name' => Permission::UPDATE]));
+ $AuthManager->add(new \yii\rbac\Role(['name' => Permission::UPDATE_OWN, 'ruleName' => $ItsMyCommentRule->name]));
+ $AuthManager->add(new \yii\rbac\Role(['name' => Permission::DELETE]));
+ $AuthManager->add(new \yii\rbac\Role(['name' => Permission::DELETE_OWN, 'ruleName' => $ItsMyCommentRule->name]));
+
+ if ($this->userIdentityClass === null) {
+ $this->userIdentityClass = \Yii::$app->getUser()->identityClass;
+ }
+ }
+}
+
diff --git a/Permission.php b/Permission.php
new file mode 100644
index 0000000..cd8f5ad
--- /dev/null
+++ b/Permission.php
@@ -0,0 +1,21 @@
+ [
+ // ...
+ 'comments' => 'rmrevin\yii\module\Comments\Module',
+ ],
+ // ...
+];
+```
+
+In auth manager add rules:
+```php
+use \yii\rbac\Role;
+use \rmrevin\yii\module\Comments\Permission;
+use \rmrevin\yii\module\Comments\rbac\ItsMyComment;
+
+$AuthManager = \Yii::$app->getAuthManager();
+$ItsMyCommentRule = new ItsMyComment();
+
+// Rules
+$AuthManager->add($ItsMyCommentRule);
+
+// Permissions
+$AuthManager->add(new Role(['name' => Permission::CREATE]));
+$AuthManager->add(new Role(['name' => Permission::UPDATE]));
+$AuthManager->add(new Role(['name' => Permission::UPDATE_OWN, 'ruleName' => $ItsMyCommentRule->name]));
+$AuthManager->add(new Role(['name' => Permission::DELETE]));
+$AuthManager->add(new Role(['name' => Permission::DELETE_OWN, 'ruleName' => $ItsMyCommentRule->name]));
+```
+
+Usage
+-----
+In view
+```php
+
+// ...
+
+echo \rmrevin\yii\module\Comments\widgets\CommentListWidget::widget([
+ 'entity' => (string) 'photo-15', // type and id
+]);
+
+```
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..d0f8dac
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "rmrevin/yii2-comments",
+ "description": "Comments module for Yii2",
+ "keywords": [
+ "yii",
+ "comment",
+ "widget",
+ "module"
+ ],
+ "type": "yii2-extension",
+ "license": "MIT",
+ "minimum-stability": "stable",
+ "support": {
+ "issues": "https://github.com/rmrevin/yii2-comments/issues",
+ "source": "https://github.com/rmrevin/yii2-comments"
+ },
+ "authors": [
+ {
+ "name": "Roman Revin",
+ "email": "xgismox@gmail.com",
+ "homepage": "http://rmrevin.ru/"
+ }
+ ],
+ "require": {
+ "php": ">=5.4.0",
+
+ "yiisoft/yii2": "2.0.1",
+ "rmrevin/yii2-fontawesome": "2.6.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "rmrevin\\yii\\module\\Comments\\": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..015b28c
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,507 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "hash": "9e34b16bc28910661333fb994bc07682",
+ "packages": [
+ {
+ "name": "bower-asset/jquery",
+ "version": "2.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jquery/jquery.git",
+ "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jquery/jquery/zipball/8f2a9d9272d6ed7f32d3a484740ab342c02541e0",
+ "reference": "8f2a9d9272d6ed7f32d3a484740ab342c02541e0",
+ "shasum": ""
+ },
+ "require-dev": {
+ "bower-asset/qunit": "1.14.0",
+ "bower-asset/requirejs": "2.1.10",
+ "bower-asset/sinon": "1.8.1",
+ "bower-asset/sizzle": "2.1.1-patch2"
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": "dist/jquery.js",
+ "bower-asset-ignore": [
+ "**/.*",
+ "build",
+ "speed",
+ "test",
+ "*.md",
+ "AUTHORS.txt",
+ "Gruntfile.js",
+ "package.json"
+ ]
+ },
+ "license": [
+ "MIT"
+ ],
+ "keywords": [
+ "javascript",
+ "jquery",
+ "library"
+ ]
+ },
+ {
+ "name": "bower-asset/jquery.inputmask",
+ "version": "3.1.52",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/RobinHerbots/jquery.inputmask.git",
+ "reference": "6afe1c66735b96dd45303b67152917cbbfa4d087"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/6afe1c66735b96dd45303b67152917cbbfa4d087",
+ "reference": "6afe1c66735b96dd45303b67152917cbbfa4d087",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/jquery": ">=1.7"
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": [
+ "./dist/inputmask/jquery.inputmask.js",
+ "./dist/inputmask/jquery.inputmask.extensions.js",
+ "./dist/inputmask/jquery.inputmask.date.extensions.js",
+ "./dist/inputmask/jquery.inputmask.numeric.extensions.js",
+ "./dist/inputmask/jquery.inputmask.phone.extensions.js",
+ "./dist/inputmask/jquery.inputmask.regex.extensions.js"
+ ],
+ "bower-asset-ignore": [
+ "**/.*",
+ "qunit/",
+ "nuget/",
+ "tools/",
+ "js/",
+ "*.md",
+ "build.properties",
+ "build.xml",
+ "jquery.inputmask.jquery.json"
+ ]
+ },
+ "license": [
+ "http://opensource.org/licenses/mit-license.php"
+ ],
+ "description": "jquery.inputmask is a jquery plugin which create an input mask.",
+ "keywords": [
+ "form",
+ "input",
+ "inputmask",
+ "jQuery",
+ "mask",
+ "plugins"
+ ]
+ },
+ {
+ "name": "bower-asset/punycode",
+ "version": "v1.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/bestiejs/punycode.js.git",
+ "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3",
+ "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3",
+ "shasum": ""
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": "punycode.js",
+ "bower-asset-ignore": [
+ "coverage",
+ "tests",
+ ".*",
+ "component.json",
+ "Gruntfile.js",
+ "node_modules",
+ "package.json"
+ ]
+ }
+ },
+ {
+ "name": "bower-asset/yii2-pjax",
+ "version": "v2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/jquery-pjax.git",
+ "reference": "fb92be865c0fd6583714475cb7d629020749d73f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/fb92be865c0fd6583714475cb7d629020749d73f",
+ "reference": "fb92be865c0fd6583714475cb7d629020749d73f",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/jquery": ">=1.8"
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": "./jquery.pjax.js",
+ "bower-asset-ignore": [
+ ".travis.yml",
+ "Gemfile",
+ "Gemfile.lock",
+ "vendor/",
+ "script/",
+ "test/"
+ ]
+ }
+ },
+ {
+ "name": "cebe/markdown",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cebe/markdown.git",
+ "reference": "9d6c36d6623497523ed421a31d940bc1d7435578"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cebe/markdown/zipball/9d6c36d6623497523ed421a31d940bc1d7435578",
+ "reference": "9d6c36d6623497523ed421a31d940bc1d7435578",
+ "shasum": ""
+ },
+ "require": {
+ "lib-pcre": "*",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "cebe/indent": "*",
+ "facebook/xhprof": "*@dev",
+ "phpunit/phpunit": "3.7.*"
+ },
+ "bin": [
+ "bin/markdown"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "cebe\\markdown\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Carsten Brandt",
+ "email": "mail@cebe.cc",
+ "homepage": "http://cebe.cc/",
+ "role": "Creator"
+ }
+ ],
+ "description": "A super fast, highly extensible markdown parser for PHP",
+ "homepage": "https://github.com/cebe/markdown#readme",
+ "keywords": [
+ "extensible",
+ "fast",
+ "gfm",
+ "markdown",
+ "markdown-extra"
+ ],
+ "time": "2014-10-25 16:16:49"
+ },
+ {
+ "name": "ezyang/htmlpurifier",
+ "version": "v4.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ezyang/htmlpurifier.git",
+ "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/6f389f0f25b90d0b495308efcfa073981177f0fd",
+ "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "HTMLPurifier": "library/"
+ },
+ "files": [
+ "library/HTMLPurifier.composer.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "LGPL"
+ ],
+ "authors": [
+ {
+ "name": "Edward Z. Yang",
+ "email": "admin@htmlpurifier.org",
+ "homepage": "http://ezyang.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "Standards compliant HTML filter written in PHP",
+ "homepage": "http://htmlpurifier.org/",
+ "keywords": [
+ "html"
+ ],
+ "time": "2013-11-30 08:25:19"
+ },
+ {
+ "name": "fortawesome/font-awesome",
+ "version": "v4.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/FortAwesome/Font-Awesome.git",
+ "reference": "a65bd93d81e9e6bd5ebfa41757a4474960b973b4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/FortAwesome/Font-Awesome/zipball/a65bd93d81e9e6bd5ebfa41757a4474960b973b4",
+ "reference": "a65bd93d81e9e6bd5ebfa41757a4474960b973b4",
+ "shasum": ""
+ },
+ "require-dev": {
+ "jekyll": "1.0.2",
+ "lessc": "1.4.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.0.x-dev"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "OFL-1.1",
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dave Gandy",
+ "email": "dave@fontawesome.io",
+ "homepage": "http://twitter.com/davegandy",
+ "role": "Developer"
+ }
+ ],
+ "description": "The iconic font and CSS framework",
+ "homepage": "http://fontawesome.io/",
+ "keywords": [
+ "FontAwesome",
+ "awesome",
+ "bootstrap",
+ "font",
+ "icon"
+ ],
+ "time": "2014-08-26 16:36:44"
+ },
+ {
+ "name": "rmrevin/yii2-fontawesome",
+ "version": "2.6.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/rmrevin/yii2-fontawesome.git",
+ "reference": "8550d89131a87e823c93ebc15cdb69d6035d4548"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/rmrevin/yii2-fontawesome/zipball/8550d89131a87e823c93ebc15cdb69d6035d4548",
+ "reference": "8550d89131a87e823c93ebc15cdb69d6035d4548",
+ "shasum": ""
+ },
+ "require": {
+ "fortawesome/font-awesome": "4.2.*",
+ "php": ">=5.4.0",
+ "yiisoft/yii2": "2.0.*"
+ },
+ "type": "yii2-extension",
+ "autoload": {
+ "psr-4": {
+ "rmrevin\\yii\\fontawesome\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Roman Revin",
+ "email": "xgismox@gmail.com",
+ "homepage": "http://rmrevin.ru/"
+ }
+ ],
+ "description": "Asset Bundle for Yii2 with Font Awesome",
+ "keywords": [
+ "asset",
+ "awesome",
+ "bundle",
+ "font",
+ "yii"
+ ],
+ "time": "2014-12-10 20:49:45"
+ },
+ {
+ "name": "yiisoft/yii2",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-framework.git",
+ "reference": "7ed175b4b71ac96eaf86aadc322186ecdc58498d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/7ed175b4b71ac96eaf86aadc322186ecdc58498d",
+ "reference": "7ed175b4b71ac96eaf86aadc322186ecdc58498d",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/jquery": "2.1.*@stable | 1.11.*@stable",
+ "bower-asset/jquery.inputmask": "3.1.*",
+ "bower-asset/punycode": "1.3.*",
+ "bower-asset/yii2-pjax": ">=2.0.1",
+ "cebe/markdown": "~1.0.0",
+ "ext-mbstring": "*",
+ "ezyang/htmlpurifier": "4.6.*",
+ "lib-pcre": "*",
+ "php": ">=5.4.0",
+ "yiisoft/yii2-composer": "*"
+ },
+ "bin": [
+ "yii"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Qiang Xue",
+ "email": "qiang.xue@gmail.com",
+ "homepage": "http://www.yiiframework.com/",
+ "role": "Founder and project lead"
+ },
+ {
+ "name": "Alexander Makarov",
+ "email": "sam@rmcreative.ru",
+ "homepage": "http://rmcreative.ru/",
+ "role": "Core framework development"
+ },
+ {
+ "name": "Maurizio Domba",
+ "homepage": "http://mdomba.info/",
+ "role": "Core framework development"
+ },
+ {
+ "name": "Carsten Brandt",
+ "email": "mail@cebe.cc",
+ "homepage": "http://cebe.cc/",
+ "role": "Core framework development"
+ },
+ {
+ "name": "Timur Ruziev",
+ "email": "resurtm@gmail.com",
+ "homepage": "http://resurtm.com/",
+ "role": "Core framework development"
+ },
+ {
+ "name": "Paul Klimov",
+ "email": "klimov.paul@gmail.com",
+ "role": "Core framework development"
+ }
+ ],
+ "description": "Yii PHP Framework Version 2",
+ "homepage": "http://www.yiiframework.com/",
+ "keywords": [
+ "framework",
+ "yii2"
+ ],
+ "time": "2014-12-07 16:42:41"
+ },
+ {
+ "name": "yiisoft/yii2-composer",
+ "version": "2.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-composer.git",
+ "reference": "7f300dd23b6c4d1e7effc81c962b3889f83e43c0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/7f300dd23b6c4d1e7effc81c962b3889f83e43c0",
+ "reference": "7f300dd23b6c4d1e7effc81c962b3889f83e43c0",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "1.0.0"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "yii\\composer\\Plugin",
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\composer\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Qiang Xue",
+ "email": "qiang.xue@gmail.com"
+ }
+ ],
+ "description": "The composer plugin for Yii extension installer",
+ "keywords": [
+ "composer",
+ "extension installer",
+ "yii2"
+ ],
+ "time": "2014-12-07 16:42:41"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=5.4.0"
+ },
+ "platform-dev": []
+}
diff --git a/forms/CommentCreateForm.php b/forms/CommentCreateForm.php
new file mode 100644
index 0000000..3d48372
--- /dev/null
+++ b/forms/CommentCreateForm.php
@@ -0,0 +1,97 @@
+Comment;
+
+ if (false === $this->Comment->isNewRecord) {
+ $this->id = $Comment->id;
+ $this->entity = $Comment->entity;
+ $this->text = $Comment->text;
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ [['entity', 'text'], 'required'],
+ [['entity', 'text'], 'string'],
+ [['id'], 'integer'],
+ [['id'], 'exist', 'targetClass' => Comments\models\Comment::class, 'targetAttribute' => 'id'],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'entity' => \Yii::t('app', 'Entity'),
+ 'text' => \Yii::t('app', 'Text'),
+ ];
+ }
+
+ /**
+ * @return bool
+ * @throws \yii\web\NotFoundHttpException
+ */
+ public function save()
+ {
+ $Comment = $this->Comment;
+
+ if (empty($this->id)) {
+ $Comment = new Comments\models\Comment();
+ } elseif ($this->id > 0 && $Comment->id !== $this->id) {
+ $Comment = Comments\models\Comment::find()
+ ->byId($this->id)
+ ->one();
+
+ if (!($Comment instanceof Comments\models\Comment)) {
+ throw new \yii\web\NotFoundHttpException;
+ }
+ }
+
+ $Comment->entity = $this->entity;
+ $Comment->text = $this->text;
+
+ $result = $Comment->save();
+
+ if ($Comment->hasErrors()) {
+ foreach ($Comment->getErrors() as $attribute => $messages) {
+ foreach ($messages as $mes) {
+ $this->addError($attribute, $mes);
+ }
+ }
+ }
+
+ $this->Comment = $Comment;
+
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/interfaces/CommentatorInterface.php b/interfaces/CommentatorInterface.php
new file mode 100644
index 0000000..0b5d7f9
--- /dev/null
+++ b/interfaces/CommentatorInterface.php
@@ -0,0 +1,30 @@
+db->driverName === 'mysql') {
+ // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+ }
+
+ $this->createTable('{{%comment}}', [
+ 'id' => Schema::TYPE_PK,
+ 'entity' => Schema::TYPE_STRING,
+ 'text' => Schema::TYPE_TEXT,
+ 'created_by' => Schema::TYPE_INTEGER,
+ 'updated_by' => Schema::TYPE_INTEGER,
+ 'created_at' => Schema::TYPE_INTEGER,
+ 'updated_at' => Schema::TYPE_INTEGER,
+ ], $tableOptions);
+
+ $this->createIndex('index_entity', '{{%comment}}', ['entity']);
+ $this->createIndex('index_created_by', '{{%comment}}', ['created_by']);
+ $this->createIndex('index_created_at', '{{%comment}}', ['created_at']);
+ }
+
+ public function safeDown()
+ {
+ $this->dropTable('{{%comment}}');
+ }
+}
\ No newline at end of file
diff --git a/models/Comment.php b/models/Comment.php
new file mode 100644
index 0000000..46ce3dc
--- /dev/null
+++ b/models/Comment.php
@@ -0,0 +1,154 @@
+ self::NOT_DELETED],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function attributeLabels()
+ {
+ return [
+ 'id' => \Yii::t('app', 'ID'),
+ 'entity' => \Yii::t('app', 'Entity'),
+ 'text' => \Yii::t('app', 'Text'),
+ 'created_by' => \Yii::t('app', 'Created by'),
+ 'updated_by' => \Yii::t('app', 'Updated by'),
+ 'created_at' => \Yii::t('app', 'Created at'),
+ 'updated_at' => \Yii::t('app', 'Updated at'),
+ ];
+ }
+
+ /**
+ * @return bool
+ */
+ public function isEdited()
+ {
+ return $this->created_at !== $this->updated_at;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isDeleted()
+ {
+ return $this->deleted === self::DELETED;
+ }
+
+ /**
+ * @return bool
+ */
+ public static function canCreate()
+ {
+ return true || \Yii::$app->getUser()->can(Comments\Permission::CREATE);
+ }
+
+ /**
+ * @return bool
+ */
+ public function canUpdate()
+ {
+ return true || \Yii::$app->getUser()->can(Comments\Permission::UPDATE) || \Yii::$app->getUser()->can(Comments\Permission::UPDATE_OWN, ['Comment' => $this]);
+ }
+
+ /**
+ * @return bool
+ */
+ public function canDelete()
+ {
+ return true || \Yii::$app->getUser()->can(Comments\Permission::DELETE) || \Yii::$app->getUser()->can(Comments\Permission::DELETE_OWN, ['Comment' => $this]);
+ }
+
+ /**
+ * @return queries\CommentQuery
+ */
+ public function getAuthor()
+ {
+ /** @var Comments\Module $Module */
+ $Module = \Yii::$app->getModule('comments');
+
+ return $this->hasOne($Module->userIdentityClass, ['id' => 'created_by']);
+ }
+
+ /**
+ * @return queries\CommentQuery
+ */
+ public function getLastUpdateAuthor()
+ {
+ /** @var Comments\Module $Module */
+ $Module = \Yii::$app->getModule('comments');
+
+ return $this->hasOne($Module->userIdentityClass, ['id' => 'updated_by']);
+ }
+
+ /**
+ * @return queries\CommentQuery
+ */
+ public static function find()
+ {
+ return new queries\CommentQuery(get_called_class());
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function tableName()
+ {
+ return '{{%comment}}';
+ }
+
+ const NOT_DELETED = 0;
+ const DELETED = 1;
+}
\ No newline at end of file
diff --git a/models/queries/CommentQuery.php b/models/queries/CommentQuery.php
new file mode 100644
index 0000000..078f528
--- /dev/null
+++ b/models/queries/CommentQuery.php
@@ -0,0 +1,49 @@
+andWhere(['id' => $id]);
+
+ return $this;
+ }
+
+ /**
+ * @param string|array $entity
+ * @return self
+ */
+ public function byEntity($entity)
+ {
+ $this->andWhere(['entity' => $entity]);
+
+ return $this;
+ }
+
+ /**
+ * @return self
+ */
+ public function withoutDeleted()
+ {
+ $this->andWhere(['deleted' => Comments\models\Comment::NOT_DELETED]);
+
+ return $this;
+ }
+}
\ No newline at end of file
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..d6af986
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,22 @@
+
+