Blame view

widgets/CommentWidget.php 13.8 KB
a2cde075   Yarik   first commit
1
2
  <?php
      
faff2c48   Yarik   Artbox comment cr...
3
      namespace artbox\webcomment\widgets;
a2cde075   Yarik   first commit
4
      
faff2c48   Yarik   Artbox comment cr...
5
6
7
8
9
      use artbox\webcomment\assets\CommentAsset;
      use artbox\webcomment\models\CommentModel;
      use artbox\webcomment\models\interfaces\CommentInterface;
      use artbox\webcomment\models\RatingModel;
      use artbox\webcomment\Module;
a2cde075   Yarik   first commit
10
11
12
13
14
15
16
17
18
19
20
21
      use Yii;
      use yii\base\InvalidConfigException;
      use yii\base\Model;
      use yii\base\Widget;
      use yii\data\ActiveDataProvider;
      use yii\db\ActiveRecord;
      use yii\helpers\ArrayHelper;
      use yii\helpers\Html;
      use yii\helpers\Json;
      
      /**
       * Class CommentWidget
faff2c48   Yarik   Artbox comment cr...
22
       *
a2cde075   Yarik   first commit
23
       * @property Model $model Model, to which comment attached
a2cde075   Yarik   first commit
24
25
26
27
28
29
       */
      class CommentWidget extends Widget
      {
          
          /**
           * Model, to which comment attached
faff2c48   Yarik   Artbox comment cr...
30
           *
a2cde075   Yarik   first commit
31
32
33
34
35
36
           * @var Model Model
           */
          //public $model;
          
          /**
           * Options
faff2c48   Yarik   Artbox comment cr...
37
           *
a2cde075   Yarik   first commit
38
39
40
41
42
43
44
45
46
47
           * @var array
           */
          public $options = [
              'class' => 'artbox_comment_container comments-start',
              'id'    => 'artbox-comment',
          ];
          
          /**
           * @var string the view file that will render comment form.
           */
faff2c48   Yarik   Artbox comment cr...
48
          public $formView = '@artbox/webcomment/views/artbox_comment_form';
a2cde075   Yarik   first commit
49
50
51
          
          /**
           * Form options
faff2c48   Yarik   Artbox comment cr...
52
           *
a2cde075   Yarik   first commit
53
54
55
56
57
58
59
60
           * @var array
           */
          public $formOptions = [
              'class' => 'artbox_form_container',
          ];
          
          /**
           * Params to be passed to form
faff2c48   Yarik   Artbox comment cr...
61
           *
a2cde075   Yarik   first commit
62
63
64
65
66
67
68
           * @var array
           */
          public $formParams = [];
          
          /**
           * @var string the view file that will render comments list.
           */
faff2c48   Yarik   Artbox comment cr...
69
          public $listView = '@artbox/webcomment/views/artbox_comment_list';
a2cde075   Yarik   first commit
70
71
72
          
          /**
           * List options
faff2c48   Yarik   Artbox comment cr...
73
           *
a2cde075   Yarik   first commit
74
75
76
77
78
79
80
81
           * @var array
           */
          public $listOptions = [
              'class' => 'artbox_list_container',
          ];
          
          /**
           * List params
faff2c48   Yarik   Artbox comment cr...
82
           *
a2cde075   Yarik   first commit
83
84
85
86
87
88
           * @var array
           */
          public $listParams = [];
          
          /**
           * Reply options
faff2c48   Yarik   Artbox comment cr...
89
           *
a2cde075   Yarik   first commit
90
91
92
93
94
95
96
97
98
           * @var array
           */
          public $replyOptions = [
              'style' => 'display: none;',
              'class' => 'artbox_comment_reply_container',
          ];
          
          /**
           * Reply view
faff2c48   Yarik   Artbox comment cr...
99
           *
a2cde075   Yarik   first commit
100
101
           * @var string
           */
faff2c48   Yarik   Artbox comment cr...
102
          public $replyView = '@artbox/webcomment/views/artbox_comment_reply';
a2cde075   Yarik   first commit
103
104
105
          
          /**
           * Comment form ID. If you have multiple forms on the same page, please use unique IDs.
faff2c48   Yarik   Artbox comment cr...
106
           *
a2cde075   Yarik   first commit
107
108
109
110
111
112
           * @var string Form ID
           */
          public $formId = 'artbox-comment-form';
          
          /**
           * Comment list ID. If you have multiple forms on the same page, please use unique IDs.
faff2c48   Yarik   Artbox comment cr...
113
           *
a2cde075   Yarik   first commit
114
115
116
117
118
119
           * @var string List ID
           */
          public $listId = 'artbox-comment-list';
          
          /**
           * Item view
faff2c48   Yarik   Artbox comment cr...
120
           *
a2cde075   Yarik   first commit
121
122
           * @var string
           */
faff2c48   Yarik   Artbox comment cr...
123
          public $itemView = '@artbox/webcomment/views/artbox_comment_item';
a2cde075   Yarik   first commit
124
125
126
          
          /**
           * Item options
faff2c48   Yarik   Artbox comment cr...
127
           *
a2cde075   Yarik   first commit
128
129
130
131
132
133
134
135
136
137
138
139
           * @var array
           */
          public $itemOptions = [
              'class'     => 'artbox_item_container',
              'itemprop'  => 'review',
              'itemscope' => 'itemscope',
              'itemtype'  => 'http://schema.org/Review',
          ];
          
          /**
           * Entity ID attribute, default to primaryKey() if ActiveRecord and throws exception if not
           * set
faff2c48   Yarik   Artbox comment cr...
140
           *
a2cde075   Yarik   first commit
141
142
143
144
145
146
           * @var string entity id attribute
           */
          public $entityIdAttribute;
          
          /**
           * Info to be passed to Comment Model
faff2c48   Yarik   Artbox comment cr...
147
           *
a2cde075   Yarik   first commit
148
149
           * @var string $info Additional info
           */
faff2c48   Yarik   Artbox comment cr...
150
          public $info = null;
a2cde075   Yarik   first commit
151
152
153
          
          /**
           * Client options to be passed to JS
faff2c48   Yarik   Artbox comment cr...
154
           *
a2cde075   Yarik   first commit
155
156
157
158
159
           * @var array comment widget client options
           */
          public $clientOptions = [];
          
          /**
a2cde075   Yarik   first commit
160
161
162
163
164
165
166
167
           * @var string pjax container id
           */
          public $pjaxContainerId;
          
          public $layout = "<div class='comments-border'></div>{form} {reply_form} {list}";
          
          /**
           * Model fully namespaced classname
faff2c48   Yarik   Artbox comment cr...
168
           *
a2cde075   Yarik   first commit
169
170
171
172
173
174
           * @var string Model namespace
           */
          protected $entity;
          
          /**
           * Entity ID for attached model
faff2c48   Yarik   Artbox comment cr...
175
           *
a2cde075   Yarik   first commit
176
177
178
179
180
181
182
183
184
           * @var integer Entity ID
           */
          protected $entityId;
          
          /**
           * Encrypted data to be passed to Controller. Consist of:
           * * Model::className()
           * * entityId
           * * info (optional)
faff2c48   Yarik   Artbox comment cr...
185
           *
a2cde075   Yarik   first commit
186
187
188
189
190
191
           * @var string encrypted entity key
           */
          protected $encryptedEntityKey;
          
          /**
           * Parts for widget
faff2c48   Yarik   Artbox comment cr...
192
           *
a2cde075   Yarik   first commit
193
194
195
196
197
198
199
200
201
202
           * @var array $parts
           */
          protected $parts;
          
          /**
           * Initializes the widget params.
           */
          public function init()
          {
              // Module init
faff2c48   Yarik   Artbox comment cr...
203
204
205
206
              $module = Yii::$app->getModule(Module::$name);
              if (!$module) {
                  Module::registerMe();
              }
a2cde075   Yarik   first commit
207
208
              // Model init
              $model = $this->getModel();
faff2c48   Yarik   Artbox comment cr...
209
210
      
              if (empty($this->pjaxContainerId)) {
a2cde075   Yarik   first commit
211
212
213
214
215
                  $this->pjaxContainerId = 'comment-pjax-container-' . $this->getId();
              }
              
              $this->entity = $model::className();
              // Entity ID init
faff2c48   Yarik   Artbox comment cr...
216
              if (!empty($this->entityIdAttribute) && $this->model->hasProperty($this->entityIdAttribute)) {
a2cde075   Yarik   first commit
217
218
                  $this->entityId = $this->model->{$this->entityIdAttribute};
              } else {
faff2c48   Yarik   Artbox comment cr...
219
                  if ($this->model instanceof ActiveRecord && !empty($this->model->getPrimaryKey())) {
a2cde075   Yarik   first commit
220
221
                      $this->entityId = (int) $this->model->getPrimaryKey();
                  } else {
faff2c48   Yarik   Artbox comment cr...
222
223
224
                      throw new InvalidConfigException(
                          Yii::t('artbox-comment', 'The "entityIdAttribute" value for widget model cannot be empty.')
                      );
a2cde075   Yarik   first commit
225
226
227
228
229
230
231
232
233
234
235
                  }
              }
              
              // Generate encryptedEntityKey
              $this->encryptedEntityKey = $this->generateEntityKey();
              
              $this->registerAssets();
          }
          
          /**
           * Executes the widget.
faff2c48   Yarik   Artbox comment cr...
236
           *
a2cde075   Yarik   first commit
237
238
239
240
241
242
           * @return string the result of widget execution to be outputted.
           */
          public function run()
          {
              /* @var Module $module */
              $module = Yii::$app->getModule(Module::$name);
faff2c48   Yarik   Artbox comment cr...
243
244
245
              if (!$module) {
                  Module::registerMe();
              }
a2cde075   Yarik   first commit
246
              $commentModelClass = $module->commentModelClass;
faff2c48   Yarik   Artbox comment cr...
247
248
249
250
251
252
253
254
255
256
              $commentModel = $this->createModel(
                  $commentModelClass,
                  [
                      'entity'          => $this->entity,
                      'entityId'        => $this->entityId,
                      'encryptedEntity' => $this->encryptedEntityKey,
                      'scenario'        => \Yii::$app->user->getIsGuest(
                      ) ? CommentModel::SCENARIO_GUEST : CommentModel::SCENARIO_USER,
                  ]
              );
fd5e93c2   Yarik   Artbox comment pr...
257
              if ($module->enableRating) {
a2cde075   Yarik   first commit
258
259
260
                  $ratingModelClass = $module->ratingModelClass;
                  $ratingModel = $this->createRating($ratingModelClass);
              } else {
faff2c48   Yarik   Artbox comment cr...
261
262
263
264
265
266
                  $ratingModel = null;
              }
              if (method_exists($commentModelClass, 'getTree')) {
                  $comments = $commentModelClass::getTree($this->entity, $this->entityId);
              } else {
                  $comments = [];
a2cde075   Yarik   first commit
267
              }
a2cde075   Yarik   first commit
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
              
              $this->buildParts($commentModel, $comments, $ratingModel);
              
              return $this->renderWidget();
          }
          
          /**
           * Register assets.
           */
          protected function registerAssets()
          {
              $this->clientOptions[ 'formSelector' ] = '#' . $this->formId;
              $this->clientOptions[ 'listSelector' ] = '#' . $this->listId;
              $options = Json::encode($this->clientOptions);
              $view = $this->getView();
              CommentAsset::register($view);
              $view->registerJs("jQuery('#{$this->formId}').artbox_comment({$options});");
          }
          
          /**
           * Get encrypted entity key
faff2c48   Yarik   Artbox comment cr...
289
           *
a2cde075   Yarik   first commit
290
291
292
293
294
           * @return string
           */
          protected function generateEntityKey()
          {
              return Yii::$app->getSecurity()
faff2c48   Yarik   Artbox comment cr...
295
296
297
298
299
300
301
302
303
304
                              ->encryptByKey(
                                  Json::encode(
                                      [
                                          'entity'    => $this->entity,
                                          'entity_id' => $this->entityId,
                                          'info'      => $this->info,
                                      ]
                                  ),
                                  Module::$encryptionKey
                              );
a2cde075   Yarik   first commit
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
          }
          
          /**
           * Create comment model
           *
           * @param string $className Full namespaced model
           * @param array  $config    Init config
           *
           * @return CommentInterface Comment model
           * @throws InvalidConfigException If object not instance of \yii\base\Model
           */
          protected function createModel(string $className, array $config = []): CommentInterface
          {
              $options = array_merge($config, [ 'class' => $className ]);
              $object = Yii::createObject($options);
faff2c48   Yarik   Artbox comment cr...
320
              if ($object instanceof CommentInterface) {
a2cde075   Yarik   first commit
321
322
                  return $object;
              }
faff2c48   Yarik   Artbox comment cr...
323
324
325
              throw new InvalidConfigException(
                  Yii::t('artbox-comment', 'Comment model must be instance of CommentInterface.')
              );
a2cde075   Yarik   first commit
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
          }
          
          /**
           * Create rating model
           *
           * @param string $className Full namespaced model
           * @param array  $config    Init config
           *
           * @return CommentInterface|RatingModel Comment model
           * @throws InvalidConfigException If object not instance of \yii\base\Model
           */
          protected function createRating(string $className, array $config = []): RatingModel
          {
              $options = array_merge($config, [ 'class' => $className ]);
              $object = Yii::createObject($options);
faff2c48   Yarik   Artbox comment cr...
341
              if ($object instanceof RatingModel) {
a2cde075   Yarik   first commit
342
343
                  return $object;
              }
faff2c48   Yarik   Artbox comment cr...
344
345
346
              throw new InvalidConfigException(
                  Yii::t('artbox-comment', 'Comment model must be instance of RatingModel.')
              );
a2cde075   Yarik   first commit
347
348
349
350
351
352
353
354
355
          }
          
          /**
           * Build parts for rendering widget
           *
           * @param CommentInterface   $commentModel
           * @param ActiveDataProvider $comments
           * @param null|RatingModel   $ratingModel
           */
faff2c48   Yarik   Artbox comment cr...
356
          protected function buildParts(CommentInterface $commentModel, ActiveDataProvider $comments, $ratingModel = null)
a2cde075   Yarik   first commit
357
358
          {
              $form_options = $this->formOptions;
faff2c48   Yarik   Artbox comment cr...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
              $this->parts[ 'form' ] = Html::tag(
                  ArrayHelper::remove($form_options, 'tag', 'div'),
                  $this->render(
                      $this->formView,
                      [
                          'comment_model' => $commentModel,
                          'form_params'   => $this->formParams,
                          'model'         => $this->getModel(),
                          'formId'        => $this->formId,
                          'rating_model'  => $ratingModel,
                      ]
                  ),
                  $form_options
              );
      
              if (!\Yii::$app->user->isGuest) {
a2cde075   Yarik   first commit
375
                  $reply_options = $this->replyOptions;
faff2c48   Yarik   Artbox comment cr...
376
377
378
379
380
381
382
383
384
385
386
387
388
                  $this->parts[ 'reply_form' ] = Html::tag(
                      ArrayHelper::remove($reply_options, 'tag', 'div'),
                      $this->render(
                          $this->replyView,
                          [
                              'comment_model' => $commentModel,
                              'form_params'   => $this->formParams,
                              'model'         => $this->getModel(),
                              'formId'        => $this->formId,
                          ]
                      ),
                      $reply_options
                  );
a2cde075   Yarik   first commit
389
390
391
              }
              
              $list_options = array_merge($this->listOptions, [ 'id' => $this->listId ]);
faff2c48   Yarik   Artbox comment cr...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
              $this->parts[ 'list' ] = Html::tag(
                  ArrayHelper::remove($list_options, 'tag', 'div'),
                  $this->render(
                      $this->listView,
                      [
                          'comment_model' => $commentModel,
                          'list_params'   => $this->listParams,
                          'model'         => $this->getModel(),
                          'comments'      => $comments,
                          'item_options'  => $this->itemOptions,
                          'item_view'     => $this->itemView,
                      ]
                  ),
                  $list_options
              );
a2cde075   Yarik   first commit
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
          }
          
          /**
           * @return string
           */
          protected function renderWidget(): string
          {
              $layout = $this->layout;
              $parts = $this->parts;
              $options = $this->options;
              $layout = preg_replace('/{list}/', ArrayHelper::getValue($parts, 'list', ''), $layout);
              $layout = preg_replace('/{form}/', ArrayHelper::getValue($parts, 'form', ''), $layout);
              $layout = preg_replace('/{reply_form}/', ArrayHelper::getValue($parts, 'reply_form', ''), $layout);
              $tag = ArrayHelper::remove($options, 'tag', 'div');
              return Html::tag($tag, $layout, $options);
          }
          
          public function setModel(Model $model)
          {
              $this->model = $model;
          }
          
          public function getModel(): Model
          {
faff2c48   Yarik   Artbox comment cr...
431
              if (!empty($this->model)) {
a2cde075   Yarik   first commit
432
433
                  return $this->model;
              }
faff2c48   Yarik   Artbox comment cr...
434
              throw new InvalidConfigException(Yii::t('artbox-comment', 'The "model" property must be set.'));
a2cde075   Yarik   first commit
435
436
          }
      }