Passed
Push — main ( d2dd60...7e41d8 )
by Sammy
10:45 queued 04:07
created

TightModel::after_destroy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace HexMakina\TightORM;
4
5
use HexMakina\BlackBox\Database\SelectInterface;
6
use HexMakina\BlackBox\ORM\ModelInterface;
7
use HexMakina\Traitor\Traitor;
8
9
abstract class TightModel extends TableModel implements ModelInterface
10
{
11
    use Traitor;
12
13
    public function __toString()
14
    {
15
        return static::class_short_name() . ' #' . $this->getId();
16
    }
17
18
    public function immortal(): bool
19
    {
20
        return self::IMMORTAL_BY_DEFAULT;
21
    }
22
    // 
23
    // public function extract(ModelInterface $extract_model, $ignore_nullable = false)
24
    // {
25
    //     $extraction_class = get_class($extract_model);
26
    //
27
    //     $extraction_table = $extraction_class::table();
28
    //     foreach ($extraction_table->columns() as $column_name => $column) {
29
    //         $probe_name = $extraction_class::tableAlias() . '_' . $column_name;
30
    //
31
    //         if (!is_null($probe_res = $this->get($probe_name))) {
32
    //             $extract_model->set($column_name, $probe_res);
33
    //         } elseif (!$column->isNullable() && $ignore_nullable === false) {
34
    //             return null;
35
    //         }
36
    //     }
37
    //
38
    //     return $extract_model;
39
    // }
40
41
    public function copy()
42
    {
43
        $class = get_called_class();
44
        $clone = new $class();
45
46
        foreach ($class::table()->columns() as $column_name => $column) {
47
            if (!is_null($column->default())) {
48
                continue;
49
            }
50
            if ($column->isAutoIncremented()) {
51
                continue;
52
            }
53
54
            $clone->set($column_name, $this->get($column_name));
55
        }
56
57
        unset($clone->created_by);
58
        return $clone;
59
    }
60
61
    public function validate(): array
62
    {
63
        return []; // no errors
64
    }
65
66
    public function before_save(): array
67
    {
68
        return [];
69
    }
70
71
    public function after_save()
72
    {
73
        return true;
74
    }
75
76
    // return array of errors
77
    public function save($operator_id)
78
    {
79
        try {
80
            if (!empty($errors = $this->traitor('before_save'))) {
81
                return $errors;
82
            }
83
            if (!empty($errors = $this->before_save())) {
84
                return $errors;
85
            }
86
87
            if (!empty($errors = $this->validate())) { // Model level validation
88
                return $errors;
89
            }
90
91
            //1 tight model *always* match a single table row
92
            $table_row = $this->to_table_row($operator_id);
93
94
95
            if ($table_row->isAltered()) { // someting to save ?
96
                if (!empty($persistence_errors = $table_row->persist())) { // validate and persist
97
                    $errors = [];
98
99
                    foreach ($persistence_errors as $column_name => $err) {
100
                        $errors[sprintf('MODEL_%s_FIELD_%s', static::model_type(), $column_name)] = 'CRUDITES_' . $err;
101
                    }
102
103
                    return $errors;
104
                }
105
106
                // reload row
107
                $refreshed_row = static::table()->restore($table_row->export());
108
109
                // update model
110
                $this->import($refreshed_row->export());
111
            }
112
113
            $this->traitor('after_save');
114
            $this->after_save();
115
        } catch (\Exception $e) {
116
            return [$e->getMessage()];
117
        }
118
119
        return [];
120
    }
121
122
    // returns false on failure or last executed delete query
123
    public function before_destroy(): bool
124
    {
125
        if ($this->isNew() || $this->immortal()) {
126
            return false;
127
        }
128
129
        $this->traitor(__FUNCTION__);
130
131
        return true;
132
    }
133
134
    public function after_destroy()
135
    {
136
        $this->traitor(__FUNCTION__);
137
    }
138
139
    public function destroy($operator_id): bool
140
    {
141
        if ($this->before_destroy() === false) {
142
            return false;
143
        }
144
145
        $table_row = static::table()->restore(get_object_vars($this));
146
147
        if ($table_row->wipe() === false) {
148
            return false;
149
        }
150
151
        $this->after_destroy();
152
153
        return true;
154
    }
155
156
    //------------------------------------------------------------  Data Retrieval
157
    public static function query_retrieve($filters = [], $options = []): SelectInterface
158
    {
159
        $class = get_called_class();
160
        $query = (new TightModelSelector(new $class()))->select($filters, $options);
161
        return $query;
162
    }
163
164
    //------------------------------------------------------------  Introspection & Data Validation
165
    /**
166
     * Cascade of table name guessing goes:
167
     * 1. Constant 'TABLE_ALIAS' defined in class
168
     * 2. lower-case class name
169
     *
170
     */
171
    public static function tableAlias(): string
172
    {
173
        if (defined(get_called_class() . '::TABLE_ALIAS')) {
174
            return get_called_class()::TABLE_ALIAS;
175
        }
176
177
        return static::model_type();
178
    }
179
180
    public static function model_type(): string
181
    {
182
        if (defined(get_called_class() . '::MODEL_TYPE')) {
183
            return get_called_class()::MODEL_TYPE;
184
        }
185
186
        return strtolower(self::class_short_name());
187
    }
188
189
    public static function class_short_name(): string
190
    {
191
        return (new \ReflectionClass(get_called_class()))->getShortName();
192
    }
193
194
195
    public static function selectAlso()
196
    {
197
        return ['*'];
198
    }
199
}
200