Issues (65)

src/Grammar/AutoJoin.php (5 issues)

Labels
Severity
1
<?php
2
3
namespace HexMakina\Crudites\Grammar\Query;
4
5
use HexMakina\Crudites\Crudites;
6
use HexMakina\BlackBox\Database\QueryInterface;
7
8
class AutoJoin
9
{
10
    public static function join(QueryInterface $select, $other_table, $select_also = [], $relation_type = null): string
11
    {
12
        $other_table_alias = null;
13
14
        if (is_array($other_table)) {
15
            list($other_table, $other_table_alias) = $other_table;
16
        } else {
17
            $other_table_alias = $other_table->name();
18
        }
19
20
        $other_table_name = $other_table->name();
21
22
        $joins = [];
23
24
        // 1. ? this->table.other_table_id -> $other_table.id
25
        // 2. ? this_table.id -> $other_table.this_table_id)
26
        // if(count($bonding_column = $this->table()->foreignKeysByTable()[$other_table_name] ?? []) === 1)
27
        if (!is_null($bonding_column = $select->table()->singleForeignKeyTo($other_table))) {
28
            $relation_type = ($relation_type ?? $bonding_column->isNullable()) !== '' && ($relation_type ?? $bonding_column->isNullable()) !== '0' ? 'LEFT OUTER' : 'INNER';
29
            // $joins []= [$bonding_column->tableName(), $bonding_column->name(), $other_table_alias ?? $bonding_column->foreignTableAlias(), $bonding_column->foreignColumnName()];
30
            $joins [] = [$select->tableAlias(), $bonding_column->name(), $other_table_alias ?? $bonding_column->foreignTableAlias(), $bonding_column->foreignColumnName()];
31
        } elseif (!is_null($bonding_column = $other_table->singleForeignKeyTo($select->table()))) {
32
            $relation_type ??= 'LEFT OUTER';
33
            $joins [] = [$select->tableLabel(), $bonding_column->foreignColumnName(), $other_table_alias ?? $other_table->name(), $bonding_column->name()];
0 ignored issues
show
The method tableLabel() does not exist on HexMakina\BlackBox\Database\QueryInterface. Did you maybe mean table()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

33
            $joins [] = [$select->/** @scrutinizer ignore-call */ tableLabel(), $bonding_column->foreignColumnName(), $other_table_alias ?? $other_table->name(), $bonding_column->name()];

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
34
        } else {
35
            $bondable_tables = self::joinableTables($select);
36
            if (isset($bondable_tables[$other_table_name])) {
37
                $bonding_columns = $bondable_tables[$other_table_name];
38
                if (count($bonding_columns) === 1) {
39
                    $bonding_column = current($bonding_columns);
40
                    $other_table_alias ??= $bonding_column->foreignTableAlias();
41
42
                    $bonding_table_label = array_search($bonding_column->tableName(), $select->joinedTables(), true);
43
                    if ($bonding_table_label === false) {
44
                        $bonding_table_label = $bonding_column->tableName();
45
                    }
46
47
                    $joins = [[$bonding_table_label, $bonding_column->name(), $other_table_alias, $bonding_column->foreignColumnName()]];
48
                    $relation_type ??= ($bonding_column->isNullable()) ? 'LEFT OUTER' : 'INNER';
49
                }
50
            } elseif (($intersections = array_intersect_key($other_table->foreignKeysByTable(), $bondable_tables)) !== []) {
51
                $other_table_alias ??= $other_table->name();
52
                foreach ($intersections as $table_name => $bonding_column) {
53
                    if (count($bonding_column) !== 1 || count($other_table->foreignKeysByTable()[$table_name]) !== 1) {
54
                        break;
55
                    }
56
57
58
                    $joins = [];
59
60
                    $bonding_column = current($bonding_column);
61
                    $joins [] = [$other_table_alias, $bonding_column->name(), $bonding_column->foreignTableAlias(), $bonding_column->foreignColumnName()];
62
63
                    $bonding_column = current($bondable_tables[$table_name]);
64
                    $joins [] = [$bonding_column->tableName(), $bonding_column->name(), $bonding_column->foreignTableAlias(), $bonding_column->foreignColumnName()];
65
66
                    // $relation_type = $relation_type ?? (($parent_column->isNullable() || $bonding_column->isNullable()) ? 'LEFT OUTER' : 'INNER');
67
                    $relation_type ??= ($bonding_column->isNullable()) ? 'LEFT OUTER' : 'INNER';
68
                }
69
            }
70
        }
71
72
        if (!empty($joins)) {
73
            
74
            $select->join([$other_table_name, $other_table_alias], $joins, $relation_type);
0 ignored issues
show
The method join() does not exist on HexMakina\BlackBox\Database\QueryInterface. It seems like you code against a sub-type of HexMakina\BlackBox\Database\QueryInterface such as HexMakina\BlackBox\Database\SelectInterface or HexMakina\Crudites\Grammar\Query\Select. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

74
            $select->/** @scrutinizer ignore-call */ 
75
                     join([$other_table_name, $other_table_alias], $joins, $relation_type);
Loading history...
75
            $select->addJoinedTable($other_table_name, $other_table_alias);
0 ignored issues
show
The method addJoinedTable() does not exist on HexMakina\BlackBox\Database\QueryInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
            $select->/** @scrutinizer ignore-call */ 
76
                     addJoinedTable($other_table_name, $other_table_alias);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
76
77
78
            if (!empty($select_also)) {
79
                $select->selectAlso($select_also);
0 ignored issues
show
The method selectAlso() does not exist on HexMakina\BlackBox\Database\QueryInterface. It seems like you code against a sub-type of HexMakina\BlackBox\Database\QueryInterface such as HexMakina\BlackBox\Database\SelectInterface or HexMakina\Crudites\Grammar\Query\Select. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

79
                $select->/** @scrutinizer ignore-call */ 
80
                         selectAlso($select_also);
Loading history...
80
            }
81
        }
82
83
        return $other_table_alias;
84
    }
85
86
    /**
87
     * @return mixed[]
88
     */
89
    private static function joinableTables(QueryInterface $select): array
90
    {
91
        $joinable_tables = $select->table()->foreignKeysByTable();
92
        foreach ($select->joinedTables() as $join_table) {
93
            $joinable_tables += Crudites::database()->table($join_table)->foreignKeysByTable();
0 ignored issues
show
The method database() does not exist on HexMakina\Crudites\Crudites. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

93
            $joinable_tables += Crudites::/** @scrutinizer ignore-call */ database()->table($join_table)->foreignKeysByTable();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
94
        }
95
96
        return $joinable_tables;
97
    }
98
99
    public static function eager(QueryInterface $select, $table_aliases = []): void
100
    {
101
        
102
        if (isset($table_aliases[$select->table()->name()])) {
103
            $select->tableAlias($table_aliases[$select->table()->name()]);
104
        }
105
106
        foreach ($select->table()->foreignKeysByTable() as $foreign_table_name => $fk_columns) {
107
            $foreign_table = Crudites::database()->table($foreign_table_name);
108
109
        
110
111
            $single_fk = count($fk_columns) === 1; //assumption
112
113
            foreach ($fk_columns as $fk_column) {
114
                $select_also = [];
115
116
                // TODO this sucks hard.. 'created_by' & 'kadro_operator' have *NOTHING* to do in SelectJoin, must create mecanism for such exception
117
                if ($fk_column->foreignTableName() == 'kadro_operator' && $fk_column->name() == 'created_by') {
118
                    continue; // dont load the log information
119
                } else {
120
                    $m = [];
121
                    if (preg_match('/(.+)_(' . $fk_column->foreignColumnName() . ')$/', $fk_column->name(), $m)) {
122
                        $foreign_table_alias = $m[1];
123
                    } else {
124
                        $foreign_table_alias = $foreign_table_name;
125
                    }
126
127
                    $foreign_table_alias = $single_fk ? $foreign_table_alias : $foreign_table_alias . '_' . $fk_column->name();
128
129
                    // auto select non nullable columns
130
                }
131
     
132
                foreach ($foreign_table->columns() as $col) {
133
134
                    // if($col->isNullable())
135
                    //     continue;
136
137
                    $select_also[$foreign_table_alias.'_'.$col] = [$foreign_table_alias, "$col"];
138
                }
139
140
                self::join($select, [$foreign_table, $foreign_table_alias], $select_also);
141
            }
142
        }
143
    }
144
}
145