• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ICanBoogie / Module / 4245494566

pending completion
4245494566

push

github

Olivier Laviale
Resolve templates using Config instead of Collection

115 of 432 relevant lines covered (26.62%)

0.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

19.35
/lib/Module.php
1
<?php
2

3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
namespace ICanBoogie;
13

14
use ICanBoogie\ActiveRecord\Model;
15
use ICanBoogie\ActiveRecord\ModelNotDefined;
16
use ICanBoogie\Module\Descriptor;
17
use ICanBoogie\Module\ModuleProvider;
18
use RuntimeException;
19
use Throwable;
20

21
use function ICanBoogie\ActiveRecord\get_model;
22

23
/**
24
 * A module of the framework.
25
 *
26
 * @property-read string $flat_id Underscored identifier.
27
 * @property-read string $id The identifier of the module, defined by {@link Descriptor::$id}.
28
 * @property-read Model $model The primary model of the module.
29
 * @property-read Module $parent The parent module, defined by {@link Descriptor::$parent}.
30
 * @property-read string $path The path to the module, defined by {@link Descriptor::$path}.
31
 * @property-read string $title The localized title of the module.
32
 * @property-read Application $app
33
 */
34
class Module extends Prototyped
35
{
36
    /*
37
     * PERMISSIONS:
38
     *
39
     * NONE: Well, you can't do anything
40
     *
41
     * ACCESS: You can access the module and view its records
42
     *
43
     * CREATE: You can create new records
44
     *
45
     * MAINTAIN: You can edit the records you created
46
     *
47
     * MANAGE: You can delete the records you created
48
     *
49
     * ADMINISTER: You have complete control over the module
50
     *
51
     */
52
    public const PERMISSION_NONE = 0;
53
    public const PERMISSION_ACCESS = 1;
54
    public const PERMISSION_CREATE = 2;
55
    public const PERMISSION_MAINTAIN = 3;
56
    public const PERMISSION_MANAGE = 4;
57
    public const PERMISSION_ADMINISTER = 5;
58

59
    /**
60
     * Defines the name of the operation used to save the records of the module.
61
     */
62
    public const OPERATION_SAVE = 'save';
63

64
    /**
65
     * Defines the name of the operation used to delete the records of the module.
66
     */
67
    public const OPERATION_DELETE = 'delete';
68

69
    /**
70
     * Returns the identifier of the module as defined by its descriptor.
71
     *
72
     * This method is the getter for the {@link $id} magic property.
73
     */
74
    protected function get_id(): string
75
    {
76
        return $this->descriptor->id;
10✔
77
    }
78

79
    /**
80
     * Returns the path of the module as defined by its descriptor.
81
     *
82
     * This method is the getter for the {@link $path} magic property.
83
     */
84
    protected function get_path(): string
85
    {
86
        return $this->descriptor->path;
×
87
    }
88

89
    public function __construct(
90
        public readonly Descriptor $descriptor,
91
        public readonly ModuleProvider $module_provider,
92
    ) {
93
    }
11✔
94

95
    /**
96
     * Returns the identifier of the module.
97
     */
98
    public function __toString(): string
99
    {
100
        return $this->id;
×
101
    }
102

103
    /**
104
     * Returns the _flat_ version of the module's identifier.
105
     *
106
     * This method is the getter for the {@link $flat_id} magic property.
107
     */
108
    protected function get_flat_id(): string
109
    {
110
        return strtr($this->id, [
1✔
111

112
            '.' => '_',
1✔
113
            '-' => '_'
1✔
114

115
        ]);
1✔
116
    }
117

118
    /**
119
     * Returns the primary model of the module.
120
     *
121
     * This is the getter for the {@link $model} magic property.
122
     */
123
    protected function get_model(): ActiveRecord\Model
124
    {
125
        return $this->model();
1✔
126
    }
127

128
    /**
129
     * Returns the module title, translated to the current language.
130
     *
131
     * @deprecated
132
     */
133
    protected function get_title(): string
134
    {
135
        $default = $this->descriptor->title ?? 'Undefined';
×
136

137
        return $this->app->translate($this->flat_id, [], [ 'scope' => 'module_title', 'default' => $default ]);
×
138
    }
139

140
    /**
141
     * Returns the parent module.
142
     */
143
    protected function get_parent(): ?Module
144
    {
145
        $parent = $this->descriptor->parent;
1✔
146

147
        return $parent ? $this->module_provider->module_for_id($parent) : null;
1✔
148
    }
149

150
    /**
151
     * Checks if the module is installed.
152
     *
153
     * @return bool|null `true` if the module is installed, `false` if the module (or parts of) is not installed, `null`
154
     * if the module has no installation.
155
     */
156
    public function is_installed(ErrorCollection $errors): ?bool
157
    {
158
        if (!$this->descriptor->models) {
×
159
            return null;
×
160
        }
161

162
        $rc = true;
×
163

164
        foreach ($this->descriptor->models as $id) {
×
165
            if (!$this->model($id)->is_installed()) {
×
166
                $errors->add($this->id, "The model %name is not installed.", [
×
167

168
                    'name' => $id
×
169

170
                ]);
×
171

172
                $rc = false;
×
173
            }
174
        }
175

176
        return $rc;
×
177
    }
178

179
    /**
180
     * Install the module.
181
     *
182
     * If the module has models they are installed.
183
     *
184
     * @return bool|null true if the module has successfully been installed, false if the
185
     * module (or parts of the module) fails to install or null if the module has
186
     * no installation process.
187
     */
188
    public function install(ErrorCollection $errors): ?bool
189
    {
190
        if (!$this->descriptor->models) {
×
191
            return null;
×
192
        }
193

194
        $rc = true;
×
195

196
        foreach ($this->descriptor->models as $id) {
×
197
            $model = $this->model($id);
×
198

199
            if ($model->is_installed()) {
×
200
                continue;
×
201
            }
202

203
            try {
204
                $model->install();
×
205
            } catch (Throwable $e) {
×
206
                $errors->add($this->id, "Unable to install model %model: !message", [
×
207

208
                    'model' => $id,
×
209
                    'message' => $e->getMessage()
×
210

211
                ]);
×
212

213
                $rc = false;
×
214
            }
215
        }
216

217
        return $rc;
×
218
    }
219

220
    /**
221
     * Uninstall the module.
222
     *
223
     * Basically it uninstall the models installed by the module.
224
     *
225
     * @return bool|null `true` if the module was successfully uninstalled. `false` if the module
226
     * (or parts of the module) failed to uninstall. `null` if there is no uninstall process.
227
     *
228
     * @throws Throwable
229
     */
230
    public function uninstall(): ?bool
231
    {
232
        if (!$this->descriptor->models) {
×
233
            return null;
×
234
        }
235

236
        $rc = true;
×
237

238
        foreach ($this->descriptor->models as $id) {
×
239
            $model = $this->model($id);
×
240

241
            if (!$model->is_installed()) {
×
242
                continue;
×
243
            }
244

245
            $model->uninstall();
×
246
        }
247

248
        return $rc;
×
249
    }
250

251
    /**
252
     * Get a model from the module.
253
     *
254
     * If the model has not been created yet, it is created on the fly.
255
     *
256
     * @throws ModelNotDefined when the model is not defined by the module.
257
     * @throws RuntimeException when the class of the model does not exist.
258
     */
259
    public function model(string $model_id = 'primary'): Model
260
    {
261
        if ($model_id === 'primary') {
1✔
262
            $model_id = current($this->descriptor->models);
1✔
263
        }
264

265
        return get_model($model_id);
1✔
266
    }
267

268
    /**
269
     * Get a block.
270
     *
271
     * @return mixed Depends on the implementation. Should return a string or an object
272
     * implementing `__toString`.
273
     *
274
     * @throws RuntimeException if the block is not defined.
275
     */
276
    public function getBlock(string $name)
277
    {
278
        $args = func_get_args();
×
279

280
        array_shift($args);
×
281

282
        $callback = 'block_' . $name;
×
283

284
        if (!method_exists($this, $callback)) {
×
285
            throw new RuntimeException(
×
286
                format('The %method method is missing from the %module module to create block %type.', [
×
287

288
                    '%method' => $callback,
×
289
                    '%module' => $this->id,
×
290
                    '%type' => $name
×
291

292
                ])
×
293
            );
×
294
        }
295

296
        return $this->$callback(...$args);
×
297
    }
298
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc