2. Primary Contributors
Stephan Soileau Adam Englander
● Former Employee ● Selling Source Employee
● Current lead developer on ● Current lead developer for CMG
Cassandra 3.0 ● Famously rode on the shirt tails
● Testing evangelist and BDD guru of Stephan to BDD fame and
glory
3. Why PHP Machinist Was Created
● Behat, a Cucumber port is born.
○ Factory Girl/Machinist port for handling relational
data as Gherkin tables is needed.
● DBUnit, a PHP port of DBUnit is just as
terrible as DBUnit.
○ XML data structure too verbose
○ Large relational datasets are unmanageable
● Phactory is almost good enough but would
not handle compound primary keys.
○ Phactory blueprints are very similar but does not
handle compound keys.
○ Only supports PDO data sources
4. Connecting to Your Data
PHP Machinist provides a standard interface
with the following provided implementations:
● PDO
○ SQLite
○ MySQL
● Doctrine ORM
● Experimental NoSQL available in doctrine-
mongodb branch
● Doctrine MongoDB
● MongoDB
5. Connection Example: PDO SQLite
Easy way:
$pdo = new PDO("sqlite::memory:");
machinistMachinist::Store(SqlStore::fromPdo($pdo));
Hard way:
$pdo = new PDO("sqlite::memory:");
$store = new machinistdriverSqlite($pdo);
machinistMachinist::Store($store);
6. Blueprints Define Data Structures
Blueprints define the data structure by:
● Defining tables with aliases
● Define default values
● Define relationships
● Useable in PHPUnit tests and Behat context
7. Blueprints Example
Create a blueprint called "cardboardbox" on table "box" and default the "type"
to "cardboard"
$cbBox = Machinist::Blueprint("cardboardbox", "box", array("type" => "cardboard"));
Create a blueprint called "plasticbox" on table "box" and default the "type" to
"plastic"
$plBox = Machinist::Blueprint("plasticbox", "box", array("type" => "plastic"));
Create a blueprint called "crayon" on table "stuff" with "name" defaulted to
"crayon" and a relationship called box that references the the "box_id" column
in the "stuff" table. If foreign method is not called, the primary key for the
foreign key is assumed.
Machinist::Blueprint("crayon", "stuff"
array(
"name" => "crayon",
"box" => Machinist::Relationship($cbBox)->local("box_id"),
)
);
8. make() Stores Data
● Make stores data in the tables.
● It will use default data.
● It will override the default data with data
provided in the make call.
● Relationship data, if provided will be
associated or added if it does not exist.
● Relationship data will use defaults for data
not provided in the make call.
9. make() Example: Save Data
$cbBox = Machinist::Blueprint("cardboardbox", "box", array("type" => "cardboard"));
$plBox = Machinist::Blueprint("plasticbox", "box", array("type" => "plastic"));
Machinist::Blueprint("crayon", "stuff"
array(
"name" => "crayon"
"box" => Machinist::Relationship($cbBox)->local("box_id"),
)
);
Make a crayon with the "name" defaulted to "crayon"
Machinist::Blueprint("crayon")->make();
Make a crayon with the "name"of "red crayon" and "color" of "red"
Machinist::Blueprint("crayon")->make(array(
"name" => "red crayon",
"color" => "red"
);
10. make() Example: Save Related Data
$cbBox = Machinist::Blueprint("cardboardbox", "box", array("type" => "cardboard"));
$plBox = Machinist::Blueprint("plasticbox", "box", array("type" => "plastic"));
Machinist::Blueprint("crayon", "stuff"
array(
"name" => "crayon"
"box" => Machinist::Relationship($cbBox)->local("box_id"),
)
);
Make a crayon with the no associated box
Machinist::Blueprint("crayon")->make();
Make a crayon with a box and create the box as none exists
Machinist::Blueprint("crayon")->make(array("box" => array("type" => "new type")));
Make a new crayon with a box and use the same box as it exists
Machinist::Blueprint("crayon")->make(array("box" => array("type" => "new type")));
11. find() Retrieves Data data
Find finds all rows by criteria.
FindOne finds one row by criteria
FindOrCreate finds one row by criteria or
creates a row using the criteria as data.
Find retrieves data by:
● Primary key
● Column/Value array
● Foreign key relationship data
Find populates relationship data if relational
data exists.
Machine objects are returned by Find*
13. wipe() Cleans Up Test Data
● Wipe is available at two levels:
○ Blueprints can perform a wipe to remove all data in
the related table.
○ Machinist instance method can clean up data for
tables related to all defined machines.
○ Machinst static method can clean up data for one or
more machines.
● Wipe can delete data or truncate tables if the
Store implentation supports the feature.
● Machinist level wipe can specify exclusions
as an array of blueprint names
14. wipe() Examples
Truncate the "crayon" blueprint's table
machinistMachinist::wipe("crayon", true);
machinistMachinist::Blueprint("crayon", true);
Truncate all blueprints tables but the "cbBox" blueprint's
table
machinistMachinist::wipe(null, true, array("cbBox"));
machinistMachinist::instance()->wipe(true, array("cbBox"));
15. Behat Usage
PHP Machinist is designed to be utilized within
Behat features with little to no additional work.
It supplies:
● Feature context that can be added to the
default feature context
● Steps for populating data as well as
validating data
● Easy Gherkin table interface
16. Behat Example: Feature Context
class FeatureContext extends BehatContext implements ClosuredContextInterface {
public function __construct(array $parameters) {
$config = array(
"database" => array(
"default" => array("dsn" => "sqlite::memory:")
)
);
$context = new machinistbehatMachinistContext($config);
$this->useContext('machinist', $this->getMachinistContext());
}
17. Behat Example
Feature: Cardboard Box
As a crayon
I should be able to have a cardboard box
Background:
Given there are no machines
And the following crayons exists:
| color | box |
| red | type: plastic |
● Performed a wipe on all Blueprints
● Performed a make on the "crayon" blueprint with the
"color" column set to red
● Performed a findOrCreate on the blueprint in the "box"
association, "cbBox", with a type of plastic