Search by

therealworld / clirun-plugin

therealworld

a script for oxid6 update preparations.

Package info

bitbucket.org/therealworld/clirun-plugin

Homepage

Issues

Type:oxideshop-component

pkg:composer/therealworld/clirun-plugin

Statistics

Installs: 1 561

Dependents: 0

Suggesters: 0


README

Deutsche Fassung: README.de.md

vendor-logo the-real-world.de

description

New oe-console commands

  • trw:allmodules:active [--env=XXXX] [--shop-id=1] (short: t:a:a)
  • trw:allmodules:deactive [--env=XXXX] [--shop-id=1] (short: t:a:d)
  • trw:allmodules:install [--env=XXXX] (short: t:a:i)
  • trw:clear:cache (short: t:cl:c)
  • trw:clear:phantomimages [--dry-run] [--force] (short: t:cl:p)
  • trw:config:export [--env=XXXX] [--shop-id=1] (short: t:co:e)
  • trw:config:import [--env=XXXX] [--shop-id=1] (short: t:co:i)
  • trw:db:charset [--apply] [--charset=utf8mb3|utf8mb4] [--allow-downgrade] [--table=XXXX] [--exclude=t.col,...] (short: t:d:c)
  • trw:db:decode-legacy [--key=XXXX] [--dry-run] [--no-schema] [--force] (short: t:d:d)
  • trw:db:export [--yaml=XXXX] (short: t:d:e)
  • trw:db:keycollation [--apply] [--schema-only] [--table=XXXX] [--exclude=t.col,...] (short: t:d:k)
  • trw:db:import [--yaml=XXXX] (short: t:d:i)
  • trw:db:migrate [migration-command] [versions] [--project=XXXX] [--edition=XXXX] [--dry-run] [--up] [--down] [--auto-sync] [--strict-migrations] (short: t:d:m)
  • trw:generate:yaml:config [--env=XXXX] [--shop-id=1] (short: t:g:y:c)
  • trw:ide:helper [--shop-id=1] (short: t:i:h)
  • trw:module:migrate module-id [--down] (short: t:m:m)
  • trw:module:refresh module-id [--uninstall] [--shop-id=1] (short: t:m:r)
  • trw:module:setup module|path [--develop] [--no-takecare] [--shop-id=1] [--env=XXXX] (short: t:m:s)
  • trw:module:wipeout module-id [--shop-id=1] [--env=XXXX] [--keep-migrations] [--force] (short: t:m:w)
  • trw:update:after [--env=XXXX] [--shop-id=1] (short: t:u:a)
  • trw:update:before [--env=XXXX] [--shop-id=1] (short: t:u:b)
  • trw:update:views (short: t:u:v)

The short forms are Symfony's built-in command abbreviations: each colon segment is shortened to the smallest prefix that is still unambiguous. Because clear/config collide on c (and would be ambiguous), their second segment needs two letters (t:cl:… / t:co:…). The first segment t resolves to trw as long as no other command namespace starts with t.

trw:clear:cache and trw:clear:phantomimages share the same namespace, so their last segment needs a letter of its own as well: t:cl:c and t:cl:p.

All-Module actions (deactivate, activate, install)

The "All-Modules" Activate Commands set the Shop in Maintenance Mode

All-Module active (trw:allmodules:active)

  • activate all Modules in a certain order
  • option --env=XXXX:
    • get the Plugin-Config from file trwclirun/XXXX.1.yaml
  • option --shop-id=YYYY:
    • get the Plugin-Config from file trwclirun/XXXX.YYYY.yaml or trwclirun/YYYY.yaml
    • activate the Modules in Shop with this ID

All-Module deactive (trw:allmodules:deactive)

  • deactivate all Modules
  • option --env=XXXX:
    • get the Plugin-Config from file trwclirun/XXXX.1.yaml
  • option --shop-id=YYYY:
    • get the Plugin-Config from file trwclirun/XXXX.YYYY.yaml or trwclirun/YYYY.yaml
    • deactivate the Modules in Shop with this ID
    • if not set, the command check if Plugin-Configs exists for all Shop-Ids

All-Module install (trw:allmodules:install)

  • deactivate all Modules
  • option --env=XXXX:
    • get the Plugin-Config from file trwclirun/XXXX.1.yaml

Clear-Commands

clean Cache (trw:clear:cache)

  • Clean OXID cache

clean phantom product images (trw:clear:phantomimages)

Removes product images that are invisible in the admin while the frontend renders a broken picture. Two flavours are detected:

  • broken: the file exists on disk but carries no image data (a 0-byte download, a stored html error page)
  • missing: an article references a picture file that does not exist at all

The matching oxpic field is cleared and the generated derivatives are dropped, so the article falls back to "no picture".

  • option --dry-run:
    • only report what was found, change nothing
  • option --force:
    • clear references to missing files even when the picture folder looks out of sync
    • without it, a folder that holds none of its referenced pictures aborts the run: that is the signature of a picture folder that was not deployed, not of missing images, and clearing every reference would destroy the assignments

Cache warmup

warm up the caches (trw:cache:warmup)

Builds the caches the shop would otherwise build while answering its first requests, so the first visitor after a deployment does not pay for all of them.

Two stages that share nothing but their purpose. --stage picks one, the default is both.

Stage "local" — compiled templates, template chain, language cache

Runs in this process, no network involved. Worth doing because the shop runs with iDebug = 0, which switches twig's auto_reload off: the compile cache never expires by itself, so its cost is paid exactly once after every trw:clear:cache — by whoever visits first, unless this ran before them.

Measured on a mid-sized shop, first page after clearing the cache:

first page loadtemplates compiled while answering
without warmup4.67 s87
with warmup0.94 s18

The 18 that remain are templates included under a computed name, which cannot be found without rendering the page.

The stage restarts itself in a subprocess whose working directory is source/. That is not cosmetic: twig builds the NAME of each compiled file from the template path relative to getcwd(). Started from the shop root it would write a complete second set of cache files that the shop never reads — silently, because nothing breaks, the shop is just as slow as before. A preflight check therefore compares what this process would write against the files already on disk and refuses to run when none of them match (--force overrides).

Backend templates are reported separately and not compiled: this process runs in frontend mode, so their parent templates are not loadable here. Warming the backend needs its own process and is not implemented yet.

Stage "pages" — the full page cache

Requests the shop's own urls over http, which is the only way a full page cache can be filled at all: it is written from inside the output pipeline while a response is rendered. Everything below it — compiled templates, template chain, seo lookups, opcache — gets warm on the way.

Urls come from oxseo, the live routing table, not from a sitemap. A sitemap answers "what should a search engine index", which is a different question: cms pages are opt-in there (OXISSITEMAP defaults to 0 for oxcontents), so a sitemap driven warmup would skip the terms of service, the shipping information and every other page visitors actually open. Where the seo module is installed, its sitemap table still contributes the ORDER, so the pages that matter are warm first if the run is cut short.

Already cached urls are skipped without requesting them, which makes a long run resumable — an interrupted crawl picks up where it stopped. That works through a contract in the tools plugin, so this command knows nothing about which page cache module is installed; without one it simply requests everything, which is slower and never wrong.

Options

  • --stage=local|pages|all
    • default all
  • --base-url=<url>
    • the address to request. The default is the shop url from the configuration, and the command prints it before it starts. That address is meant for browsers; this command runs ON the server, where the same host often does not resolve — behind a container boundary, a load balancer, or a name that only exists in public dns. The base url is requested once up front, and an unreachable shop ends the run with one sentence instead of one connection error per url.
  • --shop-id=<id>
  • --types=<a,b>
    • page stage only: limit to these oxseo types (oxarticle, oxcategory, oxcontent, oxmanufacturer, oxvendor, static, plus whatever modules register)
  • --include-inactive
    • do not check the object behind an seo row for its active flag
  • --only=<fragment>
    • local stage only: just the templates whose name contains this
  • --no-skip
    • request urls even when the page cache already holds them
  • --dry-run
    • show the plan and change nothing
  • --force
    • skip the confirmation, and run the local stage even when the preflight objects
  • --limit=<n> / --max-time=<seconds>
    • stop after this many items / seconds; combined with the skip above, a nightly run can simply continue where yesterday's stopped
  • --sleep=<ms> / --max-load=<load>
    • pace the run: pause after each item / while the one minute load average is above this. Throttling time does not count against --max-time
  • --timeout=<seconds>
    • http timeout per request, default 60
  • --min-free=<size>
    • stop when the page cache volume drops below this, default 1G. Accepts 2G, 500M, 5% or plain bytes
  • --progress=<n> / --samples=<n>
    • progress line every n items (0 = off), and how many failures to list at the end

Examples

# after a deployment: templates only, nothing over the network
vendor/bin/oe-console trw:cache:warmup --stage=local

# see what would be requested, and against which address
vendor/bin/oe-console trw:cache:warmup --stage=pages --dry-run

# nightly, gentle, resumable
vendor/bin/oe-console trw:cache:warmup --base-url=https://127.0.0.1/shop \
    --force --sleep=200 --max-load=4 --max-time=3600

Exit code is 1 when anything failed — an unreachable shop, a template that does not compile, a url that answered with something other than 200.

config im- and export commands

config export (trw:config:export)

  • export the values of Modules, Themes, Shop and ShopTable configs into a transfer YAML — purpose: hand the values over to another shop (e.g. an OXID-6 → OXID-7 migration) without dragging structural module wiring along
  • what is included per module: id + moduleSettings
  • what is stripped before writing the transfer YAML, so the target system's own metadata.php / shops/{id}/modules/*.yaml stay authoritative:
    • classExtensions, controllers, events
    • templates, templateBlocks, smartyPluginDirectories
    • the merged top-level moduleChains block
  • themes, shopconfig and shoptable are exported as values-only by design
  • option --env=XXXX:
    • get the Plugin-Config from file trwclirun/XXXX.1.yaml
  • option --shop-id=YYYY:
    • get the Plugin-Config from file trwclirun/XXXX.YYYY.yaml or trwclirun/YYYY.yaml
    • export the Config from Shop with this ID
    • if not set, the command check if Plugin-Configs exists for all Shop-Ids

config import (trw:config:import)

  • import the Modules-, Themes-, Shop- and ShopTableConfigs from the transfer YAML
  • whitelist protection: every incoming variable is checked against what the target shop actually declares. Unknown modules / themes / variables are skipped with a <comment> warning instead of being silently written. Source of truth per section:
    • modules: per-module YAMLs under var/configuration/shops/{id}/modules/*.yaml (the modules must therefore be installed/activated in the target shop before the import runs)
    • themes: oxconfig rows where OXMODULE = 'theme:{themeId}'
    • shopconfig: oxconfig rows where OXMODULE = ''
    • shoptable: declared columns of the oxshops table
  • option --env=XXXX:
    • get the Plugin-Config from file trwclirun/XXXX.1.yaml
  • option --shop-id=YYYY:
    • get the Plugin-Config from file trwclirun/XXXX.YYYY.yaml or trwclirun/YYYY.yaml
    • import the Config from Shop with this ID
    • if not set, the command check if Plugin-Configs exists for all Shop-Ids

DB im- and export commands

DB decode legacy (trw:db:decode-legacy)

One-time OXID 6 → OXID 7 migration command.

In OXID 6 the columns oxconfig.OXVARVALUE and oxuserpayments.OXVALUE were encrypted via the MySQL ENCODE() function and decrypted on the fly with DECODE(). OXID 7 expects plaintext. The standard migration path uses an SQL-side DECODE() step, which only works on databases that still ship the function — i.e. MySQL ≤ 5.7 and MariaDB ≤ 11.1. On MySQL ≥ 8.0 and MariaDB ≥ 11.2 the function has been removed.

This command performs the same migration in PHP, using a port of MySQL's sql_crypt class. It is meant to be run exactly once per shop, after importing the OXID-6 dump 1:1 into the new database and before any OXID-7 boot (in particular before trw:update:after).

What it does

For each affected table (oxconfig, oxuserpayments):

  1. Walk every row and decrypt the cipher value in PHP while the column is still BLOB. Rows that already look like plaintext are left untouched, so the command is idempotent — safe to re-run after a partial first run. Decoded plaintext is written back into the still-BLOB column.
  2. Only after the row-level decode has finished: migrate the value column from BLOB to TEXT, carrying over its NOT NULL flag and column comment.

The table charset and collation are left alone. Charset and collation are set on the value column only, and default to the table's own — so the result is identical to what a bare MODIFY ... TEXT would produce. The one exception is a table whose default charset is single-byte (e.g. latin1): since BLOB → TEXT reinterprets the stored bytes rather than converting them, and the decoded plaintext is UTF-8, that column alone is pinned to utf8mb4_general_ci and the command says so on stdout.

An earlier version issued ALTER TABLE … CONVERT TO CHARACTER SET utf8mb4 on the whole table. That was wrong: OXID declares the neighbouring id columns as latin1_general_ci on purpose (Setup/Sql/database_schema.sqloxconfig.OXID, OXMODULE, OXVARNAME, OXVARTYPE, oxuserpayments.OXID, OXUSERID, OXPAYMENTSID). Converting them costs index usage on every join against oxuser / oxpayments / oxorder, inflates those indexes from 32 to 128 bytes per char(32) entry, and is flagged as a schema deviation by the shop's system health check. Shops that ran the old version can be put right with the two charset commands instead of hand-written DDL, and both report before they change anything:

  • the id columns: trw:db:keycollation --schema-only — it reads the declarations out of database_schema.sql, so it repairs exactly those and leaves the columns OXID means to follow the table charset alone
  • the value columns left on utf8mb4 while the rest of the database is utf8mb3: trw:db:charset --allow-downgrade — the tell-tale sign is a default run reporting skipped … already utf8mb4, would be a downgrade. Both columns carry the decoded or re-encrypted payload, so take an export of the two tables first; the command's own content check refuses any column holding a character the target cannot store.

The decode-before-DDL ordering is critical: running MODIFY ... TEXT first would coerce the binary cipher bytes through the target column charset, and with sql_mode = '' MySQL silently truncates / replaces invalid UTF-8 sequences — destroying the ciphertext before the decoder ever sees it. The same hazard applies to OXID's own migration Version20180228160418, which flips oxconfig.OXVARVALUE to TEXT, so run this command before oe:migration:migrate. (oxuserpayments.OXVALUE is not covered by any OXID migration at all — that column relies on this command.)

Options

  • --key=XXXX:
    • Configuration key (corresponds to $this->sConfigKey from the old OXID-6 config.inc.php)
    • Default: the OXID stock key (fq45QS09_fqyx09239QQ)
    • Applies to oxconfig only — oxuserpayments uses a separate derived key (str_rot13() of the OXID stock key, i.e. sd45DF09_sdlk09239DD) that OXID-6's UserPayment::__construct() builds at runtime. The command applies that derivation automatically, no flag needed.
  • --dry-run:
    • Report what would be changed without writing
    • Note: dry-run reports the decode pass only; it does not exercise the schema-DDL path. A real run is the only way to verify schema migration.
  • --no-schema:
    • Skip the BLOB → TEXT and charset DDL — only run the row-level decode
  • --force or -f:
    • Skip the safety confirmation prompt

Recommended workflow

# 1. dump the OXID-6 source database 1:1 (cipher columns left untouched)
mysqldump -h <old-host> -u <user> -p <db> > oxid6.sql

# 2. import into the new MariaDB ≥ 11.2 / MySQL ≥ 8.0 instance
mysql -h <new-host> -u <user> -p <db> < oxid6.sql

# 3. install the OXID-7 project on top of the imported database
composer install

# 4. preview
vendor/bin/oe-console trw:db:decode-legacy --dry-run

# 5. real run
vendor/bin/oe-console trw:db:decode-legacy [--key=<sConfigKey>]

# 6. continue with the regular OXID-7 update sequence
vendor/bin/oe-console trw:update:after

The command uses a direct PDO connection built from source/config.inc.php. It does not boot the OXID Registry/Config stack, so the unserialize() warnings caused by reading still-encrypted oxconfig rows during a regular bootstrap do not occur.

DB export (trw:db:export)

  • export the DB to an sql-file
  • it is possible to export all or only certain tables. Furthermore, sensitive data can be anonymized during export
  • option --yaml=XXXX:
    • get the Export-Options from a yaml-file
    • If the configuration file is not provided, then a sample file is placed here: var/trwcliexportimport/example.yaml

DB import (trw:db:import)

  • import the DB from an sql-file
  • option --yaml=XXXX:
    • get the Export-Options from a yaml-file
    • If the configuration file is not provided, then a sample file is placed here: var/trwcliexportimport/example.yaml

DB migrate (trw:db:migrate)

Wrapper for OXID Doctrine Migrations (oe-eshop-db_migrate) integrated into oe-console with enhanced features.

Available Commands

  • status - Show the status of all migrations
  • migrate - Execute all pending migrations
  • execute - Execute a single migration version
  • generate - Generate a new migration class
  • sync-metadata-storage - Synchronize the metadata storage table
  • version - Manually add/delete migration versions
  • up-to-date - Check if the database is up to date
  • list - List all available migration commands

Options

  • --project=XXXX or -p XXXX:
    • Specify the migration project (ce, pe, ee, or module-id)
    • Automatically builds the full namespace for the migration
    • Examples: -p ce, -p yourmoduleid
  • --edition=XXXX:
    • The shop edition (CE, PE, EE) — usually not needed, it is derived from the installation
  • --auto-sync:
    • Automatically sync metadata storage if out of date
    • Useful for development environments
  • --dry-run:
    • Execute the migration as a dry run (for migrate command)
  • --up:
    • Execute the migration up (for execute command)
  • --down:
    • Execute the migration down (for execute command)
  • --strict-migrations:
    • Opt out of the default empty-suite handling and let Doctrine fail when a migration suite is configured but has no migration files
    • By default, the migrate command forwards Doctrine's --allow-no-migration flag so that empty suites (typically the project suite when no project migrations exist) are skipped with a warning instead of aborting the run — which would otherwise prevent any subsequent module suites from being processed

Examples

Check migration status (all projects):

vendor/bin/oe-console trw:db:migrate status

Run all pending migrations:

vendor/bin/oe-console trw:db:migrate migrate

Dry-run migrations:

vendor/bin/oe-console trw:db:migrate migrate --dry-run

Sync metadata storage (fixes "not up to date" errors):

vendor/bin/oe-console trw:db:migrate sync-metadata-storage

Execute specific migration with full namespace:

vendor/bin/oe-console trw:db:migrate execute "Your\Module\Namespace\Version20221026214950" --up

Execute specific migration with project shortcut:

vendor/bin/oe-console trw:db:migrate execute 20221026214950 --project yourmoduleid --up
vendor/bin/oe-console trw:db:migrate execute Version20170718124421 -p ce --down

Auto-fix metadata storage issues:

vendor/bin/oe-console trw:db:migrate migrate --auto-sync

Fail on empty migration suites (opt-out of the default "skip empty"):

vendor/bin/oe-console trw:db:migrate migrate --strict-migrations

Supported Project Shortcuts

  • ce - OXID Shop Community Edition
  • pe - OXID Shop Professional Edition
  • ee - OXID Shop Enterprise Edition
  • yourmoduleid - The migration of your module (uses module-id as namespace)
  • [custom] - Use full namespace for other modules

Note

OXID uses separate migration tables for each project/module:

  • oxmigrations_ce (Shop Core)
  • oxmigrations_project (Project)
  • oxmigrations_[module] (Each module)

This command is equivalent to calling vendor/bin/oe-eshop-db_migrate directly, but integrated into the oe-console for better discoverability and enhanced error handling.

Empty Migration Suites

The OXID migration wrapper runs Doctrine's migrations:migrate once per suite (ce, project, and every module). If a suite is configured (e.g. via source/migration/project_migrations.yml) but has no Version*.php files, Doctrine aborts with a non-zero exit code, which makes the wrapper stop and skip all subsequent module suites.

To avoid this, trw:db:migrate migrate forwards Doctrine's --allow-no-migration flag by default. Empty suites are then reported as a warning and the run continues with the next suite. Pass --strict-migrations to restore the default Doctrine behavior.

exportimport yaml example

YAML example:

dumpFileName: dump.sql
onlyTables: {  }
anonymizeRowsInTables:
  oxuser:
    - oxfname
    - oxlname
  oxorder:
    - oxbillfname
    - oxbilllname
    - oxdelfname
    - oxdellname

DB charset and collation

Two commands for the character set of the database, one per direction. Both report by default and change nothing without --apply — an ALTER across the tables of a live shop is not something to trigger by forgetting a flag.

Neither is a migration, on purpose: the character set of a table is a property of the installation, not of a module's schema. A migration runs once and is then marked done forever, so it can neither react to a database that gains utf8mb4 later nor repair a table that already existed when it first ran — which is exactly how a single latin1 table can survive every migration written for it. These commands have no memory: they look at the database as it is now and can be run again after every upgrade.

DB charset (trw:db:charset)

Lifts the character set of the whole database to what the installation can actually carry, and reports what stands in the way where it cannot. Two different situations end up here:

  • drift — a table sits below the level the rest of the database is on, usually because it was created long ago by something that named no charset and has been carried from dump to dump ever since. A default run finds exactly this case: the target is what the installation already carries, so anything the run lists is a table that is behind.
  • the ceiling — everything is as declared and the whole database could go one step higher. That is --charset=utf8mb4, and it is a decision, not a repair.

The ceiling is the connection, not the tables. MySQL converts between the connection charset and the column charset on every read and write, so a utf8mb4 column behind a utf8mb3 connection still receives ? instead of an emoji. dbCharset in source/config.inc.php decides this and is left to the operator — the command reports the mismatch and says what to set.

Held back in every direction:

  • latin1_general_ci — OXID spells every char(32) id column this way, in core and module tables alike. They hold hex ids, and converting them would widen every primary and foreign key index for nothing.
  • latin1_binoxseo.OXSEOURL. Byte-exact matching is the point of that column.
  • columns that look like an id (type char(32), or a name ending in ID) but are not on latin1_general_ci. Those are reported rather than skipped silently, naming which rule took hold: a column that really is an id belongs on latin1_general_ci, and the place to put it there is the migration of the module that created it.
  • generated columns — information_schema does not hand back the expression in a form a MODIFY could repeat.

Before it writes anything the run estimates the index widths for the target charset and reports the tables where a key would pass the engine's limit (1000 bytes on MyISAM, 3072 on InnoDB with DYNAMIC row format, 767 with COMPACT). Those tables are skipped instead of taking the run down halfway through, and the ALTERs are issued one table at a time so a failure leaves the others alone. Afterwards the shop views are regenerated, because the oxv_* views repeat the column types of their base tables.

  • option --apply:
    • execute the conversion; without it the command only reports
  • option --charset=utf8mb3|utf8mb4:
    • target charset; default is the highest one the connection carries
    • latin1 is not a reachable target — going further down is trw:db:keycollation
  • option --allow-downgrade:
    • also pull columns that sit above the target down to it
    • for the one case that needs it: a shop where something once followed what the server could do instead of what the installation uses, leaving single columns above everything else
    • it cannot overshoot — the target is one value for the whole run, taken from the connection, and only utf8mb3 and utf8mb4 are valid targets
    • and never at the cost of content: every candidate is round-tripped through the target charset in the database and compared byte for byte first, and a single row that would come back different leaves that column where it is
  • option --table=XXXX:
    • limit the run to a single table
  • option --exclude=table.column,...:
    • hold single columns back, comma separated
# what is behind? (reports only)
vendor/bin/oe-console t:d:c

# raise the whole database one step - check the report first
vendor/bin/oe-console t:d:c --charset=utf8mb4
vendor/bin/oe-console t:d:c --charset=utf8mb4 --apply

# clean up single columns left above the rest by an earlier tool
vendor/bin/oe-console t:d:c --allow-downgrade
vendor/bin/oe-console t:d:c --allow-downgrade --apply

DB key collation (trw:db:keycollation)

Puts id columns back on latin1_general_ci where they drifted off it — the counterpart to trw:db:charset, and the same defect seen from the other side. A module table created by an onActivate() event in the OXID 6 days and then carried into OXID 7 by a database dump keeps whatever the server default was back then. The migration written for it later guards its CREATE with hasTable(), so it counts as executed without ever having touched the table, and the schema in the database quietly differs from the schema the module declares.

Going down from utf8mb3 to latin1 is the one direction that can lose data, so it is done far more carefully than the way up:

  • which columns must be latin1 is read out of OXID's own database_schema.sql, not guessed. That file declares character set latin1 collate latin1_general_ci on 164 columns and deliberately leaves it off others — oxuser.OXUSTID, oxorder.OXTRANSID, oxorderarticles.OXWRAPID and the affiliate ids on oxshops are meant to follow the table charset. A command that pulled every column named …ID down to latin1 would break exactly those. A column the core schema knows and does not declare latin1 is never touched.
  • for everything the core schema does not know — module tables, and module columns added to core tables — the shape rules apply: type char(32), or a name ending in ID. Those are a convention, so they are reported under their own reason and are meant to be read before --apply, not after.
  • no column is converted before its content has been proven to survive. Every candidate is round-tripped through latin1 in the database and compared byte for byte; one row that would come back different blocks that column. An id holds hex, so this passes — but it is what separates a safe downgrade from a silent one.

Repairing the database is only half of it: where a module's own migration declares the column wrongly, a fresh install recreates the drift. Those belong in the module, and the report names them.

  • option --apply:
    • execute the conversion; without it the command only reports
  • option --schema-only:
    • only convert what database_schema.sql declares and ignore the shape rules
    • the risk-free way in, and the recommended first run
  • option --table=XXXX:
    • limit the run to a single table
  • option --exclude=table.column,...:
    • hold single columns back, comma separated
# full report, both rules
vendor/bin/oe-console t:d:k

# only what OXID itself declares
vendor/bin/oe-console t:d:k --schema-only
vendor/bin/oe-console t:d:k --schema-only --apply

configuration commands

configuration (trw:generate:yaml:config)

  • create a configfile via oe-console-command: oe-console trw:generate:yaml:config Example: 1.yaml.dist YAML example:
    moduleTakeCare:
    - yourmodule1
    

moduleTakeCareDevelop:

  • yourmodule2

themeTakeCare:

  • apex

dontRunIfFileExits:

  • dummyfile1.txt

runIfFileExits:

  • dummyfile2.txt

dontRunIfOptionValue: bDemoOption1: true bDemoOption2: false bDemoOption3: abc bDemoOption4: 1

runIfOptionValue: bDemoOption5: true bDemoOption6: false bDemoOption7: abc bDemoOption8: 1

runIfEnvironmentVariable: DEV_ENVIRONMENT1: true DEV_ENVIRONMENT2: false DEV_ENVIRONMENT3: abc DEV_ENVIRONMENT4: 1

prepareShopForUpdate: false

configExportImportPath: transfer

configExportNotAllowedVars:

  • bOptionNotAllowed1
  • bOptionNotAllowed2

configImportNotAllowedVars:

  • bOptionNotAllowed1
  • bOptionNotAllowed2 ...
    
    
  • option --env=XXXX: write the Plugin-Config in file trwclirun/XXXX.1.yaml
  • option --shop-id=YYYY:

    • write the Plugin-Config in file trwclirun/XXXX.YYYY.yaml or trwclirun/YYYY.yaml
    • if not set, the command write the Plugin-Configs for all Shop-Ids
  • moduleTakeCare: (necessary for command trw:update:before, trw:allmodules:active and trw:allmodules:deactive)

    • List of ModuleIds for deletetion and activation, before and after update commands
    • The sorting ensures the order of activation
  • moduleTakeCareDevelop: (necessary for command trw:update:before and trw:allmodules:deactive)

    • List of ModuleIds for deletetion and deactivation, before update commands
  • themeTakeCare: (necessary for command trw:update:before)

    • List of Themes, that will be deleted before update commands
    • the OXID-Shop-installer will create the themes again
  • prepareShopForUpdate: (necessary for command trw:update:before)

    • prepare the shop, so that the install-routine from OXID starts during "composer install"
    • please be careful, start it only if the standard OXID routines of "composer install" start after executing the command
    • the OXID-Shop-installer will create the themes again
  • dontRunIfFileExits: (necessary for command trw:update:before and trw:update:after)

    • dont run this commands if file exists
    • its a possibility to stop automatic updates
  • runIfFileExits: (necessary for command trw:update:before and trw:update:after)

    • run this commands only if file exists
    • its a possibility to stop automatic updates
  • dontRunIfOptionValue: (necessary for command trw:update:before and trw:update:after)

    • dont run this commands if an shop-config-value exists and active
    • its a possibility to stop automatic updates
  • runIfOptionValue: (necessary for command trw:update:before and trw:update:after)

    • run this commands only if if an shop-config-value exists and active
    • its a possibility to stop automatic updates
  • runIfEnvironmentVariable: (necessary for command trw:update:before and trw:update:after)

    • run this commands only if if an ENVIRONMENT-VARIABLE exists
    • its a possibility to stop automatic updates
  • configExportImportPath: (necessary for command trw:config:export and trw:config:import)

    • The path in which the config export is saved
    • relative to root/var/configuration
  • configExportNotAllowedVars: (necessary for command trw:config:export and trw:config:import)

    • Dont export this config-vars
  • configImportNotAllowedVars: (necessary for command trw:config:export and trw:config:import)

    • Dont import this config-vars

Create IDE-Helper file (trw:ide:helper)

  • option --shop-id=YYYY:
    • the id of the shop
    • if not set, the create the helper-files for all Shop-Ids
  • creates a helper file for the modules currently installed in the shop so that IDEs such as phpStorm can find the class chains and thus code completion is possible
  • it does not matter whether the module is active or not. what is important is whether it is installed for the shop
  • the file is stored in the root directory and has the name ".ide-helper_modules_1.php", for example. The 1 stands for the shop ID
  • the file(s) are parallel to the ".ide-helper.php" which is created via "vendor/bin/oe-eshop-ide_helper"
  • if no shop ID is provided optionally, the file for the standard shop is created with the ID 1

Module Refresh (trw:module:refresh)

  • argument module-id:
    • the id of the module — required, given as an argument, not as an option
  • option --uninstall:
    • If set, the module will be deactivated and uninstalled during the refresh. The default is to simply (re-)install the module and (re-)activate it.
  • option --shop-id=YYYY:
    • the id of the shop
    • if not set, the command refresh the Module for all Shop-Ids
  • helper-command for developers
  • deactivate, install and activate a module in one step
  • The command observe an existing module chain and deactivates and activates all dependent modules in the process

Module Migrate (trw:module:migrate)

  • short form: t:m:m
  • argument module-id: the module whose Doctrine suite to migrate
  • option --down: roll the suite back to zero (full down() teardown) and drop the suite's metadata table; without it the suite is migrated up to the latest version
  • scoped to the single module suite (via the edition selector)
  • used internally by trw:module:setup / trw:module:wipeout as their migration step, and usable standalone

Xdebug shutdown-segfault handling

On builds with an active Xdebug (xdebug.mode including debug/profile), the PHP process segfaults at shutdown after a migration has actually executed DDL — the migration itself succeeds and the database stays consistent, but the process exit code becomes 139, which breaks CI checks and command chaining. (A no-op migration — "already at latest" — does not trigger it.)

To keep a clean exit code, the migration is transparently run in a subprocess started with XDEBUG_MODE=off whenever Xdebug is loaded and active. This applies to t:m:m, t:m:s and t:m:w alike. On servers without Xdebug (typically production) the migration runs in-process — no subprocess, no overhead; the XDEBUG_MODE variable is meaningless there and never set. The recursion into the subprocess is guarded by XDEBUG_MODE=off, so the subprocess runs the migration in-process itself.

Module Setup (trw:module:setup)

  • short form: t:m:s
  • the counterpart to trw:module:wipeout — brings a module fully into the shop
  • argument module: two ways to address the module
    • path way (works for a module installed anywhere on the server, as OXID allows): pass the path to the module directory or directly to its metadata.php. The module id is read from the metadata (the file is included, so an id defined via a class constant like 'id' => Module::MODULE_ID resolves through the autoloader)
    • id way (only for modules under vendor/, i.e. previously pulled in via composer and therefore part of composer.lock, or modules already installed in the shop): pass the module id. It is resolved from the installed configuration, or by scanning the composer oxideshop-module packages in composer.lock. A fresh module living outside vendor/ cannot be found by id — use the path way for it
  • option --develop: register the module in moduleTakeCareDevelop instead of moduleTakeCare
  • option --no-takecare: do not register the module in the trwclirun config at all
  • option --shop-id=YYYY: the shop id; if not set, all shop ids (in CE: shop 1)
  • option --env=XXXX: environment used to locate the trwclirun config file

Steps, in this order:

  1. install the module files/configuration (oe:module:install, idempotent)
  2. migrate up to the latest version (schema build, via trw:module:migrate) — deliberately before activation, because a fresh module whose onActivate touches its own tables would otherwise fail (the tables only exist after the migration). Scoped to the module suite; a no-op for modules without a migration/migrations.yml. Xdebug-safe (runs in a clean subprocess when Xdebug is active — see Module Migrate above)
  3. activate the module in the targeted shop(s)
  4. clear the cache (via trw:clear:cache)
  5. update the views (via trw:update:views)
  6. register the module id in var/trwclirun/<shop-id>.yamlmoduleTakeCare by default, moduleTakeCareDevelop with --develop, or skipped with --no-takecare. The id is kept in exactly one of the two lists (removed from the other if present)

Module Wipeout (trw:module:wipeout)

  • short form: t:m:w
  • argument module-id: the id of the module to remove (required)
  • option --shop-id=YYYY:
    • the id of the shop
    • if not set, the module is wiped out for all shop ids (in CE: shop 1)
  • option --env=XXXX:
    • environment used to locate the trwclirun config file to clean up
  • option --keep-migrations:
    • do not roll back the module migrations — the module schema/data stays in place
    • default (without the flag) is a full rollback to version 0, i.e. every down() runs
  • option --force (-f):
    • skip the safety confirmation prompt

Completely removes a module from the shop setup, in this order:

  1. deactivate the module — and, first, any modules that depend on it (dependency chain, like trw:module:refresh --uninstall); dependents are left inactive and reported at the end
  2. roll back migrations to version 0 (schema teardown via down()) — done while the module is still installed so its migration suite is still discoverable. Scoped to the module suite only. After a successful rollback the module's Doctrine metadata table (table_storage.table_name from its migration/migrations.yml, e.g. oxmigrations_trwblockforge) is dropped too, so no trace is left behind. The shared shop-edition logs (oxmigrations_ce etc.) are never touched. Legacy flat-layout migrations (migration/Version*.php without migration/migrations.yml) cannot be isolated and are reported for manual handling. Xdebug-safe (runs in a clean subprocess when Xdebug is active — see Module Migrate below)
  3. uninstall the module (oe:module:uninstall)
  4. clear the cache (via trw:clear:cache)
  5. update the views (via trw:update:views)
  6. remove the module id from moduleTakeCare / moduleTakeCareDevelop in var/trwclirun/<shop-id>.yaml
  7. composer hints: when the module lives under vendor/, print best-effort follow-up hints — the composer remove <vendor/package> line, the authoritative provenance from composer.lock (source.url + reference and dist.url, i.e. where composer actually resolved the package from), and any matching repositories entry from the root composer.json (matched via the package short name — note the lock source url and the repository url can differ). The composer package itself and its files under vendor/ are not touched automatically, since that is a project-composer decision.

Destructive. The default migration rollback drops the module's tables/columns and their data. Take a database backup first; the command asks for confirmation unless --force is given.

shopupdate-commands

The shopupdate-commands are intended to speed up the shop composer update process. The following commands can be executed before and after the shop update:

after Update (trw:update:after)

  • option --env=XXXX: get the Plugin-Config from file trwclirun/XXXX.1.yaml
  • option --shop-id=YYYY:
    • get the Plugin-Config from file trwclirun/XXXX.YYYY.yaml or trwclirun/YYYY.yaml
    • "after updates"-processes in Shop with this ID
    • if not set, the command check if Plugin-Configs exists for all Shop-Ids
  • activate all Modules in a certain order (via trw:allmodules:active command)
  • set Shop Maintenance Mode "off"
  • clean cache (via trw:clear:cache command)
  • upate views
  • run migrations

before the Update (trw:update:before)

  • option --env=XXXX: get the Plugin-Config from file trwclirun/XXXX.1.yaml
  • option --shop-id=YYYY:
    • get the Plugin-Config from file trwclirun/XXXX.YYYY.yaml or trwclirun/YYYY.yaml
    • "before updates"-processes in Shop with this ID
    • if not set, the command check if Plugin-Configs exists for all Shop-Ids
  • check whether certain conditions are met
  • set Shop Maintenance Mode "on"
  • deactivate all Modules (via trw:allmodules:deactive command)
  • clean broken Modules Options
  • delete all old themes

Views Update (trw:update:views)

  • update the Shop views