• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lonnieezell / Bonfire2 / 13500878002

24 Feb 2025 02:52PM UTC coverage: 45.404%. First build
13500878002

push

github

web-flow
Merge pull request #553 from dgvirtual/fix/meta-info-upd

Fixes and updates for HasMeta trait

25 of 28 new or added lines in 1 file covered. (89.29%)

1561 of 3438 relevant lines covered (45.4%)

63.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.95
/src/Core/Traits/HasMeta.php
1
<?php
2

3
/**
4
 * This file is part of Bonfire.
5
 *
6
 * (c) Lonnie Ezell <lonnieje@gmail.com>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11

12
namespace Bonfire\Core\Traits;
13

14
use Bonfire\Core\Models\MetaModel;
15

16
/**
17
 * Provides "meta-field" support to Entities.
18
 * This allows storing user-configurable bits of information
19
 * for other classes without the need to modify those
20
 * classes.
21
 *
22
 * NOTE: In order to work this assumes the Entity being
23
 * used on has a primary key called 'id'.
24
 */
25
trait HasMeta
26
{
27
    /**
28
     * Cache for meta info
29
     *
30
     * @var array
31
     */
32
    private $meta = [];
33

34
    /**
35
     * Have we already hyrdated out meta info?
36
     *
37
     * @var bool
38
     */
39
    private $metaHydrated = false;
40

41
    /**
42
     * Grabs the meta data for this entity.
43
     */
44
    protected function hydrateMeta(bool $refresh = false)
45
    {
46
        if ($this->metaHydrated && ! $refresh) {
36✔
47
            return;
36✔
48
        }
49

50
        if ($refresh) {
36✔
51
            $this->meta = [];
12✔
52
        }
53

54
        $meta = model(MetaModel::class)
36✔
55
            ->where('class', static::class)
36✔
56
            ->where('resource_id', $this->id)
36✔
57
            ->findAll();
36✔
58

59
        // Index the array by key
60
        foreach ($meta as $row) {
36✔
61
            $this->meta[$row->key] = $row;
12✔
62
        }
63

64
        $this->metaHydrated = true;
36✔
65
    }
66

67
    /**
68
     * Returns the value of the request $key
69
     *
70
     * @return mixed|null
71
     */
72
    public function meta(string $key)
73
    {
74
        $this->hydrateMeta();
12✔
75

76
        $key = strtolower($key);
12✔
77

78
        return isset($this->meta[$key])
12✔
79
            ? $this->meta[strtolower($key)]->value
12✔
80
            : null;
12✔
81
    }
82

83
    /**
84
     * Returns all meta info for this entity.
85
     *
86
     * @return array
87
     */
88
    public function allMeta()
89
    {
90
        $this->hydrateMeta();
6✔
91

92
        return $this->meta;
6✔
93
    }
94

95
    /**
96
     * Returns  meta info for this entity in simplified key => value form
97
     *
98
     * @return array
99
     */
100
    public function allMetaKeyValue()
101
    {
102
        $meta = $this->allMeta();
6✔
103
        $data = [];
6✔
104

105
        foreach ($meta as $key => $value) {
6✔
106
            $data[$key] = $value->value;
6✔
107
        }
108

109
        return $data;
6✔
110
    }
111

112
    /**
113
     * Does the entry have this meta information?
114
     */
115
    public function hasMeta(string $key): bool
116
    {
117
        $this->hydrateMeta();
30✔
118

119
        return array_key_exists(strtolower($key), $this->meta ?? []);
30✔
120
    }
121

122
    /**
123
     * Saves the meta information for this entity.
124
     *
125
     * @param mixed $value
126
     *
127
     * @return mixed
128
     */
129
    public function saveMeta(string $key, $value)
130
    {
131
        $this->hydrateMeta();
24✔
132
        $key   = strtolower($key);
24✔
133
        $model = model(MetaModel::class);
24✔
134

135
        // Update?
136
        if (array_key_exists($key, $this->meta)) {
24✔
137
            $result = $model
×
138
                ->where('class', static::class)
×
139
                ->where('resource_id', $this->id)
×
140
                ->where('key', $key)
×
NEW
141
                ->set(['value' => $value])
×
NEW
142
                ->update();
×
143
        }
144

145
        // Insert
146
        else {
147
            $result = $model
24✔
148
                ->insert([
24✔
149
                    'class'       => static::class,
24✔
150
                    'resource_id' => $this->id,
24✔
151
                    'key'         => $key,
24✔
152
                    'value'       => $value,
24✔
153
                ]);
24✔
154
        }
155

156
        $this->meta[$key] = $model
24✔
157
            ->where('class', static::class)
24✔
158
            ->where('resource_id', $this->id)
24✔
159
            ->where('key', $key)
24✔
160
            ->first();
24✔
161

162
        return $result;
24✔
163
    }
164

165
    /**
166
     * Deletes a single meta value from this entity
167
     * and from the database.
168
     *
169
     * @return mixed
170
     */
171
    public function deleteMeta(string $key)
172
    {
173
        // Ensure it is initially populated
174
        $this->hydrateMeta();
6✔
175
        $key = strtolower($key);
6✔
176

177
        // Delete stuff
178
        $result = model(MetaModel::class)
6✔
179
            ->where('class', static::class)
6✔
180
            ->where('resource_id', $this->id)
6✔
181
            ->where('key', $key)
6✔
182
            ->delete();
6✔
183

184
        if ($result) {
6✔
185
            unset($this->meta[$key]);
6✔
186
        }
187

188
        return $result;
6✔
189
    }
190

191
    /**
192
     * Deletes all meta values for an entity, usually on its deletion.
193
     *
194
     * @return mixed
195
     */
196
    public function deleteResourceMeta()
197
    {
198
        // Delete stuff
199
        $result = model(MetaModel::class)
6✔
200
            ->where('class', static::class)
6✔
201
            ->where('resource_id', $this->id)
6✔
202
            ->delete();
6✔
203

204
        if ($result) {
6✔
205
            unset($this->meta);
6✔
206
        }
207

208
        return $result;
6✔
209
    }
210

211
    /**
212
     * Ensures our meta info for this resource is up
213
     * to date with what is given in $post. If a key
214
     * doesn't exist, it's deleted, otherwise it is
215
     * either inserted or updated.
216
     */
217
    public function syncMeta(array $post): void
218
    {
219
        $this->hydrateMeta();
12✔
220
        helper('setting');
12✔
221

222
        $metaInfo = setting("{$this->configClass}.metaFields");
12✔
223
        if (empty($metaInfo)) {
12✔
224
            return;
×
225
        }
226

227
        foreach ($metaInfo as $fields) {
12✔
228
            if (! is_array($fields) || $fields === []) {
12✔
229
                continue;
×
230
            }
231

232
            $inserts = [];
12✔
233
            $updates = [];
12✔
234
            $deletes = [];
12✔
235
            // Keep only these fields
236
            $legal = [];
12✔
237

238
            foreach (array_keys($fields) as $field) {
12✔
239
                $field    = strtolower($field);
12✔
240
                $existing = array_key_exists($field, $this->meta);
12✔
241
                // add to keep list
242
                $legal[] = $field;
12✔
243

244
                // Not existing and no value?
245
                if (! $existing && ! array_key_exists($field, $post)) {
12✔
246
                    continue;
12✔
247
                }
248

249
                // Create a new one
250
                if (! $existing && ! empty($post[$field])) {
12✔
251
                    $inserts[] = [
12✔
252
                        'resource_id' => $this->id,
12✔
253
                        'key'         => $field,
12✔
254
                        'value'       => $post[$field],
12✔
255
                        'class'       => static::class,
12✔
256
                    ];
12✔
257

258
                    continue;
12✔
259
                }
260

261
                // Existing one with no value now
262
                if ($existing && array_key_exists($field, $post) && empty($post[$field])) {
12✔
263
                    $deletes[] = $this->meta[$field]->id;
12✔
264

265
                    continue;
12✔
266
                }
267

268
                // Update existing one
269
                if ($existing) {
6✔
270
                    $updates[] = [
6✔
271
                        'id'    => $this->meta[$field]->id,
6✔
272
                        'key'   => $field,
6✔
273
                        'value' => $post[$field],
6✔
274
                    ];
6✔
275
                }
276
            }
277
        }
278

279
        // check if meta in db is in keep list, if not, mark for deletion
280
        foreach ($this->meta as $key => $value) {
12✔
281
            if (! in_array($key, $legal, true)) {
12✔
NEW
282
                $deletes[] = $value->id;
×
283
            }
284
        }
285

286
        $model = model(MetaModel::class);
12✔
287

288
        if ($deletes !== []) {
12✔
289
            $model->whereIn('id', $deletes)->delete();
12✔
290
        }
291

292
        if ($inserts !== []) {
12✔
293
            $model->insertBatch($inserts);
12✔
294
        }
295

296
        if ($updates !== []) {
12✔
297
            $model->updateBatch($updates, 'id');
6✔
298
        }
299

300
        $this->hydrateMeta(true);
12✔
301
    }
302

303
    /**
304
     * Returns all the validation rules set
305
     * for the given entity
306
     *
307
     * @param string|null $prefix // Specifies the form array name, if any
308
     */
309
    public function metaValidationRules(?string $prefix = null): array
310
    {
311
        $rules = [];
×
312
        helper('setting');
×
313
        $metaInfo = setting("{$this->configClass}.metaFields");
×
314

315
        if (empty($metaInfo)) {
×
316
            return $rules;
×
317
        }
318

319
        foreach ($metaInfo as $rows) {
×
320
            if (! count($rows)) {
×
321
                continue;
×
322
            }
323

324
            foreach ($rows as $name => $row) {
×
325
                $name = strtolower($name);
×
326
                if ($prefix !== null && $prefix !== '' && $prefix !== '0') {
×
327
                    $name = "{$prefix}.{$name}";
×
328
                }
329

330
                if (isset($row['validation'])) {
×
331
                    $rules[$name] = $row['validation'];
×
332
                }
333
            }
334
        }
335

336
        return $rules;
×
337
    }
338
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc