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.
- 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.
- The model name and the constructor's label are filled in from the table name; a value you typed is not overwritten.
- "Show plan" — what you will get.
- "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.
| Column | Field |
|---|---|
varchar up to 255, char | text field |
varchar longer than 255, text, tinytext | textarea |
mediumtext, longtext | rich text editor |
tinyint(1) | yes/no |
| integers | number (minimum 0 when unsigned) |
decimal, float, double | number, decimals taken from scale |
date | date without time |
datetime, timestamp | date with time |
time | time |
enum | select with the options filled in |
set | checkboxes with the options filled in |
json | key-value grid |
| an unknown type | text 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
NULLand 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
enumandsetoptions — 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
| What | Why |
|---|---|
| auto-increment | the database sets the value |
GENERATED (computed) | the database rejects a write to it |
id, created_at, updated_at, deleted_at | Eloquent maintains them |
model_type, model_id, parent_type, parent_id, constructor_id, field_id, context_key | the constructor's own links |
data | the dump for fields without columns — the other side of this very import |
menuindex | moved by dragging in the grid |
published_at | the publish button |
moderation_at | maintained by the moderation queue |
blob, binary, varbinary | binary 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/Modelsfrom the live schema. The primary key is not assumed to beid: in a foreign table it may be calledorder_idor be a string, in which case$primaryKey,$incrementingand$keyTypeare 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_idcolumn 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.