Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
61.11% covered (warning)
61.11%
22 / 36
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImageAssociableBehavior
61.11% covered (warning)
61.11%
22 / 36
50.00% covered (danger)
50.00%
2 / 4
15.88
0.00% covered (danger)
0.00%
0 / 1
 initialize
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 afterSave
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
3.14
 saveImages
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 unlinkImages
100.00% covered (success)
100.00%
12 / 12
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\Datasource\EntityInterface;
8use Cake\Event\EventInterface;
9use Cake\ORM\Behavior;
10use Cake\ORM\TableRegistry;
11
12/**
13 * ImageAssociable Behavior
14 *
15 * This behavior allows models to associate multiple images with their entities.
16 * It provides functionality for saving new image associations and unlinking existing ones.
17 * It uses the Images model so you get the resizing and AI analysis for free!
18 */
19class ImageAssociableBehavior extends Behavior
20{
21    /**
22     * Initialize method
23     *
24     * Sets up the belongsToMany association with the Images table.
25     *
26     * @param array $config The configuration settings for the behavior.
27     * @return void
28     */
29    public function initialize(array $config): void
30    {
31        parent::initialize($config);
32
33        $this->_table->belongsToMany('Images', [
34            'foreignKey' => 'foreign_key',
35            'targetForeignKey' => 'image_id',
36            'joinTable' => 'models_images',
37            'conditions' => ['ModelsImages.model' => $this->_table->getAlias()],
38        ]);
39    }
40
41    /**
42     * After save callback
43     *
44     * Handles saving new image uploads and unlinking images after an entity is saved.
45     *
46     * @param \Cake\Event\EventInterface $event The afterSave event that was fired.
47     * @param \Cake\Datasource\EntityInterface $entity The entity that was saved.
48     * @param \ArrayObject $options The options passed to the save method.
49     * @return void
50     */
51    public function afterSave(EventInterface $event, EntityInterface $entity, ArrayObject $options): void
52    {
53        if (!empty($entity->imageUploads)) {
54            $this->saveImages($entity);
55        }
56
57        if (!empty($entity->unlinkedImages)) {
58            $this->unlinkImages($entity, $entity->unlinkedImages);
59        }
60    }
61
62    /**
63     * Save images associated with an entity
64     *
65     * @param \Cake\Datasource\EntityInterface $entity The entity to associate images with.
66     * @return void
67     */
68    protected function saveImages(EntityInterface $entity): void
69    {
70        $imagesTable = TableRegistry::getTableLocator()->get('Images');
71        $modelsImagesTable = TableRegistry::getTableLocator()->get('ModelsImages');
72
73        foreach ($entity->imageUploads as $image) {
74            $imageEntity = $imagesTable->newEntity([
75                'file' => $image,
76                'name' => $image->getClientFilename(),
77            ]);
78            if ($imagesTable->save($imageEntity)) {
79                $modelsImagesTable->save($modelsImagesTable->newEntity([
80                    'model' => $this->_table->getAlias(),
81                    'foreign_key' => $entity->id,
82                    'image_id' => $imageEntity->id,
83                ]));
84            }
85        }
86    }
87
88    /**
89     * Unlink images from an entity
90     *
91     * @param \Cake\Datasource\EntityInterface $entity The entity to unlink images from.
92     * @param array $imageIds The IDs of images to unlink.
93     * @return void
94     */
95    public function unlinkImages(EntityInterface $entity, array $imageIds): void
96    {
97        $imageIds = array_filter($imageIds, function ($value) {
98            return $value !== '0';
99        });
100
101        if (empty($imageIds)) {
102            return;
103        }
104
105        $modelsImagesTable = TableRegistry::getTableLocator()->get('ModelsImages');
106
107        foreach ($imageIds as $imageId) {
108            $modelsImagesTable->deleteAll([
109                'model' => $this->_table->getAlias(),
110                'foreign_key' => $entity->id,
111                'image_id' => $imageId,
112            ]);
113        }
114    }
115}