Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
BernhardBaumrock committed Jan 11, 2025
2 parents 45601c9 + 101c575 commit 71c4d92
Show file tree
Hide file tree
Showing 15 changed files with 1,550 additions and 362 deletions.
53 changes: 48 additions & 5 deletions RockMigrations.module.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ public function init()
wire()->addHookBefore("InputfieldForm::render", $this, "showEditInfo");
wire()->addHookBefore("InputfieldForm::render", $this, "showCopyCode");
wire()->addHookBefore("Modules::uninstall", $this, "unwatchBeforeUninstall");
wire()->addHookBefore("Modules::install", $this, "beforeModuleInstall");
wire()->addHookAfter("Modules::install", $this, "migrateAfterModuleInstall");
wire()->addHookAfter("Page(template=admin)::render", $this, "addColorBar");
wire()->addHookBefore("InputfieldForm::render", $this, "addRmHints");
Expand Down Expand Up @@ -656,6 +657,14 @@ public function basename($file)
return basename($this->filePath($file));
}

protected function beforeModuleInstall(HookEvent $event): void
{
$moduleName = $event->arguments(0);
$moduleDir = dirname(wire()->modules->getModuleFile($moduleName));
$migrationsDir = $moduleDir . '/RockMigrations';
if (is_dir($migrationsDir)) $this->runConfigMigrations($migrationsDir);
}

/**
* Get data from cache that is automatically recreated on Modules::refresh
*
Expand Down Expand Up @@ -817,13 +826,17 @@ private function createConstantTraits(): void
$const = [];
$constants = [];
foreach ($configFiles as $file) {
$type = $this->getConfigFileType($file);

// no type means it's a config migrations hook file
// in the root of the /RockMigrations folder
if (!$type) continue;
$tag = $this->getConfigFileTag($file);

// skip files that have no tag (not part of a module)
// these files are located in /site/RockMigrations/*
if (!$tag) {
$const[] = $file;
} else {
if (!$tag) $const[] = $file;
else {
if (!array_key_exists($tag, $constants)) $constants[$tag] = [];
$constants[$tag][] = $file;
}
Expand Down Expand Up @@ -3560,6 +3573,7 @@ public function minify($file, $minFile = null): string|false
try {
$minify->minify($minFile);
} catch (\Throwable $th) {
if (wire()->config->debug) $this->log($th->getMessage());
}
$this->log("Minified $minFile");
} elseif ($ext == 'js') {
Expand All @@ -3569,7 +3583,13 @@ public function minify($file, $minFile = null): string|false
try {
$minify->minify($minFile);
} catch (\Throwable $th) {
if (wire()->config->debug) $this->log($th->getMessage());
}
} else if ($ext == 'less') {
// less files will be converted to css with default settings
// if you want to customise that you can use saveCSS() in your code
$css = $this->saveCSS($file);
return $this->minify($css, $minFile);
} else {
throw new WireException("Invalid Extension $ext");
}
Expand Down Expand Up @@ -4149,6 +4169,11 @@ function (RockMigrations $rm) {
*/
private function runConfigFile(string $file, $firstRun = false): void
{
// skip all files that are directly in the /RockMigrations folder
// these files are hook-files like beforeData.php or afterAssets.php
$type = $this->getConfigFileType($file);
if ($type === false) return;

$url = $this->toUrl($file);
$this->log($url);

Expand All @@ -4161,7 +4186,6 @@ private function runConfigFile(string $file, $firstRun = false): void

$config = $this->getConfigFileArray($file);
$name = $this->getConfigFileName($file);
$type = $this->getConfigFileType($file);

// don't run migrations directly in RockMigrations folder
// this is the case for constants traits
Expand All @@ -4184,7 +4208,7 @@ private function runConfigFile(string $file, $firstRun = false): void
$fieldname = array_key_exists('name', $config)
? $config['name']
: $name;
$this->createField($fieldname, $config);
$this->createField($fieldname, $config['type']);
$this->setFieldData($fieldname, ['tags' => $tag]);
break;
case 'templates':
Expand Down Expand Up @@ -4213,6 +4237,21 @@ private function runConfigFile(string $file, $firstRun = false): void
}
}

/**
* Run config hook files like /RockMigrations/beforeAssets.php
* Refer to the config migrations documentation for more info!
*/
private function runConfigHooks(string $type, array $items): void
{
$items = array_filter($items, fn($file) => str_ends_with($file, "/RockMigrations/$type.php"));
$cnt = count($items);
$this->log("--- config migration hook: $type ($cnt files) ---");
foreach ($items as $file) {
$this->log($this->toUrl($file));
require $file;
}
}

/**
* Run config migrations of given files
*
Expand All @@ -4237,10 +4276,14 @@ public function runConfigMigrations(
$this->log("### Running Config Migrations ###");
$this->indent(2);
if ($createTrait) $this->createConstantTraits();
$this->runConfigHooks('beforeAssets', $items);
$this->log("--- first run: create assets ---");
foreach ($items as $file) $this->runConfigFile($file, true);
$this->runConfigHooks('afterAssets', $items);
$this->runConfigHooks('beforeData', $items);
$this->log("--- second run: migrate data ---");
foreach ($items as $file) $this->runConfigFile($file);
$this->runConfigHooks('afterData', $items);
$this->indent(-2);
}

Expand Down
2 changes: 1 addition & 1 deletion RockShell/Commands/RmTransform.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function handle()
// load root path via PHP
// don't load $config via wire() because it will try to create some
// new cache files on shutdown which will show warnings in the console
$src = rtrim($this->app->root, "/");
$src = rtrim($this->app->rootPath(), "/");

if (!$this->confirm("This will create a new folder structure in $src - continue?")) {
return self::SUCCESS;
Expand Down
90 changes: 90 additions & 0 deletions docs/config-migrations-hooks/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Config Migration Hooks

RockMigrations executes migrations in a specific order and provides hooks that allow you to run custom code at different stages of the migration process. This is particularly useful for handling dependencies and circular references.

## Available Hooks

The migration process follows this sequence:

1. `beforeAssets`
- Executed before any assets (fields, templates, etc.) are created
- Use this hook if you need to prepare anything before asset creation

2. `afterAssets`
- Executed after all assets have been created but before any data migrations
- Perfect for creating pages that depend on templates that were just created
- At this stage, templates and fields exist but don't have their settings applied yet

3. `beforeData`
- Executed before data migrations start
- Useful for preparing data structures that your migrations might depend on

4. `afterData`
- Executed after all data migrations are complete
- Use this for cleanup tasks or final adjustments

## How to Use Hooks

To use a migration hook, create a PHP file in your `RockMigrations` directory (either `/site/RockMigrations` or `/site/modules/[module-name]/RockMigrations`) with the corresponding name:

```php
site/RockMigrations/beforeAssets.php
site/RockMigrations/afterAssets.php
site/RockMigrations/beforeData.php
site/RockMigrations/afterData.php
```

## Example Use Case

A common scenario where hooks are valuable is when dealing with circular dependencies. For example:

1. You need to create a page reference field
2. This field needs to reference a specific parent page
3. The parent page uses a template that is being created in the same migration

Solution using hooks:

1. Create the template in your regular migration file
2. Use the `afterAssets` hook to create the parent page (templates exist but settings aren't applied yet)
3. Create the page reference field in your regular migration file

```php
<?php

namespace ProcessWire;

$rm = rockmigrations();
$rm->createPage(
template: RockMigrationsConstants::template_foo,
parent: 1,
name: 'my-pagename',
title: 'My Page Title',
);
```

This structured approach ensures that dependencies are handled correctly and circular references can be resolved effectively.

## Example Log

When running config migrations, you'll see a detailed output of all the steps that are being executed. This includes the creation of constant traits, running of hooks, and the processing of your migration files. Here's an example of what the output looks like:

```
### Running Config Migrations ###
--- create PHP constant traits ---
Created /var/www/html/site/RockMigrationsConstants.php
--- config migration hook: beforeAssets (0 files) ---
--- first run: create assets ---
/site/RockMigrations/fields/foo.php
Name: foo
Tag:
/site/RockMigrations/templates/bar.php
Name: bar
Tag:
--- config migration hook: afterAssets (0 files) ---
--- config migration hook: beforeData (1 files) ---
/site/RockMigrations/beforeData.php
--- second run: migrate data ---
/site/RockMigrations/fields/foo.php
/site/RockMigrations/templates/bar.php
--- config migration hook: afterData (0 files) ---
```
12 changes: 10 additions & 2 deletions docs/config-migrations/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ These kind of circular dependencies can be solved by using config migrations, wh

## Using Config Migrations

> There is a [RockMigrations demo module](https://github.com/baumrock/ConfigMigrationsDemo) that shows how to use config migrations.
All you have to do to use config migrations is to create a PHP file in one of the supported directories:

- `site/RockMigrations/[type]/[name].php`
Expand All @@ -17,6 +19,12 @@ Where `[type]` is one of `fields`, `templates`, `roles`, `permissions` and `[nam

RockMigrations can create class constant traits/classes for you that make working with your assets a breeze. This feature is NOT enabled by default, so be sure to check out the instructions about them at the end of this page!

## Config Migration Hooks

RockMigrations provides a powerful hooks system that allows you to execute code at specific points during the migration process. This is particularly useful for handling dependencies and circular references.

For detailed information about config migration hooks, see the [Config Migration Hooks Documentation](../config-migrations-hooks/).

## Example Migration Files

### Field
Expand Down Expand Up @@ -153,10 +161,10 @@ Module specific migrations need an additional step, because we want the constant
MyModule::field_myfield
```

- Create the file `site/modules/MyModule/RockMigrations/RockMigrationsConstants.php`
- Create the file `site/modules/MyModule/RockMigrationsConstants.php` (Note: In the root folder of the module, not in the RockMigrations folder!)
- Do a modules refresh

RockMigrations should now have created a trait file like this in `/site/modules/MyModule/RockMigrations/RockMigrationsConstants.php`:
RockMigrations should now have created a trait file like this in `/site/modules/MyModule/RockMigrationsConstants.php`:

```php
<?php
Expand Down
3 changes: 3 additions & 0 deletions docs/deploy-1/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Deployments Advanced

TBD
Loading

0 comments on commit 71c4d92

Please sign in to comment.