Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
46.67% covered (warning)
46.67%
35 / 75
50.00% covered (warning)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
HasOneOf
46.67% covered (warning)
46.67%
35 / 75
50.00% covered (warning)
50.00%
2 / 4
209.37
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getParent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getChild
75.00% covered (success)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 getEagerRelationships
42.65% covered (warning)
42.65%
29 / 68
0.00% covered (danger)
0.00%
0 / 1
199.79
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Db\Record\Relationships;
15
16use Pop\Db\Record;
17use Pop\Db\Sql\Parser;
18
19/**
20 * Relationship class for "has one of" relationships
21 *
22 * @category   Pop
23 * @package    Pop\Db
24 * @author     Nick Sagona, III <dev@nolainteractive.com>
25 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
26 * @license    http://www.popphp.org/license     New BSD License
27 * @version    6.5.0
28 */
29class HasOneOf extends AbstractRelationship
30{
31
32    /**
33     * Parent record
34     * @var Record
35     */
36    protected ?Record $parent = null;
37
38    /**
39     * Constructor
40     *
41     * Instantiate the relationship object
42     *
43     * @param Record $parent
44     * @param string $foreignTable
45     * @param string $foreignKey
46     * @param ?array $options
47     */
48    public function __construct(Record $parent, string $foreignTable, string $foreignKey, ?array $options = null)
49    {
50        parent::__construct($foreignTable, $foreignKey, $options);
51        $this->parent = $parent;
52    }
53
54    /**
55     * Get parent record
56     *
57     * @return ?Record
58     */
59    public function getParent(): ?Record
60    {
61        return $this->parent;
62    }
63
64    /**
65     * Get child
66     *
67     * @return Record
68     */
69    public function getChild(): Record
70    {
71        $table = $this->foreignTable;
72        if (!empty($this->children)) {
73            return $table::with($this->children)->getById($this->parent[$this->foreignKey]);
74        } else {
75            return $table::findById($this->parent[$this->foreignKey]);
76        }
77    }
78
79    /**
80     * Get eager relationships
81     *
82     * @param  array $ids
83     * @throws Exception
84     * @return array
85     */
86    public function getEagerRelationships(array $ids): array
87    {
88        if (($this->foreignTable === null) || ($this->foreignKey === null)) {
89            throw new Exception('Error: The foreign table and key values have not been set.');
90        }
91
92        $results = [];
93        $table   = $this->foreignTable;
94        $db      = $table::db();
95        $sql     = $db->createSql();
96        $columns = null;
97
98        if (!empty($this->options)) {
99            if (isset($this->options['select'])) {
100                $columns = $this->options['select'];
101            }
102        }
103
104        $keys = (new $table())->getPrimaryKeys();
105
106        if (count($keys) == 1) {
107            $keys = $keys[0];
108        }
109        $placeholders = array_fill(0, count($ids), $sql->getPlaceholder());
110        $sql->select($columns)->from($table::table())->where->in($keys, $placeholders);
111
112        if (!empty($this->options)) {
113            if (isset($this->options['limit'])) {
114                $sql->select()->limit((int)$this->options['limit']);
115            }
116
117            if (isset($this->options['offset'])) {
118                $sql->select()->offset((int)$this->options['offset']);
119            }
120            if (isset($this->options['join'])) {
121                $joins = (is_array($this->options['join']) && isset($this->options['join']['table'])) ?
122                    [$this->options['join']] : $this->options['join'];
123
124                foreach ($joins as $join) {
125                    if (isset($join['type']) && method_exists($sql->select(), $join['type'])) {
126                        $joinMethod = $join['type'];
127                        $sql->select()->{$joinMethod}($join['table'], $join['columns']);
128                    } else {
129                        $sql->select()->leftJoin($join['table'], $join['columns']);
130                    }
131                }
132            }
133            if (isset($this->options['order'])) {
134                if (!is_array($this->options['order'])) {
135                    $orders = (str_contains($this->options['order'], ',')) ?
136                        explode(',', $this->options['order']) : [$this->options['order']];
137                } else {
138                    $orders = $this->options['order'];
139                }
140                foreach ($orders as $order) {
141                    $ord = Parser\Order::parse(trim($order));
142                    $sql->select()->orderBy($ord['by'], $db->escape($ord['order']));
143                }
144            }
145        }
146
147        $db->prepare($sql)
148           ->bindParams($ids)
149           ->execute();
150
151        $rows               = $db->fetchAll();
152        $parentIds          = [];
153        $childRelationships = [];
154
155        $primaryKey = (new $table())->getPrimaryKeys();
156        $primaryKey = (count($primaryKey) == 1) ? reset($primaryKey) : $this->foreignKey;
157
158        foreach ($rows as $row) {
159            $parentIds[] = $row[$primaryKey];
160            $record = new $table();
161            $record->setColumns($row);
162            $results[$row[$keys]] = $record;
163        }
164
165        if (!empty($this->children) && !empty($parentIds)) {
166            foreach ($results as $record) {
167                $record->getWithRelationships();
168                foreach ($record->getRelationships() as $relationship) {
169                    $childRelationships = $relationship->getEagerRelationships($parentIds);
170                }
171            }
172        }
173
174        if (!empty($childRelationships)) {
175            $children    = $this->children;
176            $subChildren = null;
177            if (str_contains($children, '.')) {
178                $names       = explode('.', $children);
179                $children    = array_shift($names);
180                $subChildren = implode('.', $names);
181            }
182
183            foreach ($results as $record) {
184                if (!empty($subChildren)) {
185                    $record->addWith($subChildren);
186                }
187                $rel = (isset($childRelationships[$record[$primaryKey]])) ?
188                    $childRelationships[$record[$primaryKey]] : [];
189
190                $record->setRelationship($children, $rel);
191            }
192        }
193
194        return $results;
195    }
196
197}