Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImageGallerySeoUpdateJob
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 3
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getJobType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2declare(strict_types=1);
3
4namespace App\Job;
5
6use App\Service\Api\AiService;
7use Cake\Queue\Job\Message;
8use Interop\Queue\Processor;
9
10/**
11 * ImageGallerySeoUpdateJob
12 *
13 * This job is responsible for updating the SEO metadata of an image gallery using AI.
14 * It processes messages from the queue to update various SEO-related fields of a gallery.
15 */
16class ImageGallerySeoUpdateJob extends AbstractJob
17{
18    /**
19     * Instance of the AI service.
20     *
21     * @var \App\Service\Api\AiService
22     */
23    private AiService $aiService;
24
25    /**
26     * Constructor to allow dependency injection for testing
27     *
28     * @param \App\Service\Api\AiService|null $aiService
29     */
30    public function __construct(?AiService $aiService = null)
31    {
32        $this->aiService = $aiService ?? new AiService();
33    }
34
35    /**
36     * Get the human-readable job type name for logging
37     *
38     * @return string The job type description
39     */
40    protected static function getJobType(): string
41    {
42        return 'gallery SEO update';
43    }
44
45    /**
46     * Executes the job to update gallery SEO metadata.
47     *
48     * @param \Cake\Queue\Job\Message $message The message containing gallery data
49     * @return string|null Returns Processor::ACK on success, Processor::REJECT on failure
50     */
51    public function execute(Message $message): ?string
52    {
53        $id = $message->getArgument('id');
54        $name = $message->getArgument('name');
55
56        if (!$this->validateArguments($message, ['id', 'name'])) {
57            return Processor::REJECT;
58        }
59
60        return $this->executeWithErrorHandling($id, function () use ($id, $name) {
61            $galleriesTable = $this->getTable('ImageGalleries');
62            $gallery = $galleriesTable->get($id, ['contain' => ['Images']]);
63
64            // Prepare gallery context for AI analysis
65            $imageCount = is_array($gallery->images) ? count($gallery->images) : 0;
66            $galleryContext = sprintf(
67                'Gallery: %s. Description: %s. Contains %d images.',
68                $name,
69                $gallery->description ?: 'No description provided',
70                $imageCount,
71            );
72
73            $seoResult = $this->aiService->generateGallerySeo(
74                (string)$name,
75                $galleryContext,
76            );
77
78            if ($seoResult) {
79                $emptyFields = $galleriesTable->emptySeoFields($gallery);
80                array_map(fn($field) => $gallery->{$field} = $seoResult[$field], $emptyFields);
81
82                return $galleriesTable->save($gallery, ['noMessage' => true]);
83            }
84
85            return false;
86        }, $name);
87    }
88}