Skip to content

Commit 6065ecb

Browse files
committed
Merge branch '6.x' into feature/create-object
2 parents b316f88 + 74928d1 commit 6065ecb

9 files changed

Lines changed: 91 additions & 38 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ Element queries (`src/Database/Queries/`) are the primary way to query content:
133133
- Uses `RefreshDatabase` trait - tables are migrated fresh via the `Install` migration
134134
- **Classes marked `final` have this keyword stripped during testing** - you can create custom test classes that extend production classes (e.g., extending `User` element) to override methods like `getFieldLayout()` for easier testing without complex mocks
135135

136-
**Important**: When creating or adjusting tests, take a look at @docs/TESTING.md for patterns and best practices.
136+
**Important**: When creating or adjusting tests, use the `testing-guidelines` skill for patterns and best practices.
137137

138138
### Service Providers Pattern
139139

src/Database/Commands/MigrateCommand.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use CraftCms\Cms\Console\CraftCommand;
88
use CraftCms\Cms\Database\Commands\Concerns\BackupTrait;
99
use CraftCms\Cms\Database\Events\RegisterMigrators;
10+
use CraftCms\Cms\Database\LaravelMigrations;
1011
use CraftCms\Cms\Database\Migrator;
1112
use CraftCms\Cms\Plugin\Plugins;
1213
use CraftCms\Cms\Support\Str;
@@ -53,19 +54,22 @@ class MigrateCommand extends Command implements Isolatable
5354

5455
private Plugins $plugins;
5556

57+
private LaravelMigrations $laravelMigrations;
58+
5659
/**
5760
* @var array<string, Migrator>
5861
*/
5962
private array $migrators = [];
6063

61-
public function handle(Updates $updates, Plugins $plugins): int
64+
public function handle(Updates $updates, Plugins $plugins, LaravelMigrations $laravelMigrations): int
6265
{
6366
if (! $this->confirmToProceed()) {
6467
return self::SUCCESS;
6568
}
6669

6770
$this->updates = $updates;
6871
$this->plugins = $plugins;
72+
$this->laravelMigrations = $laravelMigrations;
6973

7074
try {
7175
$this->runMigrations();
@@ -197,6 +201,7 @@ private function gatherMigrationsByTrack(array &$migrationsByTrack, array &$plug
197201

198202
$noContent = $this->option('no-content') ?? $this->option('noContent');
199203
if (! $noContent && (! $this->option('track') || $this->option('track') === 'content')) {
204+
$this->laravelMigrations->reconcile($this->getMigrator('content'));
200205
$contentMigrations = $this->getMigrator('content')->getPendingMigrations();
201206
if (! empty($contentMigrations)) {
202207
$migrationsByTrack['content'] = $contentMigrations;

src/Database/LaravelMigrations.php

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,42 @@
1515
class LaravelMigrations
1616
{
1717
public function install(Migrator $migrator): void
18+
{
19+
$pendingMigrations = $this->reconcile($migrator);
20+
21+
if (empty($pendingMigrations)) {
22+
return;
23+
}
24+
25+
$migrator->run($pendingMigrations);
26+
}
27+
28+
/**
29+
* Reconciles already-existing optional Laravel tables with the content
30+
* migration track and returns any optional Laravel migrations that still
31+
* need to run.
32+
*
33+
* @return string[]
34+
*/
35+
public function reconcile(Migrator $migrator): array
1836
{
1937
$this->publishMigrationFiles();
2038

2139
$migrationPaths = $this->migrationPaths();
2240

2341
if (empty($migrationPaths)) {
24-
return;
42+
return [];
2543
}
2644

2745
$originalTrack = $migrator->getTrack();
2846

2947
try {
3048
$migrator->track('content');
3149

32-
$pendingMigrations = $migrator->getPendingMigrations($migrationPaths);
33-
$batch = $migrator->getRepository()->getNextBatchNumber();
34-
35-
foreach ($pendingMigrations as $key => $path) {
36-
if (! $this->migrationTableExists($path)) {
37-
continue;
38-
}
39-
40-
$migrator->getRepository()->log($migrator->getMigrationName($path), $batch);
41-
unset($pendingMigrations[$key]);
42-
}
43-
44-
$pendingMigrations = array_values($pendingMigrations);
45-
46-
if (empty($pendingMigrations)) {
47-
return;
48-
}
49-
50-
$migrator->run($pendingMigrations);
50+
return $this->reconcilePendingMigrations(
51+
$migrator,
52+
$migrator->getPendingMigrations($migrationPaths),
53+
);
5154
} finally {
5255
$migrator->track($originalTrack ?? 'content');
5356
}
@@ -135,6 +138,26 @@ private function migrationFiles(string $pattern): array
135138
return File::glob(app()->databasePath("migrations/$pattern")) ?: [];
136139
}
137140

141+
/**
142+
* @param string[] $pendingMigrations
143+
* @return string[]
144+
*/
145+
private function reconcilePendingMigrations(Migrator $migrator, array $pendingMigrations): array
146+
{
147+
$batch = $migrator->getRepository()->getNextBatchNumber();
148+
149+
foreach ($pendingMigrations as $key => $path) {
150+
if (! $this->migrationTableExists($path)) {
151+
continue;
152+
}
153+
154+
$migrator->getRepository()->log($migrator->getMigrationName($path), $batch);
155+
unset($pendingMigrations[$key]);
156+
}
157+
158+
return array_values($pendingMigrations);
159+
}
160+
138161
private function migrationTableExists(string $path): bool
139162
{
140163
$migrationName = pathinfo($path, PATHINFO_FILENAME);

src/Http/Controllers/MigrateController.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use CraftCms\Cms\Config\GeneralConfig;
88
use CraftCms\Cms\Database\Backups;
9+
use CraftCms\Cms\Database\LaravelMigrations;
10+
use CraftCms\Cms\Database\Migrator;
911
use CraftCms\Cms\ProjectConfig\Exceptions\BusyResourceException;
1012
use CraftCms\Cms\ProjectConfig\Exceptions\StaleResourceException;
1113
use CraftCms\Cms\ProjectConfig\ProjectConfig;
@@ -28,8 +30,10 @@ class MigrateController
2830
* services (like [DeployBot](https://deploybot.com/) or [DeployPlace](https://deployplace.com/)) to minimize site
2931
* downtime after a deployment.
3032
*/
31-
public function __invoke(Request $request, GeneralConfig $generalConfig, Updates $updates, ProjectConfig $projectConfig, MaintenanceModeManager $maintenance, Backups $backups)
33+
public function __invoke(Request $request, GeneralConfig $generalConfig, Updates $updates, ProjectConfig $projectConfig, MaintenanceModeManager $maintenance, Backups $backups, Migrator $migrator, LaravelMigrations $laravelMigrations)
3234
{
35+
$laravelMigrations->reconcile($migrator);
36+
3337
$handles = $updates->pendingMigrationHandles(true);
3438
$runMigrations = ! empty($handles);
3539

src/Plugin/Testing/PluginTestCase.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use CraftCms\Cms\Database\LaravelMigrations;
88
use CraftCms\Cms\Database\Migrations\Install;
9+
use CraftCms\Cms\Database\Migrator;
910
use CraftCms\Cms\Providers\CraftServiceProvider;
1011
use CraftCms\Cms\Site\Data\Site;
1112
use CraftCms\Yii2Adapter\Yii2ServiceProvider;
@@ -40,10 +41,17 @@ protected function migrateDatabases(): void
4041
password: 'craftcms2018!!',
4142
email: 'support@craftcms.com',
4243
site: $site,
43-
);
44+
)->silent();
4445

45-
$migration->up();
46-
app(LaravelMigrations::class)->ensureSessionsTable();
46+
$migrator = app(Migrator::class)->track('craft');
47+
$migrator->runMigration($migration, 'up');
48+
$migrator->getRepository()->log('Install', 1);
49+
50+
foreach ($migrator->getPendingMigrations() as $file) {
51+
$migrator->getRepository()->log($migrator->getMigrationName($file), 1);
52+
}
53+
54+
app(LaravelMigrations::class)->install($migrator);
4755
}
4856

4957
#[Override]

src/Queue/JobProgress.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ public function jobsQuery(): Builder
8989
->orderByRaw('CASE WHEN status = ? THEN 1 ELSE 0 END DESC', [JobStatus::Reserved->value])
9090
// Pending jobs go second
9191
->orderByRaw('CASE WHEN status = ? THEN 1 ELSE 0 END DESC', [JobStatus::Pending->value])
92-
// Then by now or dateCreated + delay
93-
->orderByRaw($delay, [now()->getTimestamp()])
92+
// Then by now or dateCreated + delay, with furthest delayed jobs first
93+
->orderByRaw("$delay DESC", [now()->getTimestamp()])
9494
// Lastly by dateCreated
9595
->orderBy('dateCreated');
9696
}

tests/Feature/Utility/UtilitiesTest.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,6 @@
6565
expect($this->utilities->getAuthorizedUtilityTypes())->not()->toContain(SystemReport::class);
6666
});
6767

68-
it('can get badge count for all utilities', function () {
69-
actingAs(User::find()->one());
70-
71-
expect($this->utilities->getUtilitiesBadgeCount())->toBe(0);
72-
});
73-
7468
class DummyUtility extends Utility
7569
{
7670
#[Override]

tests/TestCase.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,17 @@ protected function refreshTestDatabase(): void
202202

203203
Cache::lock(ProjectConfig::MUTEX_NAME)->forceRelease();
204204

205-
$migration->up();
206-
app(LaravelMigrations::class)->ensureSessionsTable();
207-
208-
// Mark all existing migrations as applied
209205
$migrator = app(Migrator::class)->track('craft');
206+
$migrator->runMigration($migration, 'up');
207+
$migrator->getRepository()->log('Install', 1);
208+
209+
// Mark all existing Craft migrations as applied
210210
foreach ($migrator->getPendingMigrations() as $file) {
211211
$migrator->getRepository()->log($migrator->getMigrationName($file), 1);
212212
}
213213

214+
app(LaravelMigrations::class)->install($migrator);
215+
214216
RefreshDatabaseState::$migrated = true;
215217
}
216218

tests/UnitTestCase.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use CraftCms\Cms\Site\Data\Site;
1010
use CraftCms\Cms\Support\Facades\Sites;
1111
use CraftCms\Cms\View\TemplateMode;
12+
use Illuminate\Contracts\Config\Repository as ConfigRepository;
13+
use Illuminate\Support\Facades\DB;
1214
use Illuminate\Support\Facades\File;
1315
use Orchestra\Testbench\Concerns\WithWorkbench;
1416
use Orchestra\Testbench\TestCase as Orchestra;
@@ -29,6 +31,21 @@ protected function setUp(): void
2931
{
3032
parent::setUp();
3133

34+
tap(app(ConfigRepository::class), function (ConfigRepository $config) {
35+
$config->set('database.default', 'sqlite');
36+
$config->set('database.connections.sqlite', array_merge(
37+
$config->get('database.connections.sqlite', []),
38+
[
39+
'driver' => 'sqlite',
40+
'database' => ':memory:',
41+
'prefix' => '',
42+
],
43+
));
44+
});
45+
46+
DB::purge('sqlite');
47+
DB::setDefaultConnection('sqlite');
48+
3249
Edition::set(Edition::Pro);
3350
TemplateMode::set(TemplateMode::Cp);
3451

0 commit comments

Comments
 (0)