Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
26 / 26
95.45% covered (success)
95.45%
21 / 22
47.62% covered (danger)
47.62%
10 / 21
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
PhpLoader
100.00% covered (success)
100.00%
26 / 26
95.45% covered (success)
95.45%
21 / 22
47.62% covered (danger)
47.62%
10 / 21
100.00% covered (success)
100.00%
3 / 3
28.39
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 load
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
9 / 9
83.33% covered (warning)
83.33%
5 / 6
100.00% covered (success)
100.00%
1 / 1
5.12
 loadClass
100.00% covered (success)
100.00%
11 / 11
91.67% covered (success)
91.67%
11 / 12
28.57% covered (danger)
28.57%
4 / 14
100.00% covered (success)
100.00%
1 / 1
14.11
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Quma\Migrations;
6
7use ArgumentCountError;
8use Celemas\Quma\Contract;
9use Celemas\Quma\Environment;
10use RuntimeException;
11
12final class PhpLoader
13{
14    /** @var array<string, class-string<Contract\Migration>> */
15    private static array $classes = [];
16
17    public function __construct(
18        private readonly Environment $env,
19        private readonly ?Contract\MigrationFactory $migrationFactory = null,
20    ) {}
21
22    public function load(string $migration): Contract\Migration
23    {
24        if (!is_file($migration)) {
25            throw new RuntimeException('Could not read migration file');
26        }
27
28        $class = self::$classes[$migration] ?? null;
29
30        if ($class === null) {
31            $class = $this->loadClass($migration);
32            self::$classes[$migration] = $class;
33        }
34
35        if ($this->migrationFactory !== null) {
36            return $this->migrationFactory->create($class, $this->env);
37        }
38
39        try {
40            return new $class();
41        } catch (ArgumentCountError $e) {
42            throw new RuntimeException(
43                "Migration {$class} requires constructor arguments, but no migration factory is configured.",
44                previous: $e,
45            );
46        }
47    }
48
49    /** @return class-string<Contract\Migration> */
50    private function loadClass(string $migration): string
51    {
52        /** @psalm-suppress UnresolvableInclude */
53        $class = require $migration;
54
55        if (!is_string($class) || $class === '') {
56            throw new RuntimeException('Invalid migration file. Expected migration class name');
57        }
58
59        if (!class_exists($class)) {
60            throw new RuntimeException("Invalid migration file. Migration class '{$class}' does not exist");
61        }
62
63        if (!is_subclass_of($class, Contract\Migration::class)) {
64            throw new RuntimeException(
65                "Invalid migration file. Migration class '{$class}' must implement "
66                . Contract\Migration::class,
67            );
68        }
69
70        return $class;
71    }
72}

Branches

Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once. Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

PhpLoader->__construct
18        private readonly Environment $env,
19        private readonly ?Contract\MigrationFactory $migrationFactory = null,
20    ) {}
PhpLoader->load
22    public function load(string $migration): Contract\Migration
23    {
24        if (!is_file($migration)) {
25            throw new RuntimeException('Could not read migration file');
28        $class = self::$classes[$migration] ?? null;
29
30        if ($class === null) {
31            $class = $this->loadClass($migration);
32            self::$classes[$migration] = $class;
33        }
34
35        if ($this->migrationFactory !== null) {
35        if ($this->migrationFactory !== null) {
36            return $this->migrationFactory->create($class, $this->env);
39        try {
40            return new $class();
41        } catch (ArgumentCountError $e) {
42            throw new RuntimeException(
43                "Migration {$class} requires constructor arguments, but no migration factory is configured.",
44                previous: $e,
45            );
46        }
47    }
PhpLoader->loadClass
50    private function loadClass(string $migration): string
51    {
52        /** @psalm-suppress UnresolvableInclude */
53        $class = require $migration;
54
55        if (!is_string($class) || $class === '') {
55        if (!is_string($class) || $class === '') {
55        if (!is_string($class) || $class === '') {
56            throw new RuntimeException('Invalid migration file. Expected migration class name');
59        if (!class_exists($class)) {
59        if (!class_exists($class)) {
59        if (!class_exists($class)) {
59        if (!class_exists($class)) {
60            throw new RuntimeException("Invalid migration file. Migration class '{$class}' does not exist");
63        if (!is_subclass_of($class, Contract\Migration::class)) {
64            throw new RuntimeException(
65                "Invalid migration file. Migration class '{$class}' must implement "
66                . Contract\Migration::class,
70        return $class;
71    }