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

visavi / rotor / 26602863997

28 May 2026 09:18PM UTC coverage: 14.625% (+0.07%) from 14.557%
26602863997

push

github

visavi
Закешил disk-scan модулей, schedule только в console, пустой результат не кешится.

14 of 60 new or added lines in 2 files covered. (23.33%)

1 existing line in 1 file now uncovered.

880 of 6017 relevant lines covered (14.63%)

1.15 hits per line

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

23.17
/app/Models/Module.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace App\Models;
6

7
use Exception;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Support\Facades\Artisan;
10
use Illuminate\Support\Facades\Cache;
11
use Illuminate\Support\Facades\DB;
12
use Illuminate\Support\Facades\File;
13
use Illuminate\Support\Str;
14

15
/**
16
 * Class Module
17
 *
18
 * @property int    $id
19
 * @property string $name
20
 * @property string $version
21
 * @property bool   $active
22
 * @property array  $settings
23
 * @property int    $updated_at
24
 * @property int    $created_at
25
 */
26
class Module extends Model
27
{
28
    /**
29
     * Assets modules path
30
     */
31
    protected const ASSETS_PATH = '/assets/modules/';
32

33
    /**
34
     * Indicates if the model should be timestamped.
35
     */
36
    public $timestamps = false;
37

38
    /**
39
     * The attributes that aren't mass assignable.
40
     */
41
    protected $guarded = [];
42

43
    /**
44
     * Get the attributes that should be cast.
45
     */
46
    protected function casts(): array
60✔
47
    {
48
        return [
60✔
49
            'active'   => 'bool',
60✔
50
            'settings' => 'array',
60✔
51
        ];
60✔
52
    }
53

54
    /**
55
     * Выполняет применение миграции
56
     */
57
    public function migrate(): void
×
58
    {
59
        $migrationPath = base_path('modules/' . $this->name . '/database/migrations');
×
60

61
        if (file_exists($migrationPath)) {
×
62
            Artisan::call('migrate', [
×
63
                '--force'    => true,
×
64
                '--realpath' => true,
×
65
                '--path'     => $migrationPath,
×
66
            ]);
×
67
        }
68
    }
69

70
    /**
71
     * Выполняет откат миграций
72
     */
73
    public function rollback(): void
×
74
    {
75
        $migrationPath = base_path('modules/' . $this->name . '/database/migrations');
×
76

77
        if (file_exists($migrationPath)) {
×
78
            $migrator = app('migrator');
×
79
            $nextBatchNumber = $migrator->getRepository()->getNextBatchNumber();
×
80
            $migrationNames = array_keys($migrator->getMigrationFiles($migrationPath));
×
81

82
            DB::table(config('database.migrations.table'))
×
83
                ->whereIn('migration', $migrationNames)
×
84
                ->update(['batch' => $nextBatchNumber]);
×
85

86
            Artisan::call('migrate:rollback', [
×
87
                '--force'    => true,
×
88
                '--realpath' => true,
×
89
                '--path'     => $migrationPath,
×
90
            ]);
×
91
        }
92
    }
93

94
    /**
95
     * Создает симлинки модулей
96
     */
97
    public function createSymlink(): void
×
98
    {
99
        $originPath = public_path($this->getLinkName());
×
100
        if (file_exists($originPath)) {
×
101
            return;
×
102
        }
103

104
        $assetsPath = base_path('modules/' . $this->name . '/resources/assets');
×
105
        if (! file_exists($assetsPath)) {
×
106
            return;
×
107
        }
108

109
        File::link($assetsPath, $originPath);
×
110
    }
111

112
    /**
113
     * Удаляет симлинки модулей
114
     */
115
    public function deleteSymlink(): void
×
116
    {
117
        $originPath = public_path($this->getLinkName());
×
118
        if (! file_exists($originPath)) {
×
119
            return;
×
120
        }
121

122
        File::delete($originPath);
×
123
    }
124

125
    /**
126
     * Получает название директории для симлинка
127
     */
128
    public function getLinkName(): string
×
129
    {
130
        return self::ASSETS_PATH . Str::plural(strtolower($this->name));
×
131
    }
132

133
    /**
134
     * Получает название директории для симлинка из пути
135
     */
136
    public static function getLinkNameByPath(string $modulePath): string
×
137
    {
138
        return self::ASSETS_PATH . Str::plural(strtolower(basename($modulePath)));
×
139
    }
140

141
    /**
142
     * Get enabled modules
143
     */
144
    public static function getEnabledModules(): array
60✔
145
    {
146
        $cached = Cache::get('modules', []);
60✔
147
        if ($cached !== []) {
60✔
NEW
148
            return $cached;
×
149
        }
150

151
        $modules = self::loadEnabledModules();
60✔
152

153
        if ($modules !== []) {
60✔
NEW
154
            Cache::forever('modules', $modules);
×
155
        }
156

157
        return $modules;
60✔
158
    }
159

160
    /**
161
     * Загружает активные модули с их файловой структурой
162
     */
163
    private static function loadEnabledModules(): array
60✔
164
    {
165
        try {
166
            $settings = self::query()
60✔
167
                ->where('active', true)
60✔
168
                ->pluck('settings', 'name')
60✔
169
                ->all();
60✔
NEW
170
        } catch (Exception) {
×
NEW
171
            return [];
×
172
        }
173

174
        $result = [];
60✔
175
        foreach ($settings as $name => $moduleSettings) {
60✔
NEW
176
            $result[$name] = [
×
NEW
177
                'settings' => $moduleSettings ?? [],
×
NEW
178
                'files'    => self::scanModuleFiles($name),
×
NEW
179
            ];
×
180
        }
181

182
        return $result;
60✔
183
    }
184

185
    /**
186
     * Сканирует наличие файлов модуля
187
     */
NEW
188
    private static function scanModuleFiles(string $name): array
×
189
    {
NEW
190
        $base = base_path('modules/' . $name . '/');
×
191

NEW
192
        return [
×
NEW
193
            'views'      => is_dir($base . 'resources/views'),
×
NEW
194
            'lang'       => is_dir($base . 'resources/lang'),
×
NEW
195
            'helpers'    => file_exists($base . 'helpers.php'),
×
NEW
196
            'hooks'      => file_exists($base . 'hooks.php'),
×
NEW
197
            'routes'     => file_exists($base . 'routes.php'),
×
NEW
198
            'config'     => file_exists($base . 'config.php'),
×
NEW
199
            'middleware' => file_exists($base . 'middleware.php'),
×
NEW
200
            'module'     => file_exists($base . 'module.php'),
×
NEW
201
            'commands'   => array_map(
×
NEW
202
                static fn ($file) => 'Modules\\' . $name . '\\Console\\' . basename($file, '.php'),
×
NEW
203
                glob($base . 'Console/*.php') ?: []
×
NEW
204
            ),
×
NEW
205
        ];
×
206
    }
207
}
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

© 2026 Coveralls, Inc