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

ICanBoogie / ActiveRecord / 4437457574

pending completion
4437457574

push

github

Olivier Laviale
Case of a nullable belong_to

7 of 7 new or added lines in 1 file covered. (100.0%)

1356 of 1686 relevant lines covered (80.43%)

34.68 hits per line

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

96.15
/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 PDO;
16

17
use function ICanBoogie\pluralize;
18

19
/**
20
 * Representation of a has_many relation.
21
 */
22
class HasManyRelation extends Relation
23
{
24
    /**
25
     * @inheritdoc
26
     *
27
     * @param string|null $through If the association is made indirectly, this is the name of that model.
28
     */
29
    public function __construct(
30
        Model $owner,
31
        string $related,
32
        string $local_key,
33
        string $foreign_key,
34
        string $as,
35
        public readonly ?string $through = null,
36
    ) {
37
        parent::__construct(
85✔
38
            owner: $owner,
85✔
39
            related: $related,
85✔
40
            local_key: $local_key,
85✔
41
            foreign_key: $foreign_key,
85✔
42
            as: $as,
85✔
43
        );
85✔
44
    }
45

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

57
        return $this
5✔
58
            ->resolve_related()
5✔
59
            ->where([ $this->foreign_key => $record->{$this->local_key} ]);
5✔
60
    }
61

62
    /**
63
     * @return Query<ActiveRecord>
64
     *
65
     * https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
66
     */
67
    private function build_through_query(ActiveRecord $record, string $through_id): Query
68
    {
69
        // $owner == $r1_model
70
        // $related === $r2_model
71

72
        $owner = $this->owner;
3✔
73
        $related = $this->resolve_related();
3✔
74
        $through = $this->ensure_model($through_id);
3✔
75
        $r = $through->relations;
3✔
76
        $r1 = $r->find(fn(Relation $r) => $r->related === $this->owner->id);
3✔
77
        $r2 = $r->find(fn(Relation $r) => $r->related === $related->id);
3✔
78
        $r2_model = $this->ensure_model($r2->related);
3✔
79

80
        $q = $related->select("`{alias}`.*");
3✔
81
        // Because of the select, we need to set the mode otherwise an array would be
82
        // fetched instead of an object.
83
        $q->mode(PDO::FETCH_CLASS, $related->activerecord_class);
3✔
84
        $q->join("INNER JOIN `{$through->name}` ON `{$through->name}`.{$r2->local_key} = `{$r2_model->alias}`.{$related->primary}");
3✔
85
        $q->join("INNER JOIN `{$owner->name}` `{$owner->alias}` ON `{$through->name}`.{$r1->local_key} = `{$owner->alias}`.{$owner->primary}");
3✔
86
        $q->where("`{$owner->alias}`.{$owner->primary} = ?", $record->{$this->local_key});
3✔
87

88
        return $q;
3✔
89
    }
90

91
    protected function resolve_property_name(string $related): string
92
    {
93
        return pluralize(parent::resolve_property_name($related));
×
94
    }
95
}
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