Issues (65)

src/Crudites.php (5 issues)

1
<?php
2
3
namespace HexMakina\Crudites;
4
5
use HexMakina\BlackBox\Database\{ConnectionInterface, SchemaAttributeInterface};
0 ignored issues
show
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
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
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
            $ret = $res->ret(\PDO::FETCH_UNIQUE | \PDO::FETCH_ASSOC);
83
        }
84
85
        return $ret;
86
    }
87
88
    public static function distinctFor(string $table, string $column_name, string $filter_by_value = null)
89
    {
90
        $query = self::$connection->schema()->select($table, [sprintf('DISTINCT `%s`', $column_name)]);
91
        $where = $query->where([(new Predicate([$table, $column_name]))->isNotEmpty()]);
92
93
        if ($filter_by_value !== null) {
94
            $where->andLike([$table, $column_name], $filter_by_value);
95
        }
96
        
97
        $query->orderBy([$table, $column_name], 'ASC');
98
99
        return self::$connection->result($query)->ret(\PDO::FETCH_COLUMN);
100
    }
101
102
    public static function distinctForWithId(string $table, string $column_name, string $filter_by_value = null)
103
    {
104
        $Query = self::$connection->schema()->select($table [sprintf('DISTINCT `id`,`%s`', $column_name)]);
105
        
106
        $clause = new Where([(new Predicate([$table, $column_name]))->isNotEmpty()]);
107
        if ($filter_by_value !== null) {
108
            $clause->andLike([$table, $column_name], $filter_by_value);
109
        }
110
        $Query->add($clause);
111
112
        $clause = new OrderBy([$table, $column_name], 'ASC');
113
        $Query->add($clause);
114
115
        return self::$connection->result($Query)->ret(\PDO::FETCH_KEY_PAIR);
116
    }
117
118
    //------------------------------------------------------------  DataManipulation Helpers
119
    // returns true on success, false on failure or throws an exception
120
    // throws Exception on failure
121
    public static function toggleBoolean(string $table, string $boolean_column, array $unique_match): bool
122
    {
123
        $attribute = self::$connection->schema()->attributes($table, $boolean_column);
124
        if (!$attribute->type() === SchemaAttributeInterface::TYPE_BOOLEAN) {
125
            throw new CruditesException('TOGGLE_REQUIRES_BOOLEAN_COLUMN');
126
        }
127
128
        // throws exception if the table or column does not exist
129
        $unique_match = self::$connection->schema()->matchUniqueness($table, $unique_match);
130
        if (empty($unique_match)) {
131
            throw new CruditesException('NO_MATCH_TO_UNIQUE_RECORD');
132
        }
133
134
        $where = (new Where())->andFields($unique_match, $table);
135
136
        $query = "UPDATE $table SET $boolean_column = COALESCE(!$boolean_column, 1) WHERE $where";
137
        $res = self::$connection->result($query);
138
139
        return $res->ran();
140
        
141
        // TODO: not using the QueryInterface Way of binding stuff
142
        // $where = [];
143
        // $bindings = [];
144
        // foreach ($unique_match as $column_name => $value) {
145
        //     $binding_label = sprintf(':%s', $column_name);
146
        //     $where[] = sprintf('`%s` = %s', $column_name, $binding_label);
147
        //     $bindings[$binding_label] = $value;
148
        // }
149
150
        // $where = implode(' AND ', $where);
151
152
153
    }
154
}
155