Issues (219)

Branch: 4-cactus

Core/src/Model/Behavior/CategoriesBehavior.php (1 issue)

1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2019 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
14
namespace BEdita\Core\Model\Behavior;
15
16
use BEdita\Core\Model\Entity\Tag;
17
use Cake\Datasource\EntityInterface;
18
use Cake\Event\Event;
19
use Cake\ORM\Behavior;
20
use Cake\ORM\TableRegistry;
21
use Cake\Utility\Hash;
22
use Cake\Utility\Inflector;
23
24
/**
25
 * Categories and Tags behavior
26
 *
27
 * @since 4.1.0
28
 */
29
class CategoriesBehavior extends Behavior
30
{
31
    /**
32
     * Set categories or tags `id` in save data or
33
     *
34
     * @param \Cake\Event\Event $event Fired event.
35
     * @param \Cake\Datasource\EntityInterface $entity Entity.
36
     * @return void
37
     */
38
    public function beforeSave(Event $event, EntityInterface $entity)
0 ignored issues
show
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

38
    public function beforeSave(/** @scrutinizer ignore-unused */ Event $event, EntityInterface $entity)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
39
    {
40
        if ($entity->get('tags')) {
41
            $this->prepareData('tags', $entity);
42
        }
43
        if ($entity->get('categories')) {
44
            $this->prepareData('categories', $entity);
45
        }
46
    }
47
48
    /**
49
     * Prepare 'categories' or 'tags' data
50
     *
51
     * @param string $item Item type, 'tags' or 'categories'
52
     * @param \Cake\Datasource\EntityInterface $entity Entity data
53
     * @return void
54
     */
55
    protected function prepareData(string $item, EntityInterface $entity): void
56
    {
57
        if (!$entity->isDirty($item)) {
58
            unset($entity[$item]);
59
60
            return;
61
        }
62
        // Check if `Tags` or `Categories` associations are enabled
63
        $objectType = $this->getTable()
64
            ->getAssociation('ObjectTypes')
65
            ->get($entity->get('type'));
66
        if (!in_array(Inflector::humanize($item), (array)$objectType->get('associations'))) {
67
            unset($entity[$item]);
68
69
            return;
70
        }
71
72
        if ($item === 'categories') {
73
            $entities = $this->fetchCategories($entity, $objectType);
74
        } else {
75
            $entities = $this->fetchTags($entity);
76
        }
77
        $this->updateData($item, $entity, $entities);
78
    }
79
80
    /**
81
     * Fetch categories with id from entity data
82
     *
83
     * @param \Cake\Datasource\EntityInterface $entity Entity data
84
     * @param \Cake\Datasource\EntityInterface $objectType Object type entity
85
     * @return array
86
     */
87
    protected function fetchCategories(EntityInterface $entity, EntityInterface $objectType): array
88
    {
89
        $data = (array)$entity->get('categories');
90
        $options = [
91
            'names' => Hash::extract($data, '{n}.name'),
92
            'typeId' => (int)$objectType->get('id'),
93
        ];
94
95
        return TableRegistry::getTableLocator()->get('Categories')
96
                ->find('ids', $options)
97
                ->toArray();
98
    }
99
100
    /**
101
     * Fetch tags with id from entity.
102
     * Create new tag if no existing tag is found.
103
     *
104
     * @param \Cake\Datasource\EntityInterface $entity Entity data
105
     * @return array
106
     */
107
    protected function fetchTags(EntityInterface $entity): array
108
    {
109
        return array_filter(array_map(
110
            function ($item) {
111
                return $this->checkTag($item);
112
            },
113
            (array)$entity->get('tags')
114
        ));
115
    }
116
117
    /**
118
     * Check if tag exists
119
     *  - the existing Tag is returned if found
120
     *  - a new Tag is created if missing
121
     *  - NULL is returned if Tag exists but is disabled
122
     *
123
     * @param \BEdita\Core\Model\Entity\Tag $item Tag entity to check or create
124
     * @return \BEdita\Core\Model\Entity\Tag|null
125
     */
126
    protected function checkTag(Tag $item): ?Tag
127
    {
128
        $Tags = TableRegistry::getTableLocator()->get('Tags');
129
        $name = Hash::get($item, 'name');
130
        /** @var \BEdita\Core\Model\Entity\Tag|null $tag */
131
        $tag = $Tags->find()
132
            ->where([$Tags->aliasField('name') => $name])
133
            ->first();
134
135
        if (empty($tag)) {
136
            $label = Hash::get($item, 'label', Inflector::humanize($name));
137
            $tag = $Tags->newEntity(compact('name', 'label'));
138
139
            return $Tags->saveOrFail($tag);
140
        }
141
142
        if ($tag->get('enabled')) {
143
            return $tag;
144
        }
145
146
        return null;
147
    }
148
149
    /**
150
     * Update entity data from using tag or category entities array.
151
     * Data are removed if no category or tag has been found.
152
     *
153
     * @param string $item Item type, 'tags' or 'categories'
154
     * @param \Cake\Datasource\EntityInterface $entity Entity data
155
     * @param array $entities Entities array with 'name' and 'id'
156
     * @return void
157
     */
158
    protected function updateData(string $item, EntityInterface $entity, array $entities): void
159
    {
160
        $names = Hash::combine($entities, '{n}.name', '{n}.id');
161
        $data = (array)$entity->get($item);
162
        foreach ($data as $k => $value) {
163
            $name = $value['name'];
164
            if (!empty($names[$name])) {
165
                $data[$k]['id'] = $names[$name];
166
            } else {
167
                unset($data[$k]);
168
            }
169
        }
170
        $entity->set($item, $data);
171
    }
172
}
173