RepositoryService::findOneBy()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 12
rs 10
cc 4
nc 3
nop 2
1
<?php
2
3
/*
4
 * This file is part of the core-bundle package.
5
 *
6
 * (c) 2022 WEBEWEB
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace WBW\Bundle\CoreBundle\Service;
13
14
use Doctrine\ORM\Mapping\ClassMetadata;
15
use PDO;
16
use Throwable;
17
use WBW\Library\Symfony\Model\RepositoryDetail;
18
use WBW\Library\Symfony\Model\RepositoryReport;
19
use WBW\Library\Symfony\Model\RepositoryReportInterface;
20
use WBW\Library\Types\Helper\ArrayHelper;
21
22
/**
23
 * Repository service.
24
 *
25
 * @author webeweb <https://github.com/webeweb>
26
 * @package WBW\Bundle\CoreBundle\Service
27
 */
28
class RepositoryService implements RepositoryServiceInterface {
29
30
    use StatementServiceTrait {
31
        setStatementService as public;
32
    }
33
34
    /**
35
     * Service name.
36
     *
37
     * @var string
38
     */
39
    const SERVICE_NAME = "wbw.core.service.repository";
40
41
    /**
42
     * {@inheritDoc}
43
     */
44
    public function findAll(): array {
45
46
        /** @var RepositoryReportInterface[] $reports */
47
        $reports = [];
48
49
        /** @var ClassMetadata[] $allMetadata */
50
        $allMetadata = $this->getStatementService()->getEntityManager()->getMetadataFactory()->getAllMetadata();
51
        foreach ($allMetadata as $current) {
52
53
            if (false === $current->isMappedSuperclass) {
54
                $reports[] = $this->findReport($current);
55
            }
56
        }
57
58
        usort($reports, static::usortRepositoryReportCallback());
59
60
        return $reports;
61
    }
62
63
    /**
64
     * Find all repository details.
65
     *
66
     * @param ClassMetadata $classMetadata The class metadata.
67
     * @return RepositoryDetail[] Returns the repository details.
68
     * @throws Throwable Throws an exception if an error occurs.
69
     */
70
    protected function findDetails(ClassMetadata $classMetadata): array {
71
72
        /** @var RepositoryDetail[] $models */
73
        $models = [];
74
75
        foreach ($classMetadata->getFieldNames() as $current) {
76
77
            $fieldMapping = $classMetadata->getFieldMapping($current);
78
            if (false === in_array($fieldMapping["type"], ["string", "text"])) {
79
                continue;
80
            }
81
82
            $p = [
83
                $classMetadata->getTableName(),
84
                $classMetadata->getName(),
85
                $fieldMapping["columnName"],
86
                $fieldMapping["fieldName"],
87
                $fieldMapping["type"],
88
                ArrayHelper::get($fieldMapping, "length", -1),
89
            ];
90
91
            $models[] = $this->newRepositoryDetail($p[0], $p[1], $p[2], $p[3], $p[4], $p[5]);
92
        }
93
94
        return $models;
95
    }
96
97
    /**
98
     * Find one repository report.
99
     *
100
     * @param callable $criteria The criteria.
101
     * @param string $value The value.
102
     * @return RepositoryReportInterface|null Returns the repository report.
103
     * @throws Throwable Throws an exception if an error occurs.
104
     */
105
    protected function findOneBy(callable $criteria, string $value): ?RepositoryReportInterface {
106
107
        /** @var ClassMetadata[] $allMetadata */
108
        $allMetadata = $this->getStatementService()->getEntityManager()->getMetadataFactory()->getAllMetadata();
109
        foreach ($allMetadata as $current) {
110
111
            if (false === $current->isMappedSuperclass && $value === $criteria($current)) {
112
                return $this->findReport($current);
113
            }
114
        }
115
116
        return null;
117
    }
118
119
    /**
120
     * {@inheritDoc}
121
     */
122
    public function findOneByEntity(string $entity): ?RepositoryReportInterface {
123
124
        $criteria = function(ClassMetadata $classMetadata) {
125
            return $classMetadata->getName();
126
        };
127
128
        return $this->findOneBy($criteria, $entity);
129
    }
130
131
    /**
132
     * {@inheritDoc}
133
     */
134
    public function findOneByTable(string $table): ?RepositoryReportInterface {
135
136
        $criteria = function(ClassMetadata $classMetadata) {
137
            return $classMetadata->getTableName();
138
        };
139
140
        return $this->findOneBy($criteria, $table);
141
    }
142
143
    /**
144
     * Find one repository report.
145
     *
146
     * @param ClassMetadata $classMetadata The class metadata.
147
     * @return RepositoryReportInterface Returns the repository report.
148
     * @throws Throwable Throws an exception if an error occurs.
149
     */
150
    protected function findReport(ClassMetadata $classMetadata): RepositoryReportInterface {
151
152
        $query  = "SELECT COUNT(*) FROM {$classMetadata->getTableName()}";
153
        $result = $this->getStatementService()->executeQuery($query, []);
154
155
        $count = intval($result->fetchOne());
156
157
        $model = new RepositoryReport();
158
        $model->setTable($classMetadata->getTableName());
159
        $model->setEntity($classMetadata->getName());
160
        $model->setCount($count);
161
162
        $details = $this->findDetails($classMetadata);
163
        foreach ($details as $current) {
164
165
            if (null !== $current) {
166
                $model->addDetail($current->setRepositoryReport($model));
167
            }
168
        }
169
170
        return $model;
171
    }
172
173
    /**
174
     * Create a repository detail.
175
     *
176
     * @param string $table The table.
177
     * @param string $entity The entity.
178
     * @param string $column The column.
179
     * @param string $field The field.
180
     * @param string $type The type.
181
     * @param int $available The available.
182
     * @return RepositoryDetail Returns the repository detail.
183
     * @throws Throwable Throws an exception if an error occurs.
184
     */
185
    protected function newRepositoryDetail(string $table, string $entity, string $column, string $field, string $type, int $available): RepositoryDetail {
186
187
        $template = $this->getStatementService()->readStatementFile(__DIR__ . "/RepositoryService.sql");
188
189
        $searches = ["{{ table }}", "{{ column }}"];
190
        $replaces = [$table, $column];
191
192
        $sql = str_replace($searches, $replaces, $template);
193
194
        $stmt = $this->getStatementService()->prepareStatement($sql, [
195
            ":available" => [$available, PDO::PARAM_INT],
196
            ":column"    => [$column, PDO::PARAM_STR],
197
            ":entity"    => [$entity, PDO::PARAM_STR],
198
            ":field"     => [$field, PDO::PARAM_STR],
199
            ":table"     => [$table, PDO::PARAM_STR],
200
            ":type"      => [$type, PDO::PARAM_STR],
201
        ]);
202
203
        $result = $stmt->executeQuery();
204
205
        $row = $result->fetchAllAssociative()[0];
206
207
        $model = new RepositoryDetail();
208
        $model->setAvailable(intval($row["available"]));
209
        $model->setAverage(floatval($row["average"]));
210
        $model->setColumn($row["column"]);
211
        $model->setField($row["field"]);
212
        $model->setMaximum(intval($row["maximum"]));
213
        $model->setMinimum(intval($row["minimum"]));
214
        $model->setType($row["type"]);
215
216
        return $model;
217
    }
218
219
    /**
220
     * Usort repository report callback.
221
     *
222
     * @return callable Returns the usort repository report callback.
223
     */
224
    protected static function usortRepositoryReportCallback(): callable {
225
226
        return function(RepositoryReport $a, RepositoryReport $b): int {
227
            return strcmp($a->getTable(), $b->getTable());
0 ignored issues
show
Bug introduced by
It seems like $b->getTable() can also be of type null; however, parameter $string2 of strcmp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

227
            return strcmp($a->getTable(), /** @scrutinizer ignore-type */ $b->getTable());
Loading history...
Bug introduced by
It seems like $a->getTable() can also be of type null; however, parameter $string1 of strcmp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

227
            return strcmp(/** @scrutinizer ignore-type */ $a->getTable(), $b->getTable());
Loading history...
228
        };
229
    }
230
}
231