Code Monkey home page Code Monkey logo

rockmigrations's Introduction


See the video here:



Module Description

RockMigrations has an easy API to do all the things you can do in the PW backend via code. This means you can fully version control your site or app simply by adding all the necessary fields and templates not via clicking but via writing simple scripts that do that tasks for you.

The module also contains several helpers that make it extremely easy to implement fully automated CI/CD pipelines.

Wiki

Check out the WIKI for a Quickstart and Docs!

Pro-Fields and 3rd-Party-Fields

While RockMigrations efficiently handles most database schema changes, it's worth mentioning that not all ProcessWire pro-fields or 3rd-party-fields might be covered. In case of unsupported fields, users have the choice to sponsor the addition of support or opt for manual migration using traditional methods, mimicking a scenario without RockMigrations. This approach guarantees versatility for different field types within the ProcessWire CMS ecosystem.

Also don't forget that you can still use the PW API for everything you need or want even if you are using RockMigrations. That means you can use RockMigrations for everything that it supports (which is maybe 99% of what anybody needs) and just use the plain PW API for the remaining 1% or even make those changes manually if that is an option.

Where do I find out all those field and template properties?

  1. You can edit your field or template and copy the code from there (I recommend to only copy the settings you need to make your migration files more readable): img

  2. Hover the caret on the very right of the field of the setting you want to set: img

Magic

RockMigrations does not only help you with your migrations and deployments but it also adds a lot of helpers that make developing with ProcessWire even more fun.

See WIKI for MagicPages!

Snippets

Another option that helps you get started with migration syntax is using the shipped VSCode snippets. I highly recommend enabling the syncSnippets option in your config:

// site/config.php
$config->rockmigrations = [
  "syncSnippets" => true,
];

Watching files, paths or modules

RockMigrations can watch files, paths and modules for changes. It will detect changes on any of the files on the watchlist and trigger migrations to run if anything changed.

As from version 1.0.0 (29.8.2022) RockMigrations will not run all migrations if one file changes but will only migrate this single changed file. This makes the migrations run a lot faster!

When run from the CLI it will still run every single migration file to make sure that everything works as expected and no change is missed.

Sometimes it is necessary that even unchanged files are migrated. RockMatrix is an example for that, where the module file triggers the migrations for all Matrix-Blocks. In that case you can add the file to the watchlist using the force option:

// inside RockMatrix::init
$rm->watch($this, true, ['force'=>true]);

Watching modules

You can easily watch any ProcessWire module for changes and trigger the migrate() method whenever the file is changed:

// module needs to be autoload!
public function init() {
  $rm = $this->wire->modules->get('RockMigrations');
  if($rm) $rm->watch($this);
}
public function migrate() {
  bd('Migrating MyModule...');
}

Watching files

You can watch single files or entire paths:

$rm->watch(__FILE__, false);
$rm->watch(__DIR__."/foo");

Note that you need to define FALSE as second parameter if the file should not be migrated but only watched for changes. If you set it to TRUE the file will be included and executed as if it was a migration script (see examples below).

Running migrations

RockMigrations will run migrations automatically when a watched file was changed. In case you want to trigger the migrations manually (eg after deployment) you can use the migrate.php file:

php site/modules/RockMigrations/migrate.php

Sometimes you want to work on a file and you want it to be watched for changes, but you don't want to trigger the migrations all the time. For example when working on markup or LESS. In that case you can disable automatic running of migrations:

$config->noMigrate = true;

This prevents running migrations but files will still be watched for changes and you will still be able to trigger migrations from the CLI.

Hooking after migrationsDone

If you want to apply migrations after all other migrations have run, you can hook after migrationsDone:

$wire->addHookAfter("RockMigrations::migrationsDone", function(HookEvent $event) {
  /** @var RockMigrations $rm */
  $rm = $event->object;
  $rm->removeFieldFromTemplate('title', 'field-profilephoto');
  $rm->removeFieldFromTemplate('title', 'field-pressphoto');
});

Files On Demand

You can instruct RockMigrations to download files on demand from a remote server. This makes it possible to create content on the remote system (eg on the live server), pull data from the database to your local machine and as soon as you open a page RockMigrations will fetch the missing files from your remote server.

// without authentication
$config->filesOnDemand = 'https://example.com';

// with http basic authentication
$config->filesOnDemand = 'https://user:[email protected]';

YAML

$rm->watch("/your/file.yaml");
fields:
  foo:
    type: text
    label: My foo field

PHP

$rm->watch("/your/file.php");
<?php namespace ProcessWire;
$rm->createField('foo', 'text');

Auto-Watch

RockMigrations automatically watches /site/migrate.php and files like YourModule.migrate.php.

Working with YAML files

RockMigrations ships with the Spyc library to read/write YAML files:

// get YAML instance
$rm->yaml();

// get array from YAML file
$rm->yaml('/path/to/file.yaml');

// save data to file
$rm->yaml('/path/to/file.yaml', ['foo'=>'bar']);

Working with fieldsets

Working with fieldsets is a pain because they need to have an opening and a closing field. That makes it complicated to work with it from a migrations perspective, but RockMigrations has you covered with a nice little helper method that can wrap other fields at runtime:

// syntax
$rm->wrapFields($form, $fields, $fieldset);

// usage
$wire->addHookAfter("ProcessPageEdit::buildForm", function($event) {
  $form = $event->return;

  /** @var RockMigrations $rm */
  $rm = $this->wire->modules->get('RockMigrations');
  $rm->wrapFields($form, [
    'title' => [
      // runtime settings for title field
      'columnWidth' => 50,
    ],
    // runtime field example
    [
      'type' => 'markup',
      'label' => 'foo',
      'value' => 'bar',
      'columnWidth' => 50,
    ],
    'other_field_of_this_template',
  ], [
    'label' => 'I am a new fieldset wrapper',
  ]);
})

Migration Examples

Field migrations

CKEditor field

$rm->migrate([
  'fields' => [
    'yourckefield' => [
      'type' => 'textarea',
      'tags' => 'MyTags',
      'inputfieldClass' => 'InputfieldCKEditor',
      'contentType' => FieldtypeTextarea::contentTypeHTML,
      'rows' => 5,
      'formatTags' => "h2;p;",
      'contentsCss' => "/site/templates/main.css?m=".time(),
      'stylesSet' => "mystyles:/site/templates/mystyles.js",
      'toggles' => [
        InputfieldCKEditor::toggleCleanDIV, // convert <div> to <p>
        InputfieldCKEditor::toggleCleanP, // remove empty paragraphs
        InputfieldCKEditor::toggleCleanNBSP, // remove &nbsp;
      ],
    ],
  ],
]);

Image field

$rm->migrate([
  'fields' => [
    'yourimagefield' => [
      'type' => 'image',
      'tags' => 'YourTags',
      'maxFiles' => 0,
      'descriptionRows' => 1,
      'extensions' => "jpg jpeg gif png svg",
      'okExtensions' => ['svg'],
      'icon' => 'picture-o',
      'outputFormat' => FieldtypeFile::outputFormatSingle,
      'maxSize' => 3, // max 3 megapixels
    ],
  ],
]);

Files field

$rm->migrate([
  'fields' => [
    'yourfilefield' => [
      'type' => 'file',
      'tags' => 'YourTags',
      'maxFiles' => 1,
      'descriptionRows' => 0,
      'extensions' => "pdf",
      'icon' => 'file-o',
      'outputFormat' => FieldtypeFile::outputFormatSingle,
    ],
  ],
]);

Options field

$rm->migrate([
  'fields' => [
    'yourfield' => [
      'type' => 'options',
      'tags' => 'YourTags',
      'label' => 'Options example',
      'options' => [
        1 => 'ONE|This is option one',
        2 => 'TWO',
        3 => 'THREE',
      ],
    ],
  ],
]);

Options field with multilang labels:

$rm->createField('demo_field', 'options', [
  'label' => 'Test Field',
  'label1020' => 'Test Feld',
  'type' => 'options',
  'optionsLang' => [
    'default' => [
      1 => 'VERYLOW|Very Low',
      2 => 'LOW|Low',
      3 => 'MIDDLE|Middle',
      4 => 'HIGH|High',
      5 => 'VERYHIGH|Very High',
    ],
    'de' => [
      1 => 'VERYLOW|Sehr niedrig',
      2 => 'LOW|Niedrig',
      3 => 'MIDDLE|Mittel',
      4 => 'HIGH|Hoch',
      5 => 'VERYHIGH|Sehr hoch',
    ],
  ],
]);

Note that RockMigrations uses a slightly different syntax than when populating the options via GUI. RockMigrations makes sure that all options use the values of the default language and only set the label (title) of the options.

Page Reference field

$rm->migrate([
  'fields' => [
    'yourfield' => [
      'type' => 'page',
      'label' => __('Select a page'),
      'tags' => 'YourModule',
      'derefAsPage' => FieldtypePage::derefAsPageArray,
      'inputfield' => 'InputfieldSelect',
      'findPagesSelector' => 'foo=bar',
      'labelFieldName' => 'title',
    ],
  ],
]);

Date field

$rm->migrate([
  'fields' => [
    'yourfield' => [
      'type' => 'datetime',
      'label' => __('Enter date'),
      'tags' => 'YourModule',
      'dateInputFormat' => 'j.n.y',
      'datepicker' => InputfieldDatetime::datepickerFocus,
      'defaultToday' => 1,
    ],
  ],
]);

RepeaterMatrix field

$rm->createRepeaterMatrixField('repeater_matrix_field_name', [
   'label' => 'Field Label',
   'tags' => 'your tags',
   'repeaterAddLabel' => 'Add New Block',
   'matrixItems' => [ // matrix types with their fields
       'type1' => [
           'label' => 'Type1',
           'fields' => [
               'title' => [
                   'label' => 'Custom Title',
                   'description' => 'Custom description',
                   'required' => 1,
               ],
           ]
       ],
       'type2' => [
           'label' => 'Type2',
           'fields' => [
               'text' => [
                  'label' => 'Custom Label',
               ],
               'checkbox',
           ]
       ],
   ]
]);

// remove a matrix type from a matrix field
$rm->removeMatrixItem('repeater_matrix_field_name', 'name_of_type');
// do not forget to also remove the type from the 'matrixItems' array above

Star History

Star History Chart

rockmigrations's People

Contributors

bernhardbaumrock avatar donatasben avatar fsnck avatar gebeer avatar ivangretsky avatar jmartsch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rockmigrations's Issues

Allow field parent_id to be a path + migrate method order of operation issue

I've written a migration module for my own internal use that's not as sophisticated as RM, but the lessons I learned apply to RM as well. When creating fields, templates and pages, the order of operation matters since there are dependencies between them. RM gets this right mostly, but there is technically an issue.

Keep in mind, this is within the context of using the migrate() method...

A

First, a feature request. When creating a page field, it requires parent_id to actually be an ID. It would be nice if RM could support a page path here so I could put something like /posts/ as this would make it more portable. Otherwise, I could put wire('pages')->get('/posts/')->id here instead of a hardcoded ID. I noticed with template_id it doesn't actually require an ID and putting post works fine there. So making parent_id work in a similar way would bring some consistency.

B

Regardless of whether a parent_id is hardcoded or provided using wire('pages')->get('/posts/')->id, this will not get set when running a FRESH migration. It will require the migration to run twice. This is because of how the migrate() method works in RM. The migrate method runs things in this order (I've skipped a few steps that aren't relevant):

  1. creates fields
  2. creates templates
  3. sets field data
  4. sets template data
  5. creates pages

The problem with this is that for a page reference field, the parent_id doesn't exist yet since the page it's referring to has not yet been created. You could have a step 6 that re-does step 3 (meaning set field data twice), but that won't work either given how setting it via wire('pages')->get('/posts/')->id doesn't get reevaluated.

Not allowed to load local resource

image

I have updated from 2.x version to 3.27

Seems like it's trying to load a local file in admin (RockMigrations.admin.css and RockMigrations.js) instead of a relative path.

<link type='text/css' href='D:\development\bpg-qrmetals\site\modules\RockMigrations/RockMigrations.admin.css?m=1691581368' rel='stylesheet'/>

Updating pages via calling createPage or the migrate config array ignores existing title values in the DB if one is not supplied

If you wish to update a page rather than create it, the method will rename the title of the page to the name if you do not supply a title value in the array, overwriting the existing DB title value for the page.

I ran into this issue because I wanted to set unpublished permissions that already existed but were left unpublished to a status of published automatically.

This following code:

$rm->migrate([
    'pages' => [
        'page-action-move' => [
            'parent' => 'name=permissions,template=admin',
            'template' => 'permission',
            'status' => [
                'on',
            ],
        ],
    ],
]);

for example causes the page to update to published, but the page title becomes the page name. The original title value is lost.

The fix is relatively simple I think.

In the RockMigrations.module.php in the migrate() function around line 2830 in the //setup pages section, the createPage call should read:

   // setup pages
    foreach ($config->pages as $name => $data) {
      if (isset($data['name'])) {
        $name = $data['name'];
      } elseif (is_int($name)) {
        // no name provided
        $name = uniqid();
      }

      $d = $this->wire(new WireData());
      /** @var WireData $d */
      $d->setArray($data);
      $this->createPage(
        title: $d->title, //remove the ?: $name so this may be sent as null
        name: $name,
        template: $d->template,
        parent: $d->parent,
        status: $d->status,
        data: $d->data
      );
    }

In the RockMigrations.module.php in the createPage() function around line 1146 or so, the conditional operation should be:

   if ($page and $page->id) {
      $set_title = ($title) ? $title : $page->title; //check new title against existing title value
      $page->setAndSave('title', $set_title ?: $name); //if still no title, use $name
      $page->status($status ?: []);

      // if some page field values are provided we save them now
      if (is_array($data)) $page->setAndSave($data);

      return $page;
    }

Provide a way to identify templates and fields controlled by RockMigrations in the panel

Hi @BernhardBaumrock

Next request incoming :)

I'm in the process of implementing RockMigrations in an existing site with a few existing templates and fields. It would be nice to be able to identify the fields I haven't copied over to my migration code at a glance. Something like a new icon with the title "Controlled by Rock Migrations" on the right would be pretty helpful I imagine:

Fields:
CleanShot 2023-12-12 at 11 08 40@2x

Templates:
CleanShot 2023-12-12 at 11 12 26@2x

What do you think?

.dotfiles or .directories/ should be skipped

I often have directories or files with a preceding dot like "site/modules/.TracyDebugger". I think they are obsolete files coming from an update of modules or something like that.
However I think, that these directories and files should be excluded from a migration.

What you think about that?

Feature request: FieldtypeCombo support (ProFields module)

It would be super awesome if you could implement support for adding, removing, sorting in FieldtypeCombo subfields (ProFields module from Ryan).
The actual code is already given by Ryan in the forum, data scheme can be viewed in the exported field JSON code, but it would be very convenient if we could use good-old RockMigrations for manipulating these fields too, just like you have for FieldtypeRepeaterMatrix.

The example code by Ryan for adding new subfield is here - https://processwire.com/talk/topic/29271-create-field-into-existing-combofield-trough-api/?do=findComment&comment=237481

Or if you don't have access:

// data for the new subfield you want to create 
// like what you see in the JSON, but without the 'i123_' prefixes
$data = [
  "type" => "Integer", // see types at top of ComboModuleConfig.php
  "label" => "Test integer",
  "name" => "test_integer",
  "columnWidth" => 100,
  "ok" => "1", // 1 means that it's ready to show in page editor
  "schemaType" => "n-int-small-u", // see schema types in ComboSchema.php
  "collapsed" => 0,
  "inputType" => "text", // "text" or "number"
  "size" => 10,
];

$field = $fields->get('test_combo'); // get the combo field
$i = $field->get('qty') + 1; // identify index for new field
foreach($data as $name => $value) { 
  // set data for new subfield using index we determined above
  $field->set("i{$i}_$name", $value); 
}
$field->set('qty', $i); // update the quantity of subfields
$field->order .= ",$i"; // append new subfield to CSV order string
$field->save(); // saving creates the subfield and updates the DB schema

Docs improvement suggestion (lacks info)

Hi,
I was trying to find but couldn't (I could swear I have seen it, but probably on RM1) info how to correctly use the $rm->migrate(['fields'=>[]]) to create reapeaters. More specifically - set their fields. I found no examples in the docs.
GitHub Wiki shows:

Docs moved to https://www.baumrock.com/en/processwire/modules/rockmigrations/docs/

But there are no mention of repeater fields in those docs.

Also I couldn't find how to use migrate structure to create pages: how to set required fields, how to maybe set page field data. I was experimenting with it, but ran into some trouble. I found out that if the template is different from already existing page (name, path, etc. - identical. Want to just change template) - it created a new page instead of changing existing.
Could changing page template via "migrate" made possible in the future?

Tag support for PageFile and PageImage classes?


It looks like there is some extra work that needs to be complete for tag support on files and images.

If you try to create an images field that has the useTags field set using migrate() you will see what I mean. There is an expected column that doesn't get created by default.

There is some extra schema that needs to be worked out. I started doing some code for it but got sidetracked.

This is my pseudo - it doesn't work yet I don't think, but it's what I started before I got sidetracked. I insert this at Rockmigrations.module.php:3593 :

//If useTags flag is set, invoke the getDatabaseSchema method
//to indirectly call the private updateDatabaseSchema function to create the tags column. JAG Added

if (isset($data['useTags'])) {
  //bd($data['useTags']);
  $fieldtypeFile = $field->getFieldtype();
  $fieldtypeFile->getDatabaseSchema($field);
}

You can find the updateDatabaseSchema functions in the wire/FieldtypeFile.module and wire/FieldtypeImage.module

Provide functional access to RockMigrations

Hi there! Right now, RockMigrations needs to be referenced like this everywhere it's being used:

/** @var RockMigrations $rm */
$rm = $this->wire->modules->get('RockMigrations');
$rm->...

How about providing a little helper function with the module, similar to ProcessWire's functions API? That would make code completion feel much cleaner IMO. This little snippet in the module would be enough:

/**
 * Provide access to RockMigrations
 * @return RockMigrations
 */
function rm(): RockMigrations {
	return wire()->modules->get('RockMigrations');
}

Than we could save us the additional like $rm = $this->wire->modules->get('RockMigrations'); throughout our code bases by using the function directly:

/** anywhere, migrate.php, page classes, ... */
rm()->migrate(...)

Modifying existing repeaterMatrix fields

Hi there! I just gave migrating repeater matrix fields another go. I'm testing with a field named blocks. This is the migration code from the panel:

'blocks' => [
  'label' => 'Blocks',
  'flags' => 0,
  'type' => 'FieldtypeRepeaterMatrix',
  'template_id' => 0,
  'parent_id' => 0,
  'matrix1_name' => 'imageblock',
  'matrix1_label' => 'Image',
  'matrix1_head' => '{matrix_label} [• {matrix_summary}]',
  'matrix1_fields' => [
    0 => 'image',
    1 => 'aspect_ratio',
  ],
  'matrix1_sort' => 1,
  'matrix2_name' => 'textblock',
  'matrix2_label' => 'Text',
  'matrix2_head' => '{matrix_label} [• {matrix_summary}]',
  'matrix2_fields' => [
    0 => 'text',
    1 => 'text_size',
    2 => 'collapse',
  ],
  'matrix2_sort' => 2,
  'familyFriendly' => 0,
  'repeaterCollapse' => 3,
  'repeaterLoading' => 1,
  'rememberOpen' => 1,
  'accordionMode' => 0,
  'loudControls' => 1,
  'addType' => 1,
  'imageDefs' => 'imageblock:
textblock:
miroembed:
videoembed:',
  'imageStyle' => 'margin:10px; width:200px;',
  'imageText' => 1,
  'allowChangeType' => 2,
  'collapsed' => 0,
  'required' => 1,
  'matrix3_name' => 'miroembed',
  'matrix3_label' => 'Miro Embed',
  'matrix3_head' => '{matrix_label} [• {matrix_summary}]',
  'matrix3_fields' => [
    0 => 'miro_embed',
    1 => 'aspect_ratio',
  ],
  'matrix3_sort' => 3,
  'matrix4_name' => 'videoembed',
  'matrix4_label' => 'Video Embed',
  'matrix4_head' => '{matrix_label} [• {matrix_summary}]',
  'matrix4_fields' => [
    0 => 'image',
    1 => 'video_embed',
  ],
  'matrix4_sort' => 4,
  'tags' => '',
  'matrixN_sort' => '',
  'matrixN_name' => '',
  'matrixN_label' => '',
  'matrixN_fields' => '',
  'matrixN_head' => '{matrix_label} [• {matrix_summary}]',
  'matrixN_import' => '',
  'repeaterDepth' => '',
  'repeaterAddLabel' => '',
  'repeaterMaxItems' => '',
  'repeaterMinItems' => '',
  'lazyParents' => '',
  'allowMatrixTypes' => '',
  'showIf' => '',
  'themeOffset' => '',
  'themeBorder' => '',
  'themeColor' => '',
  'columnWidth' => 100,
  'requiredIf' => '',
]

I'm trying to re-create this programmatically, like this:

$rm->setMatrixItems('blocks', [
	'imageblock' => [
		'label' => 'Image',
		'fields' => [
			'image',
			'aspect_ratio',
		]
	],
	'textblock' => [
		'label' => 'Text',
		'fields' => [
			'text',
			'text_size',
			'collapse'
		]
	],
	'videoembed' => [
		'label' => 'Video Embed',
		'fields' => [
			'image',
			'video_embed'
		]
	],
]);
/** Remove the miro-embed that was previously defined using the panel */
rm()->removeMatrixItem('blocks', 'miroembed');

The outcome:

CleanShot 2023-12-12 at 12 52 43@2x

All sub-fields are suddenly Title fields, and sometimes I even get an ominous field "Process", that seems to be something internal. The subfields (e.g. image, aspect_ratio, text, ...) are all defined in the database, but not yet using RockMigrations. Maybe related?

Provide migrations copy code for pages

I really appreciate the copy code available from the template and field edit views for this module! It is really helpful for getting started on setting up a migration. Unfortunately, it does not appear that this workflow is set up yet for Pages1. Can you point me in the right direction? Is this work that still needs to be done?

Error when removing field/s with ProcessWire's admin

When I am removing a field on a template in ProcessWire's admin, and RockMigrations is installed, I get an error:
ProcessWire: ProcessTemplate: Invalid value for $existingItem argument
image
The field is still present in the template afterwards.

I added this field by hand to the template just to try something out, then I wanted to remove it.

Normally if I try to remove a field a security question if I really want to delete this field appears, this doesn't happen with RockMigrations installed :(

I know that there are methods for adding or removing fields with RockMigrations, but the native method of adding or removing fields in the admin should not interfere.

migrateWatchFiles Out of Memory

Hello

Sorry I'm new to raising issues on GitHub so sorry if this isn't in the right format.

I've just upgraded my local dev site (PW 3.0.200) from 3.26.1 to 3.30.0 (also tried this on the intermediate releases)
Since 3.29.0 it now hangs on migrateWatchFiles() until PHP (8.1 Win x64) runs out of memory.

I use RockMigrations by setting up a directory to watch in ready.php

// Setup Rock Migrations watches
$rm = $this->wire->modules->get('RockMigrations');
$rm->watch($wire->config->paths->site . 'migrations');
$rm->migrateWatchFiles(true);

In that directory I have a PHP file for each feature area and edit each file as I'm developing. The idea being if I want to port the feature to another site I just copy the PHP file over to that site's migrations folder. It's been working pretty well up to now.

I've stripped out all my other site modules, templates and pages to see if this was a conflict and it's not helped.
I've not tried 3.30.0 in a fresh ProcessWire install because unfortunately I just don't have the time.

Is this something I was doing wrong that is now fixed...or something I'm doing ok that's now bugged? (!)

Cheers

Proile migrations from custom files result in error "ProcessModule: ___include: File is not in an allowed path"

Hi @BernhardBaumrock !

I am testing running profile migrations from site/assets/RockMigrations/profiles. The profile is shown in the dropdown and can be selected. But running it results in this error:

ProcessWire: ProcessModule: ___include: File is not in an allowed path: /XYZ/site/assets/RockMigrations/profiles/PROFILE.php

Maybe it would be better to place the profile folder somewhere under templates?

Adding a Repeater Matrix

I'm getting the following error when trying to add a Repeater Matrix via Rock Migrations:

ProcessWire: ProcessModule: Method RockMigrations::getRepeaterTemplate does not exist or is not callable in this context

DEBUG MODE BACKTRACE ($config->debug == true):
#0 /opt/norweb/norweb-2021/public/wire/core/Wire.php(420): ProcessWire\Wire->___callUnknown('getRepeaterTemp...', Array)
#1 /opt/norweb/norweb-2021/public/wire/core/WireHooks.php(951): ProcessWire\Wire->_callMethod('___callUnknown', Array)
#2 /opt/norweb/norweb-2021/public/wire/core/Wire.php(485): ProcessWire\WireHooks->runHooks(Object(ProcessWire\RockMigrations), 'callUnknown', Array)
#3 /opt/norweb/norweb-2021/public/wire/core/Wire.php(488): ProcessWire\Wire->__call('callUnknown', Array)
#4 /opt/norweb/norweb-2021/public/site/modules/RockMigrations/RockMigrations.module.php(2539): ProcessWire\Wire->__call('getRepeaterTemp...', Array)
#5 /opt/norweb/norweb-2021/public/site/modules/RockMigrations/RockMigrations.module.php(824): ProcessWire\RockMigrations->setFieldData(Object(ProcessWire\RepeaterMatrixField), Array)
#6 /opt/norweb/norweb-2021/src/PwMigration/NorwebMigration.php(112): ProcessWire\RockMigrations->createField('components', 'FieldtypeRepeat...', Array)
#7 /opt/norweb/norweb-2021/src/PwMigration/NorwebMigration.php(103): Nordita\Norweb\PwMigration\NorwebMigration->addFields(Array)
#8 /opt/norweb/norweb-2021/public/site/migrate.php(14): Nordita\Norweb\PwMigration\NorwebMigration->migrate(Object(ProcessWire\RockMigrations))
#9 /opt/norweb/norweb-2021/public/wire/core/TemplateFile.php(327): require('/opt/norweb/nor...')
#10 /opt/norweb/norweb-2021/public/wire/core/Wire.php(414): ProcessWire\TemplateFile->___render()

I'm using the same code that worked before with the previous version of the RockMigrations module.

How can I fix this?

Thank you

Creating a Repeater Matrix

Using RockMigrations 0.15.0.

If I create a repeater matrix field using the web client and then use the code shown in the "RockMigration Code" section of the field's PW admin page to create the field programmatically, I get the following error:

Notice

Trying to get property 'id' of non-object

File: .../site/modules/RockMigrations/RockMigrations.module.php:2508

2498:            // save trace of migration to field
2499:            // this is shown on field edit screen
2500:            $field->_rockmigrations_log = $this->getTraceLog();
2501:    
2502:            // prepare data array
2503:            bd($data);
2504:            foreach ($data as $key => $val) {
2505:    
2506:          // this makes it possible to set the template via name
2507:                if ($key === 'template_id') {
2508:                    $data[$key] = $this->templates->get($val)->id;
2509:                }
2510:    
2511:                // support repeater field array
2512:                $contexts = [];

Here is the code that I used and have in site/migrate.php:

$TAG = 'MyMigrations';

function init() {
    global $TAG;

    $rm = modules()->get('RockMigrations');
    $rm->deleteFields("tags=$TAG");
    $rm->createField('demo', 'repeaterMatrix', [
            'label'            => 'test',
            'flags'            => 0,
            'type'             => 'FieldtypeRepeaterMatrix',
            'template_id'      => 0,
            'parent_id'        => 0,
            'tags'             => $TAG,
            'matrixN_sort'     => '',
            'matrixN_name'     => '',
            'matrixN_label'    => '',
            'matrixN_fields'   => '',
            'matrixN_head'     => '{matrix_label} [• {matrix_summary}]',
            'matrixN_import'   => '',
            'repeaterFields'   => [],
            'repeaterDepth'    => '',
            'familyFriendly'   => 0,
            'repeaterAddLabel' => '',
            'repeaterCollapse' => 0,
            'repeaterLoading'  => 1,
            'rememberOpen'     => 0,
            'accordionMode'    => 0,
            'loudControls'     => 0,
            'repeaterMaxItems' => '',
            'repeaterMinItems' => '',
            'lazyParents'      => '',
            'addType'          => 0,
            'imageDefs'        => '',
            'imageStyle'       => 'margin:10px; width:200px;',
            'imageText'        => 1,
            'allowMatrixTypes' => '',
            'allowChangeType'  => 2,
            'collapsed'        => 0,
            'showIf'           => '',
            'themeOffset'      => '',
            'themeBorder'      => '',
            'themeColor'       => '',
            'columnWidth'      => 100,
            'required'         => '',
            'requiredIf'       => '',
            'fieldContexts'    => []
        ]);
}

init();

Wrong URL in logs

image

<a href="<a href=&quot;editor://open?file=C:/inetpub/wwwroot/site/modules/RockMigrations/RockMigrations.module.php&amp;line=2559&quot;>RockMigrations.module:2559</a>">&lt;a href="editor://open?file=C:/inetpub/ww…</a>

Looks odd to me. Shouldn't this be:

<a href="editor://open?file=C:/inetpub/wwwroot/site/modules/RockMigrations/RockMigrations.module.php&line=2559>Open in editor</a>

Argument in function createPage()

Hello, @BernhardBaumrock!

In function createPage() in RockMigrations.module.php:1076 there is an argument with strict typization: array $status. However, $status should be typized as int, since status should be integer.

Can you please fix it?

Usage of __DIR__ in $files->render() and symlinks

For various reasons, I have a directory that contains all the modules I use on my sites. I then symlink that directory to be /site/modules/ to the site I'm working on.

With RM, you have this line in RockMigrations.module.php, which won't work with my symlinked setup because of how PW only includes files in allowed paths.

'value' => $this->wire->files->render(__DIR__ . "/profileeditor.php", [

Could you possibly change it to this instead?

'value' => $this->wire->files->render($this->path . "profileeditor.php", [

watching dirs does not work

I created a "migrations" folder at the same level as site/migrate.php
image

in migrate.php I added
$rm->watch( __DIR__ . '/migrations/' , true, ['recurse' => true] );

but when I do a modules refresh, the migration of the files in the migrations folder is not executed, and the templates are still not created. The migrate.php is executed correctly.

I also added various debug statements in RockMigrations.php and even if I change a file in site/migrations/ it is not added to the getChangedFiles array.

my migrations/news_detail.php file looks like this:

<?php namespace ProcessWire;

$rm = $wire->modules->get("RockMigrations");
$rm->migrate([
  'templates' => [
    'news_detail' => [
      'label' => 'News',
      'fields' => ['title',  'images', 'published_date', 'seo'],
      'noParents' => 0,
      'noChildren' => 1, // only one
    ]
  ]
]);

So is this an error or am I doing things wrong?

"RockMigrations Code" breaks on "<" character in description, notes

Hi,
I've added some text in descriptions and notes, that is actual html tag and when RockMigrations markup for migration code is rendered in template edit page - it breaks on html "<" & ">" brackets (the rest of page is not being rendered after encountering such characters).
(Edit) Probably this happens only if it is within template context data. Tested inside default description field - it is rendered fine in migration code display.

I use a DynamicDescriptionNotes module that allows using HTML in notes and descriptions and I find it very useful. However it just turns off entity encoding to achieve this.

Would it be possible to take this into account on RockMigrations side?

For now I manually use "<" and ">" entities where I want to display these characters.

SCR-20240206-qpqi
SCR-20240206-qpsg

The culprit notes text:
SCR-20240206-qqeu

How to migrate a repeater field?

Hi there! I'm trying to migrate a repeater field (name: 'work'). The repeater has three repeater fields:

CleanShot 2023-12-14 at 10 00 12@2x

How would I define these sub fields in $rm->migrate()? The code snippet provided in the panel doesn't include any information about these:

'work' => [
  'label' => 'Work',
  'flags' => 0,
  'type' => 'FieldtypeRepeater',
  'template_id' => 0,
  'parent_id' => 0,
  'familyFriendly' => 0,
  'repeaterCollapse' => 3,
  'repeaterLoading' => 1,
  'rememberOpen' => 1,
  'accordionMode' => 0,
  'loudControls' => 0,
  'repeaterMinItems' => 1,
  'required' => 1,
  'collapsed' => 0,
  'tags' => '',
  'repeaterTitle' => '',
  'repeaterDepth' => '',
  'repeaterAddLabel' => '',
  'repeaterMaxItems' => '',
  'lazyParents' => '',
  'showIf' => '',
  'themeOffset' => '',
  'themeBorder' => '',
  'themeColor' => '',
  'columnWidth' => 100,
  'requiredIf' => '',
]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.