Passed
Branch main (b4b05f)
by Sammy
03:19
created

Crudites::raw()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 1
eloc 1
c 4
b 1
f 0
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
3
namespace HexMakina\Crudites;
4
5
use HexMakina\BlackBox\Database\{ConnectionInterface, SchemaAttributeInterface};
0 ignored issues
show
Bug introduced by
The type HexMakina\BlackBox\Datab...chemaAttributeInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
7
use HexMakina\Crudites\CruditesException;
8
9
use HexMakina\Crudites\Grammar\Query\Select;
10
use HexMakina\Crudites\Grammar\Clause\Where;
11
use HexMakina\Crudites\Grammar\Clause\OrderBy;
12
use HexMakina\Crudites\Grammar\Predicate;
13
14
15
/**
16
 * Crudités, it's a cup of carrots sticks (but are they organic ?)
17
 * Codd's Relational model, Unicity, Definitions, Introspection, Tests, Execution & Sets
18
 * Create - Retrieve - Update - Delete
19
 * Library for writing and running SQL queries
20
 */
21
class Crudites
22
{
23
    protected static ?ConnectionInterface $connection;
24
25
    public static function setConnection(ConnectionInterface $connection): void
26
    {
27
        self::$connection = $connection;
28
    }
29
30
    public static function connection(): ConnectionInterface
31
    {
32
        return self::$connection;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::connection could return the type null which is incompatible with the type-hinted return HexMakina\BlackBox\Database\ConnectionInterface. Consider adding an additional type-check to rule them out.
Loading history...
33
    }
34
35
    /**
36
     * connects to the database; if the connection already exists, the function verifies and returns it. 
37
     * If no connection exists, a Connection object is created with the provided parameters.
38
     */
39
    public static function connect($dsn = null, $user = null, $pass = null): ConnectionInterface
40
    {
41
        // no props, assumes connection made, verify and return
42
        if (isset($dsn, $user, $pass)) {
43
            self::$connection = new Connection($dsn, $user, $pass);
44
        }
45
        elseif (self::$connection === null) {
46
            throw new CruditesException('NO_DATABASE');
47
        }
48
49
        return self::$connection;
0 ignored issues
show
Bug Best Practice introduced by
The expression return self::connection could return the type null which is incompatible with the type-hinted return HexMakina\BlackBox\Database\ConnectionInterface. Consider adding an additional type-check to rule them out.
Loading history...
50
    }
51
52
    //------------------------------------------------------------  DataRetrieval
53
54
    /**
55
     * @param QueryInterface $select  Select instance
0 ignored issues
show
Bug introduced by
The type HexMakina\Crudites\QueryInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
56
     * @return int|null  Number of records
57
     */
58
    public static function count(Select $select): ?int
59
    {
60
        $select->selectAlso(['count' => ['COUNT(*)']]);
61
        $res = self::$connection->result($select);
0 ignored issues
show
Bug introduced by
The method result() does not exist on null. ( Ignorable by Annotation )

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

61
        /** @scrutinizer ignore-call */ 
62
        $res = self::$connection->result($select);

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...
62
        $res = $res->ret(\PDO::FETCH_COLUMN);
63
        if (is_array($res)) {
64
            return (int) current($res);
65
        }
66
67
        return null;
68
    }
69
70
    /**
71
     * retrieve(): A method that retrieves data from a SELECT statement, organizes them 
72
     * in an associative array using their primary keys as the indices
73
     * 
74
     * @return array<int|string, mixed>
75
     */
76
    public static function retrieve(Select $select): array
77
    {
78
        $ret = [];
79
80
        $res = self::$connection->result($select);
81
        if($res->ran()) {
82
83
            $primary_keys = self::$connection->schema()->primaryKeys($select->table());
84
            $pk_name = implode('_', $primary_keys);
85
86
            // returns an associative array with the primary key value as the index
87
            foreach ($res->ret() as $rec) {
88
                $ret[$rec[$pk_name]] = $rec;
89
            }
90
        }
91
92
        return $ret;
93
    }
94
95
    public static function distinctFor(string $table, string $column_name, string $filter_by_value = null)
96
    {
97
        $query = self::$connection->schema()->select($table, [sprintf('DISTINCT `%s`', $column_name)]);
98
        
99
        $clause = new Where([(new Predicate([$table, $column_name]))->isNotEmpty()]);
100
        if ($filter_by_value !== null) {
101
            $clause->andLike([$table, $column_name], $filter_by_value);
102
        }
103
        $query->add($clause);
104
        
105
        $clause = new OrderBy([$table, $column_name], 'ASC');
106
        $query->add($clause);
107
108
        return self::$connection->result($query)->ret(\PDO::FETCH_COLUMN);
109
    }
110
111
    public static function distinctForWithId(string $table, string $column_name, string $filter_by_value = null)
112
    {
113
        $Query = self::$connection->schema()->select($table [sprintf('DISTINCT `id`,`%s`', $column_name)]);
114
        
115
        $clause = new Where([(new Predicate([$table, $column_name]))->isNotEmpty()]);
116
        if ($filter_by_value !== null) {
117
            $clause->andLike([$table, $column_name], $filter_by_value);
118
        }
119
        $Query->add($clause);
120
121
        $clause = new OrderBy([$table, $column_name], 'ASC');
122
        $Query->add($clause);
123
124
        return self::$connection->result($Query)->ret(\PDO::FETCH_KEY_PAIR);
125
    }
126
127
    //------------------------------------------------------------  DataManipulation Helpers
128
    // returns true on success, false on failure or throws an exception
129
    // throws Exception on failure
130
    public static function toggleBoolean(string $table, string $boolean_column, array $unique_match): bool
131
    {
132
        $attribute = self::$connection->schema()->attributes($table, $boolean_column);
133
        if (!$attribute->type() === SchemaAttributeInterface::TYPE_BOOLEAN) {
134
            throw new CruditesException('TOGGLE_REQUIRES_BOOLEAN_COLUMN');
135
        }
136
137
        // throws exception if the table or column does not exist
138
        $unique_match = self::$connection->schema()->matchUniqueness($table, $unique_match);
139
        if (empty($unique_match)) {
140
            throw new CruditesException('NO_MATCH_TO_UNIQUE_RECORD');
141
        }
142
143
        $where = (new Where())->andFields($unique_match, $table);
144
145
        $query = "UPDATE $table SET $boolean_column = COALESCE(!$boolean_column, 1) WHERE $where";
146
        $res = self::$connection->result($query);
147
148
        return $res->ran();
149
        
150
        // TODO: not using the QueryInterface Way of binding stuff
151
        // $where = [];
152
        // $bindings = [];
153
        // foreach ($unique_match as $column_name => $value) {
154
        //     $binding_label = sprintf(':%s', $column_name);
155
        //     $where[] = sprintf('`%s` = %s', $column_name, $binding_label);
156
        //     $bindings[$binding_label] = $value;
157
        // }
158
159
        // $where = implode(' AND ', $where);
160
161
162
    }
163
}
164