• 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

92.59
/lib/ActiveRecord/HasManyRelation.php
1
<?php
2

3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <olivier.laviale@gmail.com>
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 ICanBoogie\ActiveRecord;
13

14
use ICanBoogie\ActiveRecord;
15
use LogicException;
16
use PDO;
17

18
use function ICanBoogie\pluralize;
19
use function is_string;
20

21
/**
22
 * Representation of a has_many relation.
23
 */
24
class HasManyRelation extends Relation
25
{
26
    /**
27
     * @inheritdoc
28
     *
29
     * @param class-string<ActiveRecord>|null $through
30
     *     The ActiveRecord used as pivot.
31
     */
32
    public function __construct(
33
        Model $owner,
34
        string $related,
35
        string $foreign_key,
36
        string $as,
37
        public readonly ?string $through = null,
38
    ) {
39
        assert(is_string($owner->primary));
40

41
        parent::__construct(
70✔
42
            owner: $owner,
70✔
43
            related: $related,
70✔
44
            local_key: $owner->primary,
70✔
45
            foreign_key: $foreign_key,
70✔
46
            as: $as,
70✔
47
        );
70✔
48
    }
49

50
    /**
51
     * @inheritdoc
52
     *
53
     * @return Query<ActiveRecord>
54
     */
55
    public function __invoke(ActiveRecord $record): Query
56
    {
57
        if ($this->through) {
8✔
58
            return $this->build_through_query($record, $this->through);
3✔
59
        }
60

61
        return $this
5✔
62
            ->resolve_related_model()
5✔
63
            ->where([ $this->foreign_key => $record->{$this->local_key} ]);
5✔
64
    }
65

66
    /**
67
     * @param class-string<ActiveRecord> $through
68
     *
69
     * @return Query<ActiveRecord>
70
     *
71
     * https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
72
     */
73
    private function build_through_query(ActiveRecord $record, string $through): Query
74
    {
75
        // $owner == $r1_model
76
        // $related === $r2_model
77

78
        $owner = $this->owner;
3✔
79
        $related = $this->resolve_related_model();
3✔
80
        $through_model = $this->model_for_activerecord($through);
3✔
81
        $r = $through_model->relations;
3✔
82
        $r1 = $r->find(fn(Relation $r) => $r->related === $this->owner->activerecord_class);
3✔
83
        $r2 = $r->find(fn(Relation $r) => $r->related === $related->activerecord_class)
3✔
84
            ?? throw new LogicException("Unable to find related model for " . $related::class);
×
85
        $r2_model = $this->model_for_activerecord($r2->related);
3✔
86

87
        $q = $related->select("`{alias}`.*");
3✔
88
        // Because of the select, we need to set the mode otherwise an array would be
89
        // fetched instead of an object.
90
        $q->mode(PDO::FETCH_CLASS, $related->activerecord_class);
3✔
91
        //phpcs:disable Generic.Files.LineLength.TooLong
92
        $q->join(expression: "INNER JOIN `$through_model->name` ON `$through_model->name`.{$r2->local_key} = `$r2_model->alias`.{$related->primary}");
3✔
93
        //phpcs:disable Generic.Files.LineLength.TooLong
94
        $q->join(expression: "INNER JOIN `$owner->name` `$owner->alias` ON `$through_model->name`.{$r1->local_key} = `$owner->alias`.{$owner->primary}");
3✔
95
        $q->where("`$owner->alias`.{$owner->primary} = ?", $record->{$this->local_key});
3✔
96

97
        return $q;
3✔
98
    }
99

100
    protected function resolve_property_name(string $related): string
101
    {
102
        return pluralize(parent::resolve_property_name($related));
×
103
    }
104
}
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