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

ICanBoogie / ActiveRecord / 6362433236

30 Sep 2023 11:14AM UTC coverage: 85.731% (+5.6%) from 80.178%
6362433236

push

github

olvlvl
Rename StaticModelProvider methods

1436 of 1675 relevant lines covered (85.73%)

29.41 hits per line

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

89.93
/lib/ActiveRecord/SchemaBuilder.php
1
<?php
2

3
namespace ICanBoogie\ActiveRecord;
4

5
use ICanBoogie\ActiveRecord;
6
use ICanBoogie\ActiveRecord\Schema\BelongsTo;
7
use ICanBoogie\ActiveRecord\Schema\Binary;
8
use ICanBoogie\ActiveRecord\Schema\Blob;
9
use ICanBoogie\ActiveRecord\Schema\Boolean;
10
use ICanBoogie\ActiveRecord\Schema\Character;
11
use ICanBoogie\ActiveRecord\Schema\Column;
12
use ICanBoogie\ActiveRecord\Schema\Date;
13
use ICanBoogie\ActiveRecord\Schema\DateTime;
14
use ICanBoogie\ActiveRecord\Schema\Decimal;
15
use ICanBoogie\ActiveRecord\Schema\Id;
16
use ICanBoogie\ActiveRecord\Schema\Index;
17
use ICanBoogie\ActiveRecord\Schema\Integer;
18
use ICanBoogie\ActiveRecord\Schema\SchemaAttribute;
19
use ICanBoogie\ActiveRecord\Schema\Serial;
20
use ICanBoogie\ActiveRecord\Schema\Text;
21
use ICanBoogie\ActiveRecord\Schema\Timestamp;
22
use LogicException;
23
use ReflectionAttribute;
24
use ReflectionClass;
25

26
use function is_string;
27

28
final class SchemaBuilder
29
{
30
    /**
31
     * @var array<non-empty-string, Column>
32
     */
33
    private array $columns = [];
34

35
    /**
36
     * @var array<non-empty-string>
37
     */
38
    private array $primary = [];
39

40
    /**
41
     * @var array<Index>
42
     */
43
    private array $indexes = [];
44

45
    public function build(): Schema
46
    {
47
        $columns = $this->columns;
107✔
48
        assert(count($columns) > 0);
49

50
        $this->assert_indexes();
107✔
51

52
        $primary = match (count($this->primary)) {
106✔
53
            0 => null,
106✔
54
            1 => reset($this->primary),
106✔
55
            default => $this->primary,
106✔
56
        };
106✔
57

58
        return new Schema(
106✔
59
            columns: $columns,
106✔
60
            primary: $primary,
106✔
61
            indexes: $this->indexes
106✔
62
        );
106✔
63
    }
64

65
    /**
66
     * Asserts that the columns used by the indexes exist.
67
     */
68
    private function assert_indexes(): void
69
    {
70
        foreach ($this->indexes as $index) {
107✔
71
            $columns = $index->columns;
6✔
72

73
            if (is_string($columns)) {
6✔
74
                $columns = [ $columns ];
6✔
75
            }
76

77
            foreach ($columns as $column) {
6✔
78
                $this->columns[$column]
6✔
79
                    ?? throw new LogicException("Column used by index is not defined: $column");
1✔
80
            }
81
        }
82
    }
83

84
    /**
85
     * Whether the builder is empty i.e. no column is defined yet.
86
     */
87
    public function is_empty(): bool
88
    {
89
        return count($this->columns) === 0;
3✔
90
    }
91

92
    /**
93
     * @param non-empty-string $col_name
94
     *
95
     * @return $this
96
     *
97
     * @see Boolean
98
     */
99
    public function add_boolean(
100
        string $col_name,
101
        bool $null = false,
102
    ): self {
103
        $this->columns[$col_name] = new Boolean(
2✔
104
            null: $null,
2✔
105
        );
2✔
106

107
        return $this;
2✔
108
    }
109

110
    /**
111
     * @param non-empty-string $col_name
112
     *
113
     * @phpstan-param Integer::SIZE_* $size
114
     *
115
     * @return $this
116
     *
117
     * @see Integer
118
     */
119
    public function add_integer(
120
        string $col_name,
121
        int $size = Integer::SIZE_REGULAR,
122
        bool $unsigned = false,
123
        bool $serial = false,
124
        bool $null = false,
125
        bool $unique = false,
126
        int|string $default = null,
127
        bool $primary = false,
128
    ): self {
129
        $this->columns[$col_name] = new Integer(
67✔
130
            size: $size,
67✔
131
            unsigned: $unsigned,
67✔
132
            serial: $serial,
67✔
133
            null: $null,
67✔
134
            unique: $unique,
67✔
135
            default: $default,
67✔
136
        );
67✔
137

138
        if ($primary) {
67✔
139
            $this->primary[] = $col_name;
1✔
140
        }
141

142
        return $this;
67✔
143
    }
144

145
    /**
146
     * @param non-empty-string $col_name
147
     * @param positive-int $precision
148
     *
149
     * @return $this
150
     *
151
     * @see Decimal
152
     */
153
    public function add_decimal(
154
        string $col_name,
155
        int $precision,
156
        int $scale = 0,
157
        bool $approximate = false,
158
        bool $null = false,
159
        bool $unique = false,
160
    ): self {
161
        $this->columns[$col_name] = new Decimal(
15✔
162
            precision: $precision,
15✔
163
            scale: $scale,
15✔
164
            approximate: $approximate,
15✔
165
            null: $null,
15✔
166
            unique: $unique
15✔
167
        );
15✔
168

169
        return $this;
15✔
170
    }
171

172
    /**
173
     * @param non-empty-string $col_name
174
     *
175
     * @return $this
176
     *
177
     * @see add_decimal
178
     */
179
    public function add_float(
180
        string $col_name,
181
        bool $null = false,
182
        bool $unique = false,
183
    ): self {
184
        return $this->add_decimal(
14✔
185
            col_name: $col_name,
14✔
186
            precision: 9,
14✔
187
            approximate: true,
14✔
188
            null: $null,
14✔
189
            unique: $unique,
14✔
190
        );
14✔
191
    }
192

193
    /**
194
     * @param non-empty-string $col_name
195
     * @param positive-int $size
196
     *
197
     * @return $this
198
     *
199
     * @see Serial
200
     */
201
    public function add_serial(
202
        string $col_name,
203
        int $size = Integer::SIZE_REGULAR,
204
        bool $primary = false,
205
    ): self {
206
        $this->columns[$col_name] = new Serial(
101✔
207
            size: $size
101✔
208
        );
101✔
209

210
        if ($primary) {
101✔
211
            $this->primary[] = $col_name;
101✔
212
        }
213

214
        return $this;
101✔
215
    }
216

217
    /**
218
     * @param non-empty-string $col_name
219
     * @param positive-int $size
220
     *
221
     * @return $this
222
     *
223
     * @see Integer
224
     */
225
    public function add_foreign(
226
        string $col_name,
227
        int $size = Integer::SIZE_REGULAR,
228
        bool $null = false,
229
        bool $unique = false,
230
        bool $primary = false,
231
    ): self {
232
        $this->columns[$col_name] = new Integer(
14✔
233
            size: $size,
14✔
234
            null: $null,
14✔
235
            unique: $unique,
14✔
236
        );
14✔
237

238
        if ($primary) {
14✔
239
            $this->primary[] = $col_name;
14✔
240
        }
241

242
        return $this;
14✔
243
    }
244

245
    /**
246
     * @param non-empty-string $col_name
247
     *
248
     * @return $this
249
     *
250
     * @see Date
251
     */
252
    public function add_date(
253
        string $col_name,
254
        bool $null = false,
255
        ?string $default = null,
256
    ): self {
257
        $this->columns[$col_name] = new Date(
8✔
258
            null: $null,
8✔
259
            default: $default,
8✔
260
        );
8✔
261

262
        return $this;
8✔
263
    }
264

265
    /**
266
     * @param non-empty-string $col_name
267
     * @param non-empty-string|null $default
268
     *
269
     * @return $this
270
     *
271
     * @see DateTime
272
     */
273
    public function add_datetime(
274
        string $col_name,
275
        bool $null = false,
276
        ?string $default = null,
277
        bool $unique = false,
278
    ): self {
279
        $this->columns[$col_name] = new DateTime(
66✔
280
            null: $null,
66✔
281
            default: $default,
66✔
282
            unique: $unique,
66✔
283
        );
66✔
284

285
        return $this;
66✔
286
    }
287

288
    /**
289
     * @param non-empty-string $col_name
290
     *
291
     * @return $this
292
     *
293
     * @see Timestamp
294
     */
295
    public function add_timestamp(
296
        string $col_name,
297
        bool $null = false,
298
        ?string $default = null,
299
    ): self {
300
        $this->columns[$col_name] = new Timestamp(
16✔
301
            null: $null,
16✔
302
            default: $default,
16✔
303
        );
16✔
304

305
        return $this;
16✔
306
    }
307

308
    /**
309
     * @param non-empty-string $col_name
310
     * @param positive-int $size
311
     * @param non-empty-string|null $collate
312
     *
313
     * @return $this
314
     *
315
     * @see Character
316
     */
317
    public function add_character(
318
        string $col_name,
319
        int $size = 255,
320
        bool $fixed = false,
321
        bool $null = false,
322
        ?string $default = null,
323
        bool $unique = false,
324
        ?string $collate = null,
325
        bool $primary = false,
326
    ): self {
327
        $this->columns[$col_name] = new Character(
101✔
328
            size: $size,
101✔
329
            fixed: $fixed,
101✔
330
            null: $null,
101✔
331
            default: $default,
101✔
332
            unique: $unique,
101✔
333
            collate: $collate,
101✔
334
        );
101✔
335

336
        if ($primary) {
101✔
337
            $this->primary[] = $col_name;
×
338
        }
339

340
        return $this;
101✔
341
    }
342

343
    /**
344
     * @param non-empty-string $col_name
345
     * @param positive-int $size
346
     *
347
     * @return $this
348
     *
349
     * @see Binary
350
     */
351
    public function add_binary(
352
        string $col_name,
353
        int $size = 255,
354
        bool $fixed = false,
355
        bool $null = false,
356
        bool $unique = false,
357
    ): self {
358
        $this->columns[$col_name] = new Binary(
×
359
            size: $size,
×
360
            fixed: $fixed,
×
361
            null: $null,
×
362
            unique: $unique,
×
363
        );
×
364

365
        return $this;
×
366
    }
367

368
    /**
369
     * @param non-empty-string $col_name
370
     * @param Blob::SIZE_* $size
371
     *
372
     * @return $this
373
     *
374
     * @see Blob
375
     */
376
    public function add_blob(
377
        string $col_name,
378
        string $size = Blob::SIZE_REGULAR,
379
        bool $null = false,
380
        bool $unique = false,
381
    ): self {
382
        $this->columns[$col_name] = new Blob(
×
383
            size: $size,
×
384
            null: $null,
×
385
            unique: $unique,
×
386
        );
×
387

388
        return $this;
×
389
    }
390

391
    /**
392
     * @param non-empty-string $col_name
393
     * @param Text::SIZE_* $size
394
     * @param non-empty-string|null $collate
395
     *
396
     * @return $this
397
     *
398
     * @see Text
399
     */
400
    public function add_text(
401
        string $col_name,
402
        string $size = Text::SIZE_REGULAR,
403
        bool $null = false,
404
        string $default = null,
405
        bool $unique = false,
406
        string $collate = null,
407
    ): self {
408
        $this->columns[$col_name] = new Text(
67✔
409
            size: $size,
67✔
410
            null: $null,
67✔
411
            default: $default,
67✔
412
            unique: $unique,
67✔
413
            collate: $collate,
67✔
414
        );
67✔
415

416
        return $this;
67✔
417
    }
418

419
    /**
420
     * @param non-empty-string $col_name
421
     * @param class-string<ActiveRecord> $associate
422
     *     The local key i.e. column name.
423
     * @param Integer::SIZE_* $size
424
     * @param non-empty-string|null $as
425
     *
426
     * @return $this
427
     *
428
     * @see BelongsTo
429
     */
430
    public function belongs_to(
431
        string $col_name,
432
        string $associate,
433
        int $size = Integer::SIZE_REGULAR,
434
        bool $null = false,
435
        bool $unique = false,
436
        ?string $as = null,
437
    ): self {
438
        $this->columns[$col_name] = new BelongsTo(
72✔
439
            associate: $associate,
72✔
440
            size: $size,
72✔
441
            null: $null,
72✔
442
            unique: $unique,
72✔
443
            as: $as,
72✔
444
        );
72✔
445

446
        return $this;
72✔
447
    }
448

449
    /**
450
     * Adds an index on one or multiple columns.
451
     *
452
     * @param non-empty-string|non-empty-array<non-empty-string> $columns
453
     *     Identifiers of the columns making the unique index.
454
     * @param non-empty-string|null $name
455
     *
456
     * @return $this
457
     *
458
     * @throws LogicException if a column used by the index is not defined.
459
     *
460
     * @see Index
461
     */
462
    public function add_index(
463
        array|string $columns,
464
        bool $unique = false,
465
        ?string $name = null
466
    ): self {
467
        $this->indexes[] = new Index($columns, $unique, $name);
5✔
468

469
        return $this;
5✔
470
    }
471

472
    /**
473
     * @param class-string<ActiveRecord> $activerecord_class
474
     *
475
     * @return $this
476
     * @internal
477
     *
478
     */
479
    public function use_record(string $activerecord_class): self
480
    {
481
        $class = new ReflectionClass($activerecord_class);
5✔
482

483
        foreach ($class->getAttributes(Index::class) as $attribute) {
5✔
484
            $this->indexes[] = $attribute->newInstance();
2✔
485
        }
486

487
        foreach ($class->getProperties() as $property) {
5✔
488
            // We only want the columns for this record, not its parent.
489
            if ($property->getDeclaringClass()->name !== $activerecord_class) {
5✔
490
                continue;
2✔
491
            }
492

493
            foreach (
494
                $property->getAttributes(
5✔
495
                    SchemaAttribute::class,
5✔
496
                    ReflectionAttribute::IS_INSTANCEOF
5✔
497
                ) as $attribute
5✔
498
            ) {
499
                $attribute = $attribute->newInstance();
5✔
500

501
                if ($attribute instanceof Id) {
5✔
502
                    $this->primary[] = $property->name;
4✔
503

504
                    continue;
4✔
505
                }
506

507
                if ($attribute instanceof Column) {
5✔
508
                    $this->columns[$property->name] = $attribute;
5✔
509
                }
510
            }
511
        }
512

513
        return $this;
5✔
514
    }
515
}
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