Skip to content

Import a table (PRO) ​

Describe a table the database already has with the constructor, without typing one field per column.

The constructor can create a table from scratch, but people usually arrive with a database already in place: their own from a previous project, built by someone else's code, inherited from the last developer. Describing such a table by hand means opening the field editor once per column and never once mistyping a name. And the typo is silent: the field saves, but its value goes into data instead of the real column, and you notice a week later from an empty column in the grid.

Migrations from the manager are not required for an import

Working with file migrations alone is a first-class way to run this component, and a table may have no row in the migration journal at all. The schema is read from the live table.

Using it ​

Constructor → Tables → "Import a table" in the toolbar.

  1. Pick a table. Ones the constructor already describes are marked with the name of their constructor — picking them is allowed, and a repeat import only adds columns that are new.
  2. The model name and the constructor's label are filled in from the table name; a value you typed is not overwritten.
  3. "Show plan" — what you will get.
  4. "Import".

Read the plan before the write

Plan and write are deliberately separate: on a forty-column table a wrong field is visible in the plan, whereas after the write you clean it up by hand.

How a column becomes a field ​

The field type is chosen from the column type alone, never guessed from the name.

ColumnField
varchar up to 255, chartext field
varchar longer than 255, text, tinytexttextarea
mediumtext, longtextrich text editor
tinyint(1)yes/no
integersnumber (minimum 0 when unsigned)
decimal, float, doublenumber, decimals taken from scale
datedate without time
datetime, timestampdate with time
timetime
enumselect with the options filled in
setcheckboxes with the options filled in
jsonkey-value grid
an unknown typetext field

Why names are not used as a hint

The temptation was there: *_id looks like a relation, image like a picture, color like a palette. But a relation has to be known, not suspected, and an error here costs more than a blank: you hand someone a form that writes into a column something other than what it holds. A field type is two clicks to change in the constructor, so the import gives an honest minimum.

What else comes off the schema:

  • required — a column that takes no NULL and has no default will refuse an insert at the database level. The field is marked required so that this shows in the form rather than arriving as a MySQL error after "Save";
  • default value — from the column's default. Expressions (CURRENT_TIMESTAMP, uuid()) are dropped: in an input that is just a word;
  • help text — from the column's COMMENT;
  • the enum and set options — the single most valuable line of the import: by hand that is the most tedious field of all to fill in.

Columns that do not reach the form ​

WhatWhy
auto-incrementthe database sets the value
GENERATED (computed)the database rejects a write to it
id, created_at, updated_at, deleted_atEloquent maintains them
model_type, model_id, parent_type, parent_id, constructor_id, field_id, context_keythe constructor's own links
datathe dump for fields without columns — the other side of this very import
menuindexmoved by dragging in the grid
published_atthe publish button
moderation_atmaintained by the moderation queue
blob, binary, varbinarybinary data, no form input for it

Skipped columns appear in the plan with a reason — they are not lost silently.

Six grid columns ​

A grid of forty columns is unreadable, and the first thing anyone does with it is delete thirty-five. So columns are created for the first six fields; how many were left out, the plan states as a number. The limit is editable in the form, and zero means "create no grid columns".

The model ​

The constructor needs an Eloquent class bound to the table: without one the section opens but shows no rows. Three cases, and the plan says which:

  • the class exists — the constructor binds to it;
  • no class, the box is ticked — the model is generated in core/App/Models from the live schema. The primary key is not assumed to be id: in a foreign table it may be called order_id or be a string, in which case $primaryKey, $incrementing and $keyType are written into the base model;
  • no class, the box is clear — stated in the plan and again after the write.

Your edits to the model are not lost: only Models/Base/Base<Name>.php is overwritten, while Models/<Name>.php is created once.

A singular is not derived from the table name

shop_orders gives ShopOrders. The "drop the s" rule breaks on address, status and settings, and a wrong class name then lives on in the database as a relation key. Set your own name in the form.

Running it again ​

Safe. A field is matched by name within the constructor, and a column already described stays as it is — type, label and help are things a person edits after the import, and a second run does not overwrite that. A field in the recycle bin also counts as holding its name.

The import does not restore a grid column for a field already described: it may have been removed on purpose.

Which tables the list offers ​

Only tables carrying the connection's prefix (usually modx_ on MODX), and they are shown without it: the physical modx_shop_orders is the logical shop_orders.

This is not cosmetic. A model with $table = 'shop_orders' asks for modx_shop_orders, because the prefix is prepended anyway. A table without the prefix is one no model on this connection can address at all, and offering it would promise a constructor that opens empty.

To import an unprefixed table, rename it

Add the site's prefix. There is no other route through the constructor.

What is not there ​

  • foreign keys are not read, and the import creates no relation fields. A relation has to be known, and a user_id column does not say where it points;
  • indexes affect nothing: the "searchable" and "filterable" flags stay clear, to be set deliberately;
  • tabs are not created — every field lands on the main one;
  • there is no reverse operation: the import describes a table, it does not change it. Changing the structure is migrations from the manager, a different thing that is easy to confuse with this one.

© PageBlocks 2019-present