├── .gitignore
├── .scrutinizer.yml
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── Module.php
├── Permission.php
├── README.md
├── composer.json
├── composer.lock
├── forms
└── CommentCreateForm.php
├── interfaces
└── CommentatorInterface.php
├── migrations
├── m150106_122229_comments.php
└── m151005_165040_comment_from.php
├── models
├── Comment.php
└── queries
│ └── CommentQuery.php
├── phpunit.xml.dist
├── rbac
└── ItsMyComment.php
├── tests
├── unit
│ ├── .gitignore
│ ├── TestCase.php
│ ├── bootstrap.php
│ ├── comments
│ │ └── MainTest.php
│ ├── config
│ │ ├── .gitignore
│ │ └── main.php
│ ├── models
│ │ └── User.php
│ └── runtime
│ │ └── .gitignore
└── web
│ ├── README.md
│ ├── assets
│ └── AppAssetBundle.php
│ ├── config
│ ├── console.php
│ ├── db.php
│ └── web.php
│ ├── controllers
│ ├── DemoController.php
│ └── SignController.php
│ ├── migrations
│ └── m151005_165039_user.php
│ ├── models
│ └── User.php
│ ├── runtime
│ └── .gitignore
│ ├── views
│ ├── demo
│ │ └── index.php
│ └── layouts
│ │ └── main.php
│ ├── web
│ ├── assets
│ │ └── .gitignore
│ └── index.php
│ └── yii
└── widgets
├── CommentFormAsset.php
├── CommentFormWidget.php
├── CommentListAsset.php
├── CommentListWidget.php
├── _assets
├── comment-form.css
├── comment-list.css
└── comment-list.js
└── views
├── comment-form.php
└── comment-list.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /vendor
3 | /coverage
4 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | build:
2 | environment:
3 | php:
4 | version: 5.5.12
5 | dependencies:
6 | before:
7 | - sudo composer self-update && composer --version
8 | - composer global require "fxp/composer-asset-plugin:~1.0"
9 | tests:
10 | override:
11 | - phpunit
12 | imports:
13 | - php
14 | checks:
15 | php:
16 | code_rating: true
17 | duplication: true
18 | tools:
19 | php_sim: false
20 | php_cpd: false
21 | php_pdepend: true
22 | php_analyzer: true
23 | php_changetracking: true
24 | external_code_coverage:
25 | timeout: 2100 # Timeout in seconds.
26 | filter:
27 | excluded_paths:
28 | - tests/*
29 | - vendor/*
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.4
5 | - 5.5
6 | - 5.6
7 | - hhvm
8 | - hhvm-nightly
9 |
10 | matrix:
11 | fast_finish: true
12 | allow_failures:
13 | - php: hhvm
14 | - php: hhvm-nightly
15 |
16 | sudo: false
17 |
18 | cache:
19 | directories:
20 | - vendor
21 |
22 | install:
23 | - travis_retry composer self-update && composer --version
24 | - travis_retry composer global require "fxp/composer-asset-plugin:~1.0"
25 | - export PATH="$HOME/.composer/vendor/bin:$PATH"
26 | - travis_retry composer install --prefer-dist --no-interaction
27 |
28 | script:
29 | - phpunit --verbose --coverage-clover=coverage/coverage.clover
30 |
31 | after_script:
32 | - travis_retry wget https://scrutinizer-ci.com/ocular.phar
33 | - php ocular.phar code-coverage:upload --format=php-clover coverage/coverage.clover
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | 2016-04-28 - 1.4.4
2 | ------------------
3 | * Fix #16
4 | * Fix #13
5 | * Refactoring
6 |
7 | 2016-04-28 - 1.4.3
8 | ------------------
9 | * Fix trouble with delete button, when user delete comment from page with GET parameters in url (like `foo/bar?id=1`)
10 | * Refactoring.
11 |
12 | 2016-03-01 - 1.4.2
13 | ------------------
14 | * Refactoring.
15 |
16 | 2016-02-28 - 1.4.1
17 | ------------------
18 | * Fix author check.
19 | * Update packages.
20 |
21 | 2015-10-05 - 1.4.0
22 | ------------------
23 | * Improve dependency injection.
24 | * Add comment from field.
25 | * Add web test.
26 | * Refactoring.
27 |
28 | 2015-06-27 - 1.3.1
29 | ------------------
30 | * Add param `theme` to `CommentFormWidget`
31 |
32 | 2015-06-22 - 1.3.0
33 | ------------------
34 | * Bugfixes and add `theme` parameter into `CommentListWidget`
35 |
36 | 2015-06-19 - 1.2.1
37 | ------------------
38 | * Refactoring.
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Revin Roman Borisovich
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Module.php:
--------------------------------------------------------------------------------
1 | 'frontend/models/comments/CommentModel'
34 | * ]
35 | *
36 | * The classes defined here will be merged with getDefaultModels()
37 | * having he manually defined by the user preference.
38 | *
39 | * @var array
40 | */
41 | public $modelMap = [];
42 |
43 | public function init()
44 | {
45 | parent::init();
46 |
47 | if ($this->userIdentityClass === null) {
48 | $this->userIdentityClass = \Yii::$app->getUser()->identityClass;
49 | }
50 |
51 | // Merge the default model classes
52 | // with the user defined ones.
53 | $this->defineModelClasses();
54 | }
55 |
56 | /**
57 | * @return static
58 | */
59 | public static function instance()
60 | {
61 | return \Yii::$app->getModule(static::$moduleName);
62 | }
63 |
64 | /**
65 | * Merges the default and user defined model classes
66 | * Also let's the developer to set new ones with the
67 | * parameter being those the ones with most preference.
68 | *
69 | * @param array $modelClasses
70 | */
71 | public function defineModelClasses($modelClasses = [])
72 | {
73 | $this->modelMap = ArrayHelper::merge(
74 | $this->getDefaultModels(),
75 | $this->modelMap,
76 | $modelClasses
77 | );
78 | }
79 |
80 | /**
81 | * Get default model classes
82 | */
83 | protected function getDefaultModels()
84 | {
85 | return [
86 | 'Comment' => Comments\models\Comment::className(),
87 | 'CommentQuery' => Comments\models\queries\CommentQuery::className(),
88 | 'CommentCreateForm' => Comments\forms\CommentCreateForm::className(),
89 | ];
90 | }
91 |
92 | /**
93 | * Get defined className of model
94 | *
95 | * Returns an string or array compatible
96 | * with the Yii::createObject method.
97 | *
98 | * @param string $name
99 | * @param array $config // You should never send an array with a key defined as "class" since this will
100 | * // overwrite the main className defined by the system.
101 | * @return string|array
102 | */
103 | public function model($name, $config = [])
104 | {
105 | $modelData = $this->modelMap[ucfirst($name)];
106 |
107 | if (!empty($config)) {
108 | if (is_string($modelData)) {
109 | $modelData = ['class' => $modelData];
110 | }
111 |
112 | $modelData = ArrayHelper::merge(
113 | $modelData,
114 | $config
115 | );
116 | }
117 |
118 | return $modelData;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Permission.php:
--------------------------------------------------------------------------------
1 | [
30 | // ...
31 | 'comments' => [
32 | 'class' => 'rmrevin\yii\module\Comments\Module',
33 | 'userIdentityClass' => 'app\models\User',
34 | 'useRbac' => true,
35 | ]
36 | ],
37 | // ...
38 | ];
39 | ```
40 |
41 | In your `User` model (or another model implements the interface `IdentityInterface`) need to implement the interface "\rmrevin\yii\module\Comments\interfaces\CommentatorInterface"
42 | ```php
43 | class User extends \yii\db\ActiveRecord
44 | implements
45 | \yii\web\IdentityInterface,
46 | \rmrevin\yii\module\Comments\interfaces\CommentatorInterface
47 | {
48 | // ...
49 |
50 | public function getCommentatorAvatar()
51 | {
52 | return $this->avatar_url;
53 | }
54 |
55 | public function getCommentatorName()
56 | {
57 | return $this->name;
58 | }
59 |
60 | public function getCommentatorUrl()
61 | {
62 | return ['/profile', 'id' => $this->id]; // or false, if user does not have a public page
63 | }
64 |
65 | // ...
66 | }
67 | ```
68 |
69 | In auth manager add rules (if `Module::$useRbac = true`):
70 | ```php
71 | getAuthManager();
76 | $ItsMyCommentRule = new ItsMyComment();
77 |
78 | $AuthManager->add($ItsMyCommentRule);
79 |
80 | $AuthManager->add(new \yii\rbac\Permission([
81 | 'name' => Permission::CREATE,
82 | 'description' => 'Can create own comments',
83 | ]));
84 | $AuthManager->add(new \yii\rbac\Permission([
85 | 'name' => Permission::UPDATE,
86 | 'description' => 'Can update all comments',
87 | ]));
88 | $AuthManager->add(new \yii\rbac\Permission([
89 | 'name' => Permission::UPDATE_OWN,
90 | 'ruleName' => $ItsMyCommentRule->name,
91 | 'description' => 'Can update own comments',
92 | ]));
93 | $AuthManager->add(new \yii\rbac\Permission([
94 | 'name' => Permission::DELETE,
95 | 'description' => 'Can delete all comments',
96 | ]));
97 | $AuthManager->add(new \yii\rbac\Permission([
98 | 'name' => Permission::DELETE_OWN,
99 | 'ruleName' => $ItsMyCommentRule->name,
100 | 'description' => 'Can delete own comments',
101 | ]));
102 | ```
103 |
104 | Updating database schema
105 | ------------------------
106 | After you downloaded and configured `rmrevin/yii2-comments`,
107 | the last thing you need to do is updating your database schema by applying the migrations:
108 |
109 | In `command line`:
110 | ```
111 | php yii migrate/up --migrationPath=@vendor/rmrevin/yii2-comments/migrations/
112 | ```
113 |
114 | Usage
115 | -----
116 | In view
117 | ```php
118 | (string) 'photo-15', // type and id
125 | ]);
126 |
127 | ```
128 |
129 | Parameters
130 | ----------
131 |
132 | ### Module parameters
133 |
134 | * **userIdentityClass** (required, string) The user identity class that Yii2 uses to provide identity information about the users in the App.
135 |
136 | * **useRbac** (optional, boolean) Default TRUE. Defines if the comment system will use Rbac validation to check the comment permissions when trying to update, delete or add new comments.
137 |
138 | * **modelClasses** (optional, string[]) Stores the user defined model classes that will be used instead of the default ones in the comment system. Must have a key => classname format. e.g. `'Comment' => '@app\comments\CommentModel'`
139 |
140 |
141 | ### Widget parameters
142 |
143 | * **entity** (required, string) The entity that will identify the comments under on section from all the comments in this module.
144 |
145 | * **theme** (optional, string) In case you want to use a theme in your application you should define here it's location.
146 |
147 | * **viewParams** (optional, array) Data that will be sent directly into the widget view files. Must have a key => data format. The key will be the variable name in the view. The variable `CommentsDataProvider` it's already taken.
148 |
149 | * **options** (optional, array) Default `['class' => 'comments-widget']`. Option data array that will be sent into the div holding the comment system in your views.
150 |
151 | * **pagination** (optional, array) Pagination configuration that will be used in the comment panel.
152 | Default data:
153 | ```php
154 | public $pagination =
155 | [
156 | 'pageParam' => 'page',
157 | 'pageSizeParam' => 'per-page',
158 | 'pageSize' => 20,
159 | 'pageSizeLimit' => [1, 50],
160 | ];
161 | ```
162 |
163 | * **sort** (optional, array) Type of sorting used to retrieve the comments into the panel. Can be sorted by any of the columns defined in the `comment` table.
164 | Default data:
165 | ```php
166 | 'defaultOrder' => [
167 | 'id' => SORT_ASC,
168 | ],
169 | ```
170 |
171 | * **showDeleted** (optional, boolean) Default `True`. Defines if the comments panel will show a message indicating the deleted comments.
172 |
173 | * **showCreateForm** (optional, boolean) Default `True`. Will show or hide the form to add a comment in this panel.
174 |
175 |
176 | Extending the package
177 | ---------------------
178 |
179 | ### Extending Model files
180 |
181 | Depending on which ones you need, you can set the `modelMap` config property:
182 |
183 | ```php
184 |
185 | // ...
186 | 'modules' => [
187 | // ...
188 | 'comments' => [
189 | 'class' => 'rmrevin\yii\module\Comments\Module',
190 | 'userIdentityClass' => 'app\models\User',
191 | 'useRbac' => true,
192 | 'modelMap' => [
193 | 'Comment' => '@app\comments\CommentModel'
194 | ]
195 | ]
196 | ],
197 | // ...
198 | ```
199 |
200 |
201 | Attention: keep in mind that if you are changing the `Comment` model, the new class should always extend the package's original `Comment` class.
202 |
203 |
204 | ### Attaching behaviors and event handlers
205 |
206 | The package allows you to attach behavior or event handler to any model. To do this you can set model map like so:
207 |
208 | ```php
209 |
210 | // ...
211 | 'modules' => [
212 | // ...
213 | 'comments' => [
214 | 'class' => 'rmrevin\yii\module\Comments\Module',
215 | 'userIdentityClass' => 'app\models\User',
216 | 'useRbac' => true,
217 | 'modelMap' => [
218 | 'Comment' => [
219 | 'class' => '@app\comments\CommentModel',
220 | 'on event' => function(){
221 | // code here
222 | },
223 | 'as behavior' =>
224 | ['class' => 'Foo'],
225 | ]
226 | ]
227 | ],
228 | // ...
229 | ```
230 |
231 | ### Extending View files
232 |
233 | You can extend the view files supplied by this package using the `theme` component in the config file.
234 |
235 | ```php
236 | // app/config/web.php
237 |
238 | 'components' => [
239 | 'view' => [
240 | 'theme' => [
241 | 'pathMap' => [
242 | '@vendor/rmrevin/yii2-comments/widgets/views' => '@app/views/comments', // example: @app/views/comment/comment-form.php
243 | ],
244 | ],
245 | ],
246 | ],
247 |
248 | ```
249 |
250 | ### Extending Widgets
251 |
252 | To extend the widget code and behavior you only have to extend the widget classes and call them instead of the package's ones.
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rmrevin/yii2-comments",
3 | "description": "Comments module for Yii2",
4 | "keywords": [
5 | "yii",
6 | "comment",
7 | "widget",
8 | "module"
9 | ],
10 | "type": "yii2-extension",
11 | "license": "MIT",
12 | "minimum-stability": "stable",
13 | "support": {
14 | "issues": "https://github.com/rmrevin/yii2-comments/issues",
15 | "source": "https://github.com/rmrevin/yii2-comments"
16 | },
17 | "authors": [
18 | {
19 | "name": "Roman Revin",
20 | "email": "xgismox@gmail.com",
21 | "homepage": "http://rmrevin.ru/"
22 | }
23 | ],
24 | "require": {
25 | "php": ">=5.4.0",
26 |
27 | "yiisoft/yii2": "2.0.*",
28 | "rmrevin/yii2-fontawesome": "~2.10"
29 | },
30 | "autoload": {
31 | "psr-4": {
32 | "rmrevin\\yii\\module\\Comments\\": ""
33 | }
34 | },
35 | "extra": {
36 | "asset-installer-paths": {
37 | "npm-asset-library": "vendor/npm",
38 | "bower-asset-library": "vendor/bower"
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "hash": "ed4934636110d3d30a7d7b8b554cb1d3",
8 | "content-hash": "1a2475ef8226c24df1dc00d303ac7ee5",
9 | "packages": [
10 | {
11 | "name": "bower-asset/jquery",
12 | "version": "2.2.3",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/jquery/jquery-dist.git",
16 | "reference": "af22a351b2ea5801ffb1695abb3bb34d5bed9198"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/af22a351b2ea5801ffb1695abb3bb34d5bed9198",
21 | "reference": "af22a351b2ea5801ffb1695abb3bb34d5bed9198",
22 | "shasum": ""
23 | },
24 | "type": "bower-asset-library",
25 | "extra": {
26 | "bower-asset-main": "dist/jquery.js",
27 | "bower-asset-ignore": [
28 | "package.json"
29 | ]
30 | },
31 | "license": [
32 | "MIT"
33 | ],
34 | "keywords": [
35 | "browser",
36 | "javascript",
37 | "jquery",
38 | "library"
39 | ]
40 | },
41 | {
42 | "name": "bower-asset/jquery.inputmask",
43 | "version": "3.2.7",
44 | "source": {
45 | "type": "git",
46 | "url": "https://github.com/RobinHerbots/jquery.inputmask.git",
47 | "reference": "5a72c563b502b8e05958a524cdfffafe9987be38"
48 | },
49 | "dist": {
50 | "type": "zip",
51 | "url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/5a72c563b502b8e05958a524cdfffafe9987be38",
52 | "reference": "5a72c563b502b8e05958a524cdfffafe9987be38",
53 | "shasum": ""
54 | },
55 | "require": {
56 | "bower-asset/jquery": ">=1.7"
57 | },
58 | "type": "bower-asset-library",
59 | "extra": {
60 | "bower-asset-main": [
61 | "./dist/inputmask/inputmask.js"
62 | ],
63 | "bower-asset-ignore": [
64 | "**/*",
65 | "!dist/*",
66 | "!dist/inputmask/*",
67 | "!dist/min/*",
68 | "!dist/min/inputmask/*",
69 | "!extra/bindings/*",
70 | "!extra/dependencyLibs/*",
71 | "!extra/phone-codes/*"
72 | ]
73 | },
74 | "license": [
75 | "http://opensource.org/licenses/mit-license.php"
76 | ],
77 | "description": "jquery.inputmask is a jquery plugin which create an input mask.",
78 | "keywords": [
79 | "form",
80 | "input",
81 | "inputmask",
82 | "jquery",
83 | "mask",
84 | "plugins"
85 | ]
86 | },
87 | {
88 | "name": "bower-asset/punycode",
89 | "version": "v1.3.2",
90 | "source": {
91 | "type": "git",
92 | "url": "https://github.com/bestiejs/punycode.js.git",
93 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3"
94 | },
95 | "dist": {
96 | "type": "zip",
97 | "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3",
98 | "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3",
99 | "shasum": ""
100 | },
101 | "type": "bower-asset-library",
102 | "extra": {
103 | "bower-asset-main": "punycode.js",
104 | "bower-asset-ignore": [
105 | "coverage",
106 | "tests",
107 | ".*",
108 | "component.json",
109 | "Gruntfile.js",
110 | "node_modules",
111 | "package.json"
112 | ]
113 | }
114 | },
115 | {
116 | "name": "bower-asset/yii2-pjax",
117 | "version": "v2.0.6",
118 | "source": {
119 | "type": "git",
120 | "url": "https://github.com/yiisoft/jquery-pjax.git",
121 | "reference": "60728da6ade5879e807a49ce59ef9a72039b8978"
122 | },
123 | "dist": {
124 | "type": "zip",
125 | "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/60728da6ade5879e807a49ce59ef9a72039b8978",
126 | "reference": "60728da6ade5879e807a49ce59ef9a72039b8978",
127 | "shasum": ""
128 | },
129 | "require": {
130 | "bower-asset/jquery": ">=1.8"
131 | },
132 | "type": "bower-asset-library",
133 | "extra": {
134 | "bower-asset-main": "./jquery.pjax.js",
135 | "bower-asset-ignore": [
136 | ".travis.yml",
137 | "Gemfile",
138 | "Gemfile.lock",
139 | "CONTRIBUTING.md",
140 | "vendor/",
141 | "script/",
142 | "test/"
143 | ]
144 | },
145 | "license": [
146 | "MIT"
147 | ]
148 | },
149 | {
150 | "name": "cebe/markdown",
151 | "version": "1.1.0",
152 | "source": {
153 | "type": "git",
154 | "url": "https://github.com/cebe/markdown.git",
155 | "reference": "54a2c49de31cc44e864ebf0500a35ef21d0010b2"
156 | },
157 | "dist": {
158 | "type": "zip",
159 | "url": "https://api.github.com/repos/cebe/markdown/zipball/54a2c49de31cc44e864ebf0500a35ef21d0010b2",
160 | "reference": "54a2c49de31cc44e864ebf0500a35ef21d0010b2",
161 | "shasum": ""
162 | },
163 | "require": {
164 | "lib-pcre": "*",
165 | "php": ">=5.4.0"
166 | },
167 | "require-dev": {
168 | "cebe/indent": "*",
169 | "facebook/xhprof": "*@dev",
170 | "phpunit/phpunit": "4.1.*"
171 | },
172 | "bin": [
173 | "bin/markdown"
174 | ],
175 | "type": "library",
176 | "extra": {
177 | "branch-alias": {
178 | "dev-master": "1.1.x-dev"
179 | }
180 | },
181 | "autoload": {
182 | "psr-4": {
183 | "cebe\\markdown\\": ""
184 | }
185 | },
186 | "notification-url": "https://packagist.org/downloads/",
187 | "license": [
188 | "MIT"
189 | ],
190 | "authors": [
191 | {
192 | "name": "Carsten Brandt",
193 | "email": "mail@cebe.cc",
194 | "homepage": "http://cebe.cc/",
195 | "role": "Creator"
196 | }
197 | ],
198 | "description": "A super fast, highly extensible markdown parser for PHP",
199 | "homepage": "https://github.com/cebe/markdown#readme",
200 | "keywords": [
201 | "extensible",
202 | "fast",
203 | "gfm",
204 | "markdown",
205 | "markdown-extra"
206 | ],
207 | "time": "2015-03-06 05:28:07"
208 | },
209 | {
210 | "name": "ezyang/htmlpurifier",
211 | "version": "v4.7.0",
212 | "source": {
213 | "type": "git",
214 | "url": "https://github.com/ezyang/htmlpurifier.git",
215 | "reference": "ae1828d955112356f7677c465f94f7deb7d27a40"
216 | },
217 | "dist": {
218 | "type": "zip",
219 | "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/ae1828d955112356f7677c465f94f7deb7d27a40",
220 | "reference": "ae1828d955112356f7677c465f94f7deb7d27a40",
221 | "shasum": ""
222 | },
223 | "require": {
224 | "php": ">=5.2"
225 | },
226 | "type": "library",
227 | "autoload": {
228 | "psr-0": {
229 | "HTMLPurifier": "library/"
230 | },
231 | "files": [
232 | "library/HTMLPurifier.composer.php"
233 | ]
234 | },
235 | "notification-url": "https://packagist.org/downloads/",
236 | "license": [
237 | "LGPL"
238 | ],
239 | "authors": [
240 | {
241 | "name": "Edward Z. Yang",
242 | "email": "admin@htmlpurifier.org",
243 | "homepage": "http://ezyang.com"
244 | }
245 | ],
246 | "description": "Standards compliant HTML filter written in PHP",
247 | "homepage": "http://htmlpurifier.org/",
248 | "keywords": [
249 | "html"
250 | ],
251 | "time": "2015-08-05 01:03:42"
252 | },
253 | {
254 | "name": "rmrevin/yii2-fontawesome",
255 | "version": "2.15.1",
256 | "source": {
257 | "type": "git",
258 | "url": "https://github.com/rmrevin/yii2-fontawesome.git",
259 | "reference": "d2777130bc926bc670a4e50c2f504a0fb782efb1"
260 | },
261 | "dist": {
262 | "type": "zip",
263 | "url": "https://api.github.com/repos/rmrevin/yii2-fontawesome/zipball/d2777130bc926bc670a4e50c2f504a0fb782efb1",
264 | "reference": "d2777130bc926bc670a4e50c2f504a0fb782efb1",
265 | "shasum": ""
266 | },
267 | "require": {
268 | "php": ">=5.4.0",
269 | "yiisoft/yii2": "2.0.*"
270 | },
271 | "type": "yii2-extension",
272 | "extra": {
273 | "asset-installer-paths": {
274 | "npm-asset-library": "vendor/npm",
275 | "bower-asset-library": "vendor/bower"
276 | }
277 | },
278 | "autoload": {
279 | "psr-4": {
280 | "rmrevin\\yii\\fontawesome\\": ""
281 | }
282 | },
283 | "notification-url": "https://packagist.org/downloads/",
284 | "license": [
285 | "MIT"
286 | ],
287 | "authors": [
288 | {
289 | "name": "Revin Roman",
290 | "email": "roman@rmrevin.com",
291 | "homepage": "https://rmrevin.com/"
292 | }
293 | ],
294 | "description": "Asset Bundle for Yii2 with Font Awesome",
295 | "keywords": [
296 | "asset",
297 | "awesome",
298 | "bundle",
299 | "font",
300 | "yii"
301 | ],
302 | "time": "2016-05-28 21:18:32"
303 | },
304 | {
305 | "name": "yiisoft/yii2",
306 | "version": "2.0.8",
307 | "source": {
308 | "type": "git",
309 | "url": "https://github.com/yiisoft/yii2-framework.git",
310 | "reference": "53992b136b993e32ca7b6f399cf42b143f8685a6"
311 | },
312 | "dist": {
313 | "type": "zip",
314 | "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/53992b136b993e32ca7b6f399cf42b143f8685a6",
315 | "reference": "53992b136b993e32ca7b6f399cf42b143f8685a6",
316 | "shasum": ""
317 | },
318 | "require": {
319 | "bower-asset/jquery": "2.2.*@stable | 2.1.*@stable | 1.11.*@stable",
320 | "bower-asset/jquery.inputmask": "~3.2.2",
321 | "bower-asset/punycode": "1.3.*",
322 | "bower-asset/yii2-pjax": "~2.0.1",
323 | "cebe/markdown": "~1.0.0 | ~1.1.0",
324 | "ext-ctype": "*",
325 | "ext-mbstring": "*",
326 | "ezyang/htmlpurifier": "~4.6",
327 | "lib-pcre": "*",
328 | "php": ">=5.4.0",
329 | "yiisoft/yii2-composer": "~2.0.4"
330 | },
331 | "bin": [
332 | "yii"
333 | ],
334 | "type": "library",
335 | "extra": {
336 | "branch-alias": {
337 | "dev-master": "2.0.x-dev"
338 | }
339 | },
340 | "autoload": {
341 | "psr-4": {
342 | "yii\\": ""
343 | }
344 | },
345 | "notification-url": "https://packagist.org/downloads/",
346 | "license": [
347 | "BSD-3-Clause"
348 | ],
349 | "authors": [
350 | {
351 | "name": "Qiang Xue",
352 | "email": "qiang.xue@gmail.com",
353 | "homepage": "http://www.yiiframework.com/",
354 | "role": "Founder and project lead"
355 | },
356 | {
357 | "name": "Alexander Makarov",
358 | "email": "sam@rmcreative.ru",
359 | "homepage": "http://rmcreative.ru/",
360 | "role": "Core framework development"
361 | },
362 | {
363 | "name": "Maurizio Domba",
364 | "homepage": "http://mdomba.info/",
365 | "role": "Core framework development"
366 | },
367 | {
368 | "name": "Carsten Brandt",
369 | "email": "mail@cebe.cc",
370 | "homepage": "http://cebe.cc/",
371 | "role": "Core framework development"
372 | },
373 | {
374 | "name": "Timur Ruziev",
375 | "email": "resurtm@gmail.com",
376 | "homepage": "http://resurtm.com/",
377 | "role": "Core framework development"
378 | },
379 | {
380 | "name": "Paul Klimov",
381 | "email": "klimov.paul@gmail.com",
382 | "role": "Core framework development"
383 | },
384 | {
385 | "name": "Dmitry Naumenko",
386 | "email": "d.naumenko.a@gmail.com",
387 | "role": "Core framework development"
388 | }
389 | ],
390 | "description": "Yii PHP Framework Version 2",
391 | "homepage": "http://www.yiiframework.com/",
392 | "keywords": [
393 | "framework",
394 | "yii2"
395 | ],
396 | "time": "2016-04-28 14:50:20"
397 | },
398 | {
399 | "name": "yiisoft/yii2-composer",
400 | "version": "2.0.4",
401 | "source": {
402 | "type": "git",
403 | "url": "https://github.com/yiisoft/yii2-composer.git",
404 | "reference": "7452fd908a5023b8bb5ea1b123a174ca080de464"
405 | },
406 | "dist": {
407 | "type": "zip",
408 | "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/7452fd908a5023b8bb5ea1b123a174ca080de464",
409 | "reference": "7452fd908a5023b8bb5ea1b123a174ca080de464",
410 | "shasum": ""
411 | },
412 | "require": {
413 | "composer-plugin-api": "^1.0"
414 | },
415 | "type": "composer-plugin",
416 | "extra": {
417 | "class": "yii\\composer\\Plugin",
418 | "branch-alias": {
419 | "dev-master": "2.0.x-dev"
420 | }
421 | },
422 | "autoload": {
423 | "psr-4": {
424 | "yii\\composer\\": ""
425 | }
426 | },
427 | "notification-url": "https://packagist.org/downloads/",
428 | "license": [
429 | "BSD-3-Clause"
430 | ],
431 | "authors": [
432 | {
433 | "name": "Qiang Xue",
434 | "email": "qiang.xue@gmail.com"
435 | }
436 | ],
437 | "description": "The composer plugin for Yii extension installer",
438 | "keywords": [
439 | "composer",
440 | "extension installer",
441 | "yii2"
442 | ],
443 | "time": "2016-02-06 00:49:24"
444 | }
445 | ],
446 | "packages-dev": [],
447 | "aliases": [],
448 | "minimum-stability": "stable",
449 | "stability-flags": [],
450 | "prefer-stable": false,
451 | "prefer-lowest": false,
452 | "platform": {
453 | "php": ">=5.4.0"
454 | },
455 | "platform-dev": []
456 | }
457 |
--------------------------------------------------------------------------------
/forms/CommentCreateForm.php:
--------------------------------------------------------------------------------
1 | Comment;
30 |
31 | if (false === $this->Comment->isNewRecord) {
32 | $this->id = $Comment->id;
33 | $this->entity = $Comment->entity;
34 | $this->from = $Comment->from;
35 | $this->text = $Comment->text;
36 | } elseif (!\Yii::$app->getUser()->getIsGuest()) {
37 | $User = \Yii::$app->getUser()->getIdentity();
38 |
39 | $this->from = $User instanceof Comments\interfaces\CommentatorInterface
40 | ? $User->getCommentatorName()
41 | : null;
42 | }
43 | }
44 |
45 | /**
46 | * @inheritdoc
47 | */
48 | public function rules()
49 | {
50 | $CommentModelClassName = Comments\Module::instance()->model('comment');
51 |
52 | return [
53 | [['entity', 'text'], 'required'],
54 | [['entity', 'from', 'text'], 'string'],
55 | [['id'], 'integer'],
56 | [['id'], 'exist', 'targetClass' => $CommentModelClassName, 'targetAttribute' => 'id'],
57 | ];
58 | }
59 |
60 | /**
61 | * @inheritdoc
62 | */
63 | public function attributeLabels()
64 | {
65 | return [
66 | 'entity' => \Yii::t('app', 'Entity'),
67 | 'from' => \Yii::t('app', 'Your name'),
68 | 'text' => \Yii::t('app', 'Text'),
69 | ];
70 | }
71 |
72 | /**
73 | * @return bool
74 | * @throws \yii\web\NotFoundHttpException
75 | */
76 | public function save()
77 | {
78 | $Comment = $this->Comment;
79 |
80 | $CommentModelClassName = Comments\Module::instance()->model('comment');
81 |
82 | if (empty($this->id)) {
83 | $Comment = \Yii::createObject($CommentModelClassName);
84 | } elseif ($this->id > 0 && $Comment->id !== $this->id) {
85 | /** @var Comments\models\Comment $CommentModel */
86 | $CommentModel = \Yii::createObject($CommentModelClassName);
87 | $Comment = $CommentModel::find()
88 | ->byId($this->id)
89 | ->one();
90 |
91 | if (!($Comment instanceof Comments\models\Comment)) {
92 | throw new \yii\web\NotFoundHttpException;
93 | }
94 | }
95 |
96 | $Comment->entity = $this->entity;
97 | $Comment->from = $this->from;
98 | $Comment->text = $this->text;
99 |
100 | $result = $Comment->save();
101 |
102 | if ($Comment->hasErrors()) {
103 | foreach ($Comment->getErrors() as $attribute => $messages) {
104 | foreach ($messages as $mes) {
105 | $this->addError($attribute, $mes);
106 | }
107 | }
108 | }
109 |
110 | $this->Comment = $Comment;
111 |
112 | return $result;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/interfaces/CommentatorInterface.php:
--------------------------------------------------------------------------------
1 | db->driverName === 'mysql') {
10 | // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
11 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
12 | }
13 |
14 | $this->createTable('{{%comment}}', [
15 | 'id' => $this->primaryKey(),
16 | 'entity' => $this->string(),
17 | 'text' => $this->text(),
18 | 'deleted' => $this->boolean()->notNull()->defaultValue(false),
19 | 'created_by' => $this->integer(),
20 | 'updated_by' => $this->integer(),
21 | 'created_at' => $this->integer(),
22 | 'updated_at' => $this->integer(),
23 | ], $tableOptions);
24 |
25 | $this->createIndex('idx_entity', '{{%comment}}', ['entity']);
26 | $this->createIndex('idx_created_by', '{{%comment}}', ['created_by']);
27 | $this->createIndex('idx_created_at', '{{%comment}}', ['created_at']);
28 | }
29 |
30 | public function safeDown()
31 | {
32 | $this->dropTable('{{%comment}}');
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/migrations/m151005_165040_comment_from.php:
--------------------------------------------------------------------------------
1 | addColumn('{{%comment}}', 'from', $this->string()->after('entity'));
11 | }
12 |
13 | public function down()
14 | {
15 | $this->dropColumn('{{%comment}}', 'from');
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/models/Comment.php:
--------------------------------------------------------------------------------
1 | BlameableBehavior::className(),
44 | 'timestamp' => TimestampBehavior::className(),
45 | ];
46 | }
47 |
48 | /**
49 | * @inheritdoc
50 | */
51 | public function rules()
52 | {
53 | return [
54 | [['text'], 'required'],
55 | [['from', 'text'], 'string'],
56 | [['created_by', 'updated_by', 'created_at', 'updated_at'], 'integer'],
57 | [['deleted'], 'boolean'],
58 | [['deleted'], 'default', 'value' => self::NOT_DELETED],
59 | ];
60 | }
61 |
62 | /**
63 | * @inheritdoc
64 | */
65 | public function attributeLabels()
66 | {
67 | return [
68 | 'id' => \Yii::t('app', 'ID'),
69 | 'entity' => \Yii::t('app', 'Entity'),
70 | 'from' => \Yii::t('app', 'Comment author'),
71 | 'text' => \Yii::t('app', 'Text'),
72 | 'created_by' => \Yii::t('app', 'Created by'),
73 | 'updated_by' => \Yii::t('app', 'Updated by'),
74 | 'created_at' => \Yii::t('app', 'Created at'),
75 | 'updated_at' => \Yii::t('app', 'Updated at'),
76 | ];
77 | }
78 |
79 | /**
80 | * @return bool
81 | */
82 | public function isEdited()
83 | {
84 | return $this->created_at !== $this->updated_at;
85 | }
86 |
87 | /**
88 | * @return bool
89 | */
90 | public function isDeleted()
91 | {
92 | return $this->deleted === self::DELETED;
93 | }
94 |
95 | /**
96 | * @return bool
97 | */
98 | public static function canCreate()
99 | {
100 | return Comments\Module::instance()->useRbac === true
101 | ? \Yii::$app->getUser()->can(Comments\Permission::CREATE)
102 | : true;
103 | }
104 |
105 | /**
106 | * @return bool
107 | */
108 | public function canUpdate()
109 | {
110 | $User = \Yii::$app->getUser();
111 |
112 | return Comments\Module::instance()->useRbac === true
113 | ? (\Yii::$app->getUser()->can(Comments\Permission::UPDATE) || \Yii::$app->getUser()->can(Comments\Permission::UPDATE_OWN, ['Comment' => $this]))
114 | : ($User->isGuest ? false : ($this->created_by === $User->id));
115 | }
116 |
117 | /**
118 | * @return bool
119 | */
120 | public function canDelete()
121 | {
122 | $User = \Yii::$app->getUser();
123 |
124 | return Comments\Module::instance()->useRbac === true
125 | ? (\Yii::$app->getUser()->can(Comments\Permission::DELETE) || \Yii::$app->getUser()->can(Comments\Permission::DELETE_OWN, ['Comment' => $this]))
126 | : ($User->isGuest ? false : ($this->created_by === $User->id));
127 | }
128 |
129 | /**
130 | * @return queries\CommentQuery
131 | */
132 | public function getAuthor()
133 | {
134 | return $this->hasOne(Comments\Module::instance()->userIdentityClass, ['id' => 'created_by']);
135 | }
136 |
137 | /**
138 | * @return queries\CommentQuery
139 | */
140 | public function getLastUpdateAuthor()
141 | {
142 | return $this->hasOne(Comments\Module::instance()->userIdentityClass, ['id' => 'updated_by']);
143 | }
144 |
145 | /**
146 | * @return queries\CommentQuery
147 | */
148 | public static function find()
149 | {
150 | return \Yii::createObject(
151 | Comments\Module::instance()->model('commentQuery'),
152 | [get_called_class()]
153 | );
154 | }
155 |
156 | /**
157 | * @inheritdoc
158 | */
159 | public static function tableName()
160 | {
161 | return '{{%comment}}';
162 | }
163 |
164 | const NOT_DELETED = 0;
165 | const DELETED = 1;
166 | }
--------------------------------------------------------------------------------
/models/queries/CommentQuery.php:
--------------------------------------------------------------------------------
1 | andWhere(['id' => $id]);
29 |
30 | return $this;
31 | }
32 |
33 | /**
34 | * @param string|array $entity
35 | * @return static
36 | */
37 | public function byEntity($entity)
38 | {
39 | $this->andWhere(['entity' => $entity]);
40 |
41 | return $this;
42 | }
43 |
44 | /**
45 | * @return static
46 | */
47 | public function withoutDeleted()
48 | {
49 | /** @var Comments\models\Comment $CommentModel */
50 | $CommentModel = \Yii::createObject(Comments\Module::instance()->model('comment'));
51 |
52 | $this->andWhere(['deleted' => $CommentModel::NOT_DELETED]);
53 |
54 | return $this;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |