Jump to content

RockMigrations1 - Easy migrations from dev/staging to live server


bernhard

Recommended Posts

v0.0.63

Thx to the feedback of @wbmnfktr I've made it a lot easier to get started with RockMigrations!

The readme has now a dedicated quickstart section: https://github.com/BernhardBaumrock/RockMigrations#quickstart

The example that was shipped with RockMigrations was also improved. I removed some complexity and used real world example names (a simple blog setup) instead of "foo" and "bar". This should make it a lot easier to understand ? 

Also I improved the page name replacements feature introduced lately: Page name replacements now ship with the module. They are saved in a dedicated folder and named "de.txt" for german replacements. If you need any other replacement options just let me know! (maybe @apeisa ? )

$rm->setPagenameReplacements("de");

https://github.com/BernhardBaumrock/RockMigrations/tree/master/replacements

  • Like 4
Link to comment
Share on other sites

  • 5 weeks later...

I love the module! 

I was wondering how do you handle creating a page reference field when the templates and pages are created in the same migration. Because you don't know the id's yet.

'fields' => [
	'pageSelect' => [
		'type' => 'page',
        'template_id' => XX, //template ID (foo-template to be created)
        'parent_id' => XX // Parent ID (parent-foo to be created),
        'inputfield' => 'InputfieldAsmSelect',
 	],
 ],

'templates' => [
    'foo-template',
	'parent-foo-template',
 ],

 

  • Like 1
Link to comment
Share on other sites

1 minute ago, bernhard said:

If execution order is important you can always use the declarative syntax:


$p1 = $rm->createPage(...);
$p2 = $rm->createPage(...);
$p2->setAndSave('pageref', $p1);

does that help?

Kind of

How would it work for field settings?

Link to comment
Share on other sites

v0.0.64 adds a new method

$rm->createViewFile('yourtemplate');

that creates a file /site/templates/yourtemplate.php

That might sound like overkill, but when used with class constant and OOP that makes it clear and easy:

<?php namespace RockTeam;

use ProcessWire\Page;
use ProcessWire\RockMigrations;
use ProcessWire\RockTeam;

class TeamPage extends Page {

  const prefix = RockTeam::prefix;
  const tpl = self::prefix."teampage";
  const tags = RockTeam::tags;

  /**
   * Triggered in RockTeam::migrate()
   */
  public function migrate(RockMigrations $rm) {
    $rm->migrate([
      'templates' => [
        self::tpl => [
          'tags' => self::tags,
          'icon' => 'users',
          'fields' => ['title'],
        ],
      ],
    ]);
    $rm->createViewFile(self::tpl);
  }

}

 

  • Like 2
Link to comment
Share on other sites

Hi Ivan,

good question ? My workflow is based on RockUikit - a module for Frontend Development similar to WireFrame. So I need the file solely for making the site visible on the frontend. Markup is placed in a different location. Now that you are asking I realize that this might not be the most helpful addition for others. Anyhow I'm just keeping you updated so maybe someone will pick up some inspiration or have suggestions or input for me ? 

But in general my workflow is now a little bit like "everything is a module" ? And RockMigrations does everything related to template/field/page creation ? 

  • Like 1
Link to comment
Share on other sites

Actually it already has a second parameter to provide a file to take the content from. This means you could add a skeleton folder to your module holding the initial markup and the module will copy that content to the templates folder: https://github.com/BernhardBaumrock/RockMigrations/blob/3844b697be393b98dbc9a47b55370c4fa521c20b/RockMigrations.module.php#L1817

One could also make it sync files or add the file having a single "include" to reference the markup from within a module folder. But I didn't want to overcomplicate things ? 

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...

v0.0.67 has a fix to setModuleConfig method that might change how existing implementations work:

$rm->setModuleConfig("AdminThemeUikit", [
	'maxWidth' => 0, // use full width of screen
]);

Before the fix from today this code would have reset any other module settings (like a custom logoURL). No it does only update the maxWidth setting (as it merges existing config data). If you want the old behaviour you can set the third parameter to TRUE:

$rm->setModuleConfig("AdminThemeUikit", [
	'maxWidth' => 0, // use full width of screen
], TRUE);

 

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...
On 3/11/2021 at 10:42 AM, bernhard said:

Whenever I don't know the code for a migration I simply create the field and have a look at Tracys field code panel:

IzoRwd4.png

 

Just a couple of quick questions - and I know this might be more of a question for Tracy Debugger itself but - why can't I see "Field Code" in my Request tab? 

Edit: sorry, found it! Tracy settings > Request info panel > Panel sections if anyone else was wondering.

Is there any other useful things I should turn on in Tracy for copying field data and similar?? ? 

And second question please, how do I add a field to a template and have it be inside a Fieldset Tab?

Thanks in advance!

Link to comment
Share on other sites

21 hours ago, cjx2240 said:

Is there any other useful things I should turn on in Tracy for copying field data and similar?? ? 

dont think so ? 

21 hours ago, cjx2240 said:

And second question please, how do I add a field to a template and have it be inside a Fieldset Tab?

Usually I do that via hooking ProcessPageEdit::buildForm and the wrapFields method of RM

<?php
$this->addHookAfter("ProcessPageEdit::buildForm", function(HookEvent $event) {
    $page = $event->process->getPage();
    if($page->template != "yourtemplate") return;
    $form = $event->arguments(0);
	$rm = $event->modules->get("RockMigrations");
	$rm->wrapFields($form, ['field1', 'field2'], [
      'label' => 'your fieldset label',
      'icon' => 'bolt',
    ]);
});

 

  • Like 2
Link to comment
Share on other sites

  • 5 weeks later...

I'm looking forward to using your module Bernhard. I have written an application in ProcessWire over the past year, and 3 months into development I started kicking myself for not starting from a multi-site perspective. Now with this I can see a solid workflow for migrations whilst benefiting from keeping users locked in their own instances.

Having now read the docs I'm keen to try it out with a single new feature that will require several templates, fields and pages!

  • Like 2
Link to comment
Share on other sites

  • 3 months later...

Hi @bernhard, thank you for this great module. I am trying to add a repeater field which is very easy as this 

'repeater_field' => [
	'type' => 'repeater',
	'label' => 'Label',
	'repeaterFields' => [
		'field1',
		'field2'
	]
]

How can I set fields' contexts, I need to set their columnWidths

I tried the same approach as with template fields

'repeater_field' => [
	'type' => 'repeater',
	'label' => 'Label',
	'repeaterFields' => [
		'field1' => [
			'columnWidth' => 50
		],
		'field2' => [
			'columnWidth' => 50
		]
	]
]

but it doesn't work.

Link to comment
Share on other sites

@bernhard Some questions come to my mind. 

1) I am now using $rm->fireOnRefresh(...) for executing my "permanent" migrations (mostly declarative, describing a structure). But what should I do if I have some migration which I want to run only once, e.g. renaming a field (but could be more complex dealing with data). I got an idea to run that specific "upgrade" migration when upgrading a module to a specific version, which would work. The problem is, when I refresh modules my "permanent" migrations (which expects the field is already renamed!!) will run before upgrading a module and running the "upgrade" migration. ?

2) Did you explored the Import/Export code (for fields, templates, ...) already built in ProcessWire? It is similar to what RockMigrations do (in declarative way) or not? I did not explored it much, but I am thinking if your module is needed, if there are already similar functions in a core code.

3) Consireding 2) and previous discussion

On 12/8/2021 at 4:19 PM, bernhard said:

At the moment not, but if you think that would be worth to have you could add that here and create a PR: https://github.com/BernhardBaumrock/RockMigrations/blob/dc9dba1b050469ea085af9dca1201746e2422960/RockMigrations.module.php#L984-L990

when I export a template or repeater field (using the built-in admin buttons), context for subfields is stored under fieldContexts key, so e.g. for a repeater field:

'repeater_field' => [
	'type' => 'repeater',
	'label' => 'Label',
	'repeaterFields' => [
		'field1',
		'field2'
	],
	'fieldContexts' => [
		'field1' => [
			'columnWidth' => 50
		],
		'field2' => [
			'columnWidth' => 50
		]
	]
]

the same for a template, so maybe you can use the same format in RM.

Link to comment
Share on other sites

3 hours ago, Richard Jedlička said:

But what should I do if I have some migration which I want to run only once, e.g. renaming a field (but could be more complex dealing with data).

Adding data via migrations is the most straightforward thing, but removing or renaming is a little more tricky, as you realized ? Usually all methods are built in a way that they can run as often as you want. That means you can just run $rm->renameField(...) as often as you want: https://github.com/BernhardBaumrock/RockMigrations/blob/dc9dba1b050469ea085af9dca1201746e2422960/RockMigrations.module.php#L942-L944

I know that adds a little overhead and I've heard from @dotnetic that some of his migrations needed around 20 seconds to finish. On all of my setups (and I'm using RM all the time, everywhere, extensively) site-wide migrations fired via $rm->fireOnRefresh(...) take at most around 2 seconds to finish.

If you really want to avoid that, you can always do custom logic via PHP's if/else... Of course that does not work with declarative syntax, but that's no problem in my opinion. The declarative syntax is easier to use and easier to read, but it has limitations regarding the execution of things by design.

3 hours ago, Richard Jedlička said:

Did you explored the Import/Export code (for fields, templates, ...) already built in ProcessWire? It is similar to what RockMigrations do (in declarative way) or not? I did not explored it much, but I am thinking if your module is needed, if there are already similar functions in a core code.

I'm not sure. I've evaluated it more than 2 years ago and never ever used it again. It was simply useless for my workflows. I've just had a glance in the core and it does not seem to be very helpful for RM.

 

I've just addes support for your request and added an example to the readme:

$rm->migrate([
  // fields to create
  'fields' => [
    'ready_text' => [
      'type' => 'textarea',
      'tags' => 'ReadyDemo',
    ],
    'context_example' => [
      'type' => 'text',
      'label' => 'Global field label',
    ],
  ],
  // templates to create
  'templates' => [
    'ready_blog' => [
      'tags' => 'ReadyDemo',
      'fields' => [
        'title',
        'context_example' => [
          'label' => 'Field label on ready_blog template',
        ],
      ],
    ],

Repeaters

$rm->migrate([
  'fields' => [
    'foo_field' => [...],
    'bar_field' => [...],
    'my_repeater_field' => [
      'type' => 'repeater',
      'repeaterFields' => [
        // you can set field data in repeater context like this:
        'title' => ['required'=>0],
        'foo_field' => ['columnWidth'=>50],
        'bar_field'=> ['columnWidth'=>50],
      ],
    ],
  ],
]);
  • Like 2
Link to comment
Share on other sites

  • bernhard changed the title to RockMigrations1 - Easy migrations from dev/staging to live server

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...