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

heimrichhannot / contao-utils-bundle / 13951376717

19 Mar 2025 04:12PM UTC coverage: 79.32% (+5.6%) from 73.745%
13951376717

push

github

web-flow
Forwardport #87 (#93)

* forwardport #87

* updated tests

* refactored some deprecated code into finder

* fix phpstan reports

* update tests

* add more test coverage

* raise test coveage

* fix bug

---------

Co-authored-by: DDEV User <nobody@example.com>

142 of 178 new or added lines in 6 files covered. (79.78%)

2 existing lines in 1 file now uncovered.

1097 of 1383 relevant lines covered (79.32%)

3.28 hits per line

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

58.93
/src/EntityFinder/EntityFinderHelper.php
1
<?php
2

3
/*
4
 * Copyright (c) 2022 Heimrich & Hannot GmbH
5
 *
6
 * @license LGPL-3.0-or-later
7
 */
8

9
namespace HeimrichHannot\UtilsBundle\EntityFinder;
10

11
use Contao\ContentModel;
12
use Contao\CoreBundle\Framework\ContaoFramework;
13
use Contao\Database;
14
use Contao\Model;
15
use Contao\Model\Collection;
16
use Contao\ModuleModel;
17
use Contao\Validator;
18
use Doctrine\DBAL\Connection;
19
use HeimrichHannot\UtilsBundle\Util\Utils;
20

21
class EntityFinderHelper
22
{
23
    public function __construct(
24
        private readonly Utils           $utils,
25
        private readonly ContaoFramework $framework,
26
        private readonly Connection      $connection,
27
    )
28
    {
29
    }
2✔
30

31
    /**
32
     * Search within serialized array fields of the model entity.
33
     *
34
     * @param string $type   Module type
35
     * @param string $field  Field with serialized data
36
     * @param array  $values Values to search for in serialized data field
37
     *
38
     * @throws \Exception
39
     */
40
    public function findModulesByTypeAndSerializedValue(string $type, string $field, array $values): ?Collection
41
    {
42
        $blobQuery = $this->utils->database()->createWhereForSerializedBlob(ModuleModel::getTable().'.'.$field, $values);
1✔
43
        $columns = [$blobQuery->createOrWhere()];
1✔
44
        $values = $blobQuery->values;
1✔
45

46
        $columns[] = ModuleModel::getTable().'.type=?';
1✔
47
        $values[] = $type;
1✔
48

49
        return $this->framework->getAdapter(ModuleModel::class)->findBy($columns, $values);
1✔
50
    }
51

52
        /**
53
     * Find frontend modules by insert inserttags like insert_module oder insert_article.
54
     *
55
     * @param string $type The module type
56
     * @param string $field The tl_module field
57
     * @param string $inserttag The inserttag to search for, for example insert_module
58
     * @param int $id The element id to search for, for example the module id (as used in {{insert_module::1}}, would be 1 in this case)
59
     * @return array The found module ids
60
     * @throws \Exception
61
     */
62
    public function findModulesByInserttag(string $type, string $field, string $inserttag, int $id): array
63
    {
64
        if (!Validator::isAlias($field)) {
×
65
            throw new \Exception('Invalid field name '.$field.'given.');
×
66
        }
67
        if (!Validator::isAlias($inserttag)) {
×
68
            throw new \Exception('Invalid inserttag '.$inserttag.'given.');
×
69
        }
70
        $result = Database::getInstance()
×
71
            ->prepare("SELECT id FROM tl_module
×
72
                        WHERE type=?
73
                        AND (
74
                            $field LIKE '%{{".$inserttag."::".$id."}}%'
×
75
                            OR $field LIKE '%{{".$inserttag."::".$id."::%')")
×
76
            ->execute($type);
×
77

78
        return $result->fetchEach('id');
×
79
    }
80

81

82
    /**
83
     * Find content elements by insert inserttags like insert_module oder insert_article.
84
     *
85
     * @param string $type The element type
86
     * @param string $field The tl_content field
87
     * @param string $inserttag The inserttag to search for, for example insert_module
88
     * @param int $id The element id to search for, for example the module id (as used in {{insert_module::1}}, would be 1 in this case)
89
     * @return array<ContentModel> The found content element ids
90
     * @throws \Exception
91
     */
92
    public function findContentElementByInserttag(string $type, string $field, string $inserttag, int $id): array
93
    {
94
        if (!Validator::isAlias($field)) {
×
95
            throw new \Exception('Invalid field name '.$field.'given.');
×
96
        }
97
        if (!Validator::isAlias($inserttag)) {
×
98
            throw new \Exception('Invalid inserttag '.$inserttag.'given.');
×
99
        }
100
        $result = Database::getInstance()
×
101
            ->prepare("SELECT id FROM tl_content
×
102
                        WHERE type=?
103
                        AND (
104
                            $field LIKE '%{{".$inserttag."::".$id."}}%'
×
105
                            OR $field LIKE '%{{".$inserttag."::".$id."::%')")
×
106
            ->execute($type);
×
107

108
        return $result->fetchEach('id');
×
109
    }
110

111
    /**
112
     * @throws \Doctrine\DBAL\Exception
113
     */
114
    public function fetchModelOrData(string $table, int|string $idOrAlias): ?Model
115
    {
116
        /** @var class-string<Model> $modelClass */
117
        $modelClass = $this->framework->getAdapter(Model::class)->getClassFromTable($table);
1✔
118

119
        if (!$modelClass || !class_exists($modelClass)) {
1✔
120
            if (!$this->connection->createSchemaManager()->tablesExist([$table])) {
1✔
121
                return null;
1✔
122
            }
123
            if (is_string($idOrAlias)) {
1✔
124
                $result = $this->connection->executeQuery("SELECT * FROM $table WHERE alias=?", [$idOrAlias]);
1✔
125
                if ($result->rowCount() === 0) {
1✔
126
                    return null;
1✔
127
                }
128
                return $this->anonymousModel($table, $result->fetchAssociative());
1✔
129
            }
130
            if (is_numeric($idOrAlias)) {
1✔
131
                if ($idOrAlias != (int) $idOrAlias) {
1✔
NEW
132
                    return null;
×
133
                }
134

135
                $result = $this->connection->executeQuery("SELECT * FROM $table WHERE id=?", [(int)$idOrAlias]);
1✔
136
                if ($result->rowCount() === 0) {
1✔
137
                    return null;
1✔
138
                }
139
                return $this->anonymousModel($table, $result->fetchAssociative());
1✔
140
            }
141
        }
142

143
        return $this->framework->getAdapter($modelClass)->findByIdOrAlias($idOrAlias);
1✔
144
    }
145

146
    private function anonymousModel(string $table, array $data): Model
147
    {
148
        return new class($table, $data) extends Model {
1✔
149

150
            protected $blnPreventSaving = true;
151

152
            public function __construct(string $table, array $data = [])
153
            {
154
                $this->strTable = $table;
1✔
155
                $this->setRow($data);
1✔
156
            }
157

158
            public function __set($strKey, $varValue)
159
            {
160
                if (isset($this->arrData[$strKey]) && $this->arrData[$strKey] === $varValue)
1✔
161
                {
NEW
162
                    return;
×
163
                }
164

165
                $this->arrData[$strKey] = $varValue;
1✔
166
            }
167

168
            public function setRow(array $arrData)
169
            {
170
                foreach ($arrData as $k => $v)
1✔
171
                {
172
                    if (static::isJoinedField($k))
1✔
173
                    {
NEW
174
                        unset($arrData[$k]);
×
175
                    }
176
                }
177

178
                $this->arrData = $arrData;
1✔
179

180
                return $this;
1✔
181
            }
182
        };
1✔
183
    }
184
}
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

© 2025 Coveralls, Inc