Multi-Component Data Model
Propulsion comes with packaging capabilities that make it easier to integrate into a packaged or modularized application.
Multiple schemas
Section titled “Multiple schemas”You can use as many schema.xml files as you want. Schema files must be named (*.)schema.xml, so schema.xml, package1.schema.xml, and core.package1.schema.xml are all acceptable names. These files have to be located in your project directory.
Each schema file must contain a <database> element with a name attribute. This name references the connection settings to use for this database (configured in your project’s configuration), so separate schema files can share a common database name.
Whenever you run a Propulsion build command, it considers all matching schema files and builds classes (or SQL) for every table across all of them.
Understanding packages
Section titled “Understanding packages”In Propulsion, a package is a group of models. It’s a convenient way to organize your code in a modularized fashion, since classes and SQL files for a given package are grouped together and separated from other packages. By carefully choosing the package for each model, an application ends up split into smaller, independent modules that are easier to manage.
Package cascade
Section titled “Package cascade”The package is defined through a configuration cascade — you can set it for the whole project, for all the tables in a schema, or for a single table.
For the whole project, set the main package in your configuration file:
<?phpreturn [ 'propulsion.targetPackage' => 'my_project',];By default, all tables in all schemas use this package. You can override it for a given <database> by setting its package attribute:
<!-- in author.schema.xml --><database package="author" name="bookstore"> <table name="author"> <!-- author columns --> </table></database>
<!-- in book.schema.xml --><database package="book" name="bookstore"> <table name="book"> <!-- book columns --> </table> <table name="review"> <!-- review columns --> </table></database>Thanks to the package attribute, tables are grouped into:
my_project.authorpackage: theauthortablemy_project.bookpackage: thebookandreviewtables
You can also override package at the <table> element level:
<!-- in author.schema.xml --><database package="author" name="bookstore"> <table name="author"> <!-- author columns --> </table></database>
<!-- in book.schema.xml --><database package="book" name="bookstore"> <table name="book"> <!-- book columns --> </table> <table name="review" package="review"> <!-- review columns --> </table></database>This produces:
my_project.authorpackage: theauthortablemy_project.bookpackage: thebooktablemy_project.reviewpackage: thereviewtable
Tables can end up in separate packages even though they belong to the same schema file.
Packages and generated model files
Section titled “Packages and generated model files”A table’s package attribute translates to the directory Propulsion generates its Model classes into.
If no package attribute is set anywhere, Propulsion places all classes according to propulsion.targetPackage:
generated-classes/Base/Map/Author.phpAuthorQuery.phpBook.phpBookQuery.phpReview.phpReviewQuery.php
You can further control where Propulsion writes generated files with the --output-dir/-o option on model:build (and sql:build for SQL, see below). There is no outputDir build-config property for this — it’s a command-line option, and it defaults to ./generated-classes for model:build.
If you set up packages at the <database> level, Propulsion splits the generated model classes into subdirectories named after the package:
generated-classes/author/Base/Map/Author.phpAuthorQuery.php
book/Base/Map/Book.phpBookQuery.phpReview.phpReviewQuery.php
And, if you specialize package per table, one table can use its own package:
generated-classes/author/Base/Map/Author.phpAuthorQuery.php
book/Base/Map/Book.phpBookQuery.php
review/Base/Map/Review.phpReviewQuery.php
Packages and SQL files
Section titled “Packages and SQL files”SQL generation does not split by package. sql:build writes exactly one .sql file per distinct <database name="..."> value: all CREATE TABLE statements for every schema file (and every package) that shares that database name are concatenated together into that one file, named <name>.sql.
For the author.schema.xml/book.schema.xml example above, both files declare <database name="bookstore" ...>, so regardless of their different package attributes (author, book, review), the output is a single file:
generated-sql/bookstore.sql—CREATE TABLE author,CREATE TABLE book, andCREATE TABLE review
To get separate SQL files, give the <database> elements different name attributes instead of relying on package.
Understanding packageObjectModel
Section titled “Understanding packageObjectModel”propulsion.packageObjectModel is a build property defined in generator/default.php (defaulting to false), but it is not currently read anywhere in Propulsion’s build pipeline — toggling it has no observable effect on model:build or sql:build. Each schema file passed to a build command is parsed into its own independent model; a table can only resolve foreign keys against tables declared in the same file, regardless of whether other files share its database name. To reference tables defined in another file, use an explicit <external-schema filename="..."/> element inside the <database> element that needs the reference.
A packaged example
Section titled “A packaged example”Consider a project laid out with these schema files:
author.schema.xmlbook.schema.xmlclub.schema.xmlmedia.schema.xmlpublisher.schema.xmlreview.schema.xmllog.schema.xml
Each file’s <database> tag sets package to the package name every table in that file belongs to. For example, author.schema.xml might contain:
<database package="core.author" name="bookstore" ...>This means the Author Object Model classes are generated under a core/author/ subdirectory of the build output directory.
More than one schema file can belong to the same package — for example, book.schema.xml and media.schema.xml might both belong to core.book, so their generated classes end up together under core/book/.
The Object Model build
Section titled “The Object Model build”To build the packaged example, run from the project directory containing these schema files (the schema argument tells the command where to look — its default is ./schema, so pass . to scan the current directory instead):
php bin/propulsion model:build .This produces a directory tree along these lines (the Base/ and Map/ subdirectories under each package are omitted for clarity):
addon/club/BookClubList.phpBookListRel.php
core/author/Author.php
book/Book.php
media/Media.php
publisher/Publisher.php
review/Review.php
util/log/BookstoreLog.php
The SQL build
Section titled “The SQL build”From the same schema files, generate SQL with:
php bin/propulsion sql:build .Inspect the generated-sql/ directory: one SQL file has been created per distinct <database name="..."> value, not per package. If author.schema.xml, book.schema.xml, club.schema.xml, media.schema.xml, publisher.schema.xml, and review.schema.xml all declare <database name="bookstore" ...> while log.schema.xml declares <database name="bookstore-log" ...>, the build produces just two files:
bookstore.sql—CREATE TABLEstatements for every table across the sixbookstoreschema files, regardless of theirpackageattributebookstore-log.sql—CREATE TABLEstatements forlog.schema.xml’s table
Run sql:exec to execute a file against your configured database (it requires an explicit list of .sql files and connection options — there’s no config-driven auto-discovery):
php bin/propulsion sql:exec generated-sql/bookstore.sql --dsn="pgsql:host=localhost;dbname=mydb" --user=me --password=secret