Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.71% covered (warning)
85.71%
36 / 42
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
CommentableBehavior
85.71% covered (warning)
85.71%
36 / 42
80.00% covered (warning)
80.00%
4 / 5
12.42
0.00% covered (danger)
0.00%
0 / 1
 initialize
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 clearEntityCache
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 beforeSave
14.29% covered (danger)
14.29%
1 / 7
0.00% covered (danger)
0.00%
0 / 1
14.08
 addComment
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 getComments
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2declare(strict_types=1);
3
4namespace App\Model\Behavior;
5
6use ArrayObject;
7use Cake\Cache\Cache;
8use Cake\Datasource\EntityInterface;
9use Cake\Event\EventInterface;
10use Cake\ORM\Behavior;
11use Cake\ORM\ResultSet;
12
13/**
14 * CommentableBehavior class
15 *
16 * This behavior provides functionality to manage comments associated with a model.
17 */
18class CommentableBehavior extends Behavior
19{
20    /**
21     * @var array<string, mixed>
22     */
23    protected array $_defaultConfig = [
24        'commentsTable' => 'Comments',
25        'foreignKey' => 'foreign_key',
26        'modelField' => 'model',
27        'userField' => 'user_id',
28        'contentField' => 'content',
29    ];
30
31    /**
32     * Initialize the behavior with the given configuration.
33     *
34     * @param array<string, mixed> $config The configuration settings provided to the behavior.
35     * @return void
36     */
37    public function initialize(array $config): void
38    {
39        parent::initialize($config);
40
41        $this->_table->hasMany($this->getConfig('commentsTable'), [
42            'foreignKey' => $this->getConfig('foreignKey'),
43            'conditions' => [
44                $this->getConfig('commentsTable') . '.' . $this->getConfig('modelField') => $this->_table->getAlias(),
45            ],
46            'dependent' => true,
47        ]);
48    }
49
50    /**
51     * Clear the cache for a specific entity.
52     *
53     * @param string $entityId The ID of the entity to clear cache for.
54     * @return void
55     */
56    protected function clearEntityCache(string $entityId): void
57    {
58        $entity = $this->_table->get($entityId);
59        if ($entity->slug) {
60            Cache::delete("article_{$entity->slug}", 'content');
61        }
62    }
63
64    /**
65     * Before save callback.
66     *
67     * Automatically saves new comments associated with the entity.
68     *
69     * @param \Cake\Event\EventInterface $event The beforeSave event that was fired.
70     * @param \Cake\Datasource\EntityInterface $entity The entity that is going to be saved.
71     * @param \ArrayObject $options The options passed to the save operation.
72     * @return void
73     */
74    public function beforeSave(EventInterface $event, EntityInterface $entity, ArrayObject $options): void
75    {
76        if ($entity->isNew() && !empty($entity->comments)) {
77            $commentsTable = $this->_table->getAssociation($this->getConfig('commentsTable'))->getTarget();
78            foreach ($entity->comments as $comment) {
79                $commentEntity = $commentsTable->newEntity($comment);
80                $commentEntity->set($this->getConfig('foreignKey'), $entity->id);
81                $commentEntity->set($this->getConfig('modelField'), $this->_table->getAlias());
82                $commentsTable->save($commentEntity);
83            }
84        }
85    }
86
87    /**
88     * Add a comment to an entity.
89     *
90     * @param string $entityId The ID of the entity to which the comment is related.
91     * @param string $userId The ID of the user who made the comment.
92     * @param string $content The content of the comment.
93     * @return \Cake\Datasource\EntityInterface|false The saved comment entity or false on failure.
94     */
95    public function addComment(string $entityId, string $userId, string $content): EntityInterface|false
96    {
97        $commentsTable = $this->_table->getAssociation($this->getConfig('commentsTable'))->getTarget();
98        $comment = $commentsTable->newEntity([
99            $this->getConfig('foreignKey') => $entityId,
100            $this->getConfig('modelField') => $this->_table->getAlias(),
101            $this->getConfig('userField') => $userId,
102            $this->getConfig('contentField') => $content,
103        ]);
104
105        $result = $commentsTable->save($comment);
106
107        if ($result) {
108            $this->clearEntityCache($entityId);
109        }
110
111        return $result;
112    }
113
114    /**
115     * Retrieve comments associated with an entity.
116     *
117     * @param string $entityId The ID of the entity for which to retrieve comments.
118     * @param array<string, mixed> $options Options for the query, such as 'order' and 'limit'.
119     * @return \Cake\ORM\ResultSet The result set containing the comments.
120     */
121    public function getComments(string $entityId, array $options = []): ResultSet
122    {
123        $commentsTable = $this->_table->getAssociation($this->getConfig('commentsTable'))->getTarget();
124        $query = $commentsTable->find();
125        $query->where([
126            $this->getConfig('foreignKey') => $entityId,
127            $this->getConfig('modelField') => $this->_table->getAlias(),
128            'display' => true,
129        ]);
130
131        if (!empty($options['order'])) {
132            $query->orderBy($options['order']);
133        } else {
134            $query->orderBy(['created' => 'DESC']);
135        }
136
137        if (!empty($options['limit'])) {
138            $query->limit($options['limit']);
139        }
140
141        return $query->all();
142    }
143}