›
›
›
  1. docs
  2. ›
  3. byrcsc/laravel-cartographer
1.x
Browse documentationOpenClose

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • How a diagram is built
  • Model discovery
  • Relationship detection
  • Schema introspection
  • Scoping a diagram

Operations

  • Diagrams per subsystem
  • Exporting images
  • Themes and fonts
  • Renderer limits
  • Keeping the diagram current
  • Continuous integration

Reference

  • Configuration
  • Console commands
  • Diagram syntax
  • PHP API
  • Testing
  • Troubleshooting

Getting started

  • Introduction
  • Installation and setup
  • Quick start

Core concepts

  • How a diagram is built
  • Model discovery
  • Relationship detection
  • Schema introspection
  • Scoping a diagram

Operations

  • Diagrams per subsystem
  • Exporting images
  • Themes and fonts
  • Renderer limits
  • Keeping the diagram current
  • Continuous integration

Reference

  • Configuration
  • Console commands
  • Diagram syntax
  • PHP API
  • Testing
  • Troubleshooting

byrcsc/laravel-cartographer · 1.x

Schema introspection.

Cartographer reads tables, columns, and keys without reading application data.

Cartographer asks Laravel's schema builder for every table on the selected connection. It reads columns, indexes, and foreign key constraints from the database.

The database must be reachable and migrated before you generate a diagram. In return, the diagram reflects the current structure even when the application uses squashed migrations, raw SQL, or columns added outside a migration.

No data is read

Schema introspection means reading information about the database structure. Cartographer reads information_schema on MySQL, system catalogs on PostgreSQL, and PRAGMA data on SQLite. It never selects rows from an application table.

The connection therefore only needs permission to read schema metadata.

Choosing the connection

php artisan cartographer:erd --connection=reporting
// config/cartographer.php
'connection' => 'reporting',

The --connection option wins over the config key, and null in config means the application's default connection. The value must be null or a non-empty string; anything else fails the command.

Each run reads one connection. If your models use several connections, generate one diagram for each connection. See diagrams per subsystem.

When the connection cannot be opened or introspected, the command fails with:

   ERROR  Unable to introspect database connection [reporting]. Check the connection name, credentials, and database availability.

The same message covers an unknown connection name, wrong credentials, and a database that is not running. The original driver exception is kept as the previous exception on SchemaReadException.

Column types are normalized

The same application on three drivers reports three sets of type names. Cartographer maps them onto one small vocabulary, so the committed diagram does not change when a developer runs it against SQLite and CI runs it against MySQL.

Rendered asDriver types collapsed into it
bigintbigint, bigserial, int8
integerint, int4, integer, mediumint, serial
smallintint2, smallint, smallserial, tinyint
varcharvarchar, char, character, character varying, bpchar, uuid
timestamptimestamp, timestamptz, timestamp with time zone, timestamp without time zone, datetime, datetime2, smalldatetime
texttext, tinytext, mediumtext, longtext, json, jsonb
decimaldecimal, numeric, float, real, double, double precision
booleanbool, boolean, and any tinyint(1)

Three rules shape the table:

  • Length and precision are dropped. varchar(255) and varchar(64) both render as varchar. The diagram is about shape, not storage.
  • unsigned is dropped. bigint unsigned renders as bigint.
  • tinyint(1) is boolean. MySQL's boolean is a tinyint(1), and it is matched on the native type before anything else.

A type the normalizer does not recognise passes through unchanged, with its original spelling and whitespace. A PostGIS geometry column stays geometry; a vector column stays whatever the driver called it. Nothing is lost, and future column types need no package release.

The integer-to-bigint rule

int and integer render as bigint when the column takes part in a key, and integer when it does not.

"Takes part in a key" means the column appears in any index, of any kind, or in any foreign key constraint. SQLite reports id as INTEGER where MySQL and PostgreSQL report bigint; without this rule, the same application would produce a different diagram per driver on nearly every primary and foreign key.

The effect is confined to int-family types. A non-key integer column stays integer:

    attachments {
        bigint id PK
        integer size_bytes
    }

Key markers

Each column line carries the markers that apply to it, in this order:

MarkerCondition
PKThe column appears in the table's primary key
FKThe column appears in a foreign key constraint
UKThe column appears in a unique index and is not part of the primary key
    profiles {
        bigint id PK
        bigint user_id FK, UK
    }

Composite keys mark every column they contain. PK suppresses UK on the same column, because a primary key is unique by definition and the second marker adds nothing.

Two things follow, and both surprise people at least once:

FK requires a real constraint. Applications that model relationships in Eloquent but never declare foreign keys in the database get correct edges and no FK markers. The edges come from the models; the markers come from the schema.

Plain indexes are invisible. A non-unique index affects nothing you can see, though it does count towards the integer-to-bigint rule above. Mermaid entity blocks have no notation for it.

Which tables become entities

Introspection reads every table on the connection, but the graph only uses two kinds:

  • Tables belonging to a discovered model.
  • Pivot tables named by a many-to-many relation that is in scope.

Cartographer ignores a table that has no discovered model. This includes legacy log tables, framework tables such as jobs and cache, and tables created by other packages. The model list acts as the table filter.

Ordering

Tables, columns, indexes, and foreign keys are each sorted by name before use. Column order in the diagram is alphabetical, not the physical column order of the table. Drivers do not agree on the order they return metadata in, and a diagram that reshuffles itself between machines is not reviewable.

What to read next

  • Diagram syntax for how columns and markers are rendered.
  • Model discovery for how the model list, and therefore the table list, is decided.
  • Troubleshooting for missing tables and connection failures.
PreviousRelationship detectionNextScoping a diagram
View source

On this page

  1. No data is read
  2. Choosing the connection
  3. Column types are normalized
  4. The integer-to-bigint rule
  5. Key markers
  6. Which tables become entities
  7. Ordering
  8. What to read next