NOTE: This was originally submitted as Pull Request #17. I am submitting it as a new pull request in order to direct it into the next branch, rather than master.
WARNING:Accepting this pull request will break backwards compatibility with all previous versions of Phactory, as well as what's currently in master. I am submitting this for review and discussion more than blind acceptance into the Phactory master branch. Following discussion, you may feel that these modifications aren't good for the Phactory project or that they are best-suited in a Phactory2 repository, creating a logical split from the current version of the project. That's up to you.
This pull request introduces namespaces to Phactory. It also removes all static calls and singleton behavior, so that instances of Phactory objects must be created and passed around (dependency injection). These changes were made to solve the following problems I encountered:
Since Phactory.php and PhactoryMongo.php both contained classes named Phactory, it was impossible to include them both in the same tests
Again, since both files defined classes with the same name, PSR-0 autoloaders had problems loading the PhactoryMongo class, since it was not named appropriately; this also led to problems with Composer autoloading from the vendor directory
The static methods were difficult to write tests for in PHPUnit. Migrating them to instance methods has alleviated the problems caused by testing static methods and singletons
As a result of these changes, backwards compatibility is broken with current master and all previous tags of Phactory. However, what is gained is:
Compliance with PSR-0 autoloaders
Ability to use Phactory with Composer without autoloader conflicts
Ability to test both SQL and Mongo databases within the same tests
Easier to test Phactory methods with PHPUnit
Here is an example unit test using MongoDB and these updates to Phactory. This unit test will run as is, provided you have a local MongoDB database with a "testdb" database and a user with username "myuser" and password "mypass". It assumes you have this test in a file in the root of your project and that you have run composer.phar install so that there is a vendor/ directory with your autoloader in it. Feel free to give it a try.
<?php
namespace My\Foo;
require_once 'vendor/autoload.php';
use Phactory\Mongo\Phactory as PhactoryMongo;
class FooTestCase extends \PHPUnit_Framework_TestCase
{
protected $mongo;
protected $phactory;
protected $fixtures = array();
protected function setUp()
{
$this->mongo = new \Mongo('mongodb://localhost:27017', array(
'db' => 'testdb',
'username' => 'myuser',
'password' => 'mypass',
));
$this->phactory = new PhactoryMongo($this->mongo->testdb);
$this->phactory->reset();
$this->defineFixtures();
$this->buildFixtures();
}
protected function tearDown()
{
$this->phactory->recall();
}
protected function defineFixtures()
{
$this->phactory->define('book', array(
'_id' => null,
'name' => 'The Great Book $n',
'created' => new \MongoDate,
));
$this->phactory->define('author', array(
'_id' => null,
'name' => 'J.R.R. Authorname $n',
'description' => 'A widely respected test author.',
'created' => new \MongoDate,
), array(
'books' => $this->phactory->embedsMany('books'),
));
$this->phactory->define('publisher', array(
'_id' => null,
'name' => 'Acme Publishing $n, LLC',
'created' => new \MongoDate,
), array(
'authors' => $this->phactory->embedsMany('authors'),
));
}
protected function buildFixtures()
{
// Books for Publisher 1, Author 1 (embedded doc, use "build")
$book1 = $this->phactory->build('book', array('_id' => new \MongoId));
$book2 = $this->phactory->build('book', array('_id' => new \MongoId));
// Books for Publisher 1, Author 2 (embedded doc, use "build")
$book3 = $this->phactory->build('book', array('_id' => new \MongoId));
$book4 = $this->phactory->build('book', array('_id' => new \MongoId));
// Books for Publisher 2, Author 3 (embedded doc, use "build")
$book5 = $this->phactory->build('book', array('_id' => new \MongoId));
$book6 = $this->phactory->build('book', array('_id' => new \MongoId));
// Publisher 1, Author 1
// (embedded doc with embedded items, use "buildWithAssociations")
$author1 = $this->phactory->buildWithAssociations('author', array(
'books' => array($book1, $book2),
), array(
'_id' => new \MongoId,
));
// Publisher 1, Author 2
// (embedded doc with embedded items, use "buildWithAssociations")
$author2 = $this->phactory->buildWithAssociations('author', array(
'books' => array($book3, $book4),
), array(
'_id' => new \MongoId,
));
// Publisher 2, Author 3
// (embedded doc with embedded items, use "buildWithAssociations")
$author3 = $this->phactory->buildWithAssociations('author', array(
'books' => array($book5, $book6),
), array(
'_id' => new \MongoId,
));
// Publisher 1
// (parent doc with embedded items, use "createWithAssociations")
$publisher1 = $this->phactory->createWithAssociations('publisher', array(
'authors' => array($author1, $author2),
), array(
'_id' => new \MongoId,
));
// Publisher 2
// (parent doc with embedded items, use "createWithAssociations")
$publisher2 = $this->phactory->createWithAssociations('publisher', array(
'authors' => array($author3),
), array(
'_id' => new \MongoId,
));
// Set the fixtures so that we may access them from the tests
$this->fixtures['publisher1'] = $publisher1;
$this->fixtures['publisher2'] = $publisher2;
}
public function testSomething()
{
$publisher = $this->mongo->testdb->publishers->findOne(array(
'_id' => $this->fixtures['publisher1']['_id'],
));
$this->assertEquals($this->fixtures['publisher1']['name'], $publisher['name']);
}
}
This test will create structures in Mongo DB that look like this:
For Publisher 1:
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000009"),
"name" : "Acme Publishing 0, LLC",
"created" : ISODate("2012-06-22T18:39:47.122Z"),
"authors" : [
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000006"),
"name" : "J.R.R. Authorname 0",
"description" : "A widely respected test author.",
"created" : ISODate("2012-06-22T18:39:47.121Z"),
"books" : [
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000000"),
"name" : "The Great Book 0",
"created" : ISODate("2012-06-22T18:39:47.121Z")
},
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000001"),
"name" : "The Great Book 1",
"created" : ISODate("2012-06-22T18:39:47.121Z")
}
]
},
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000007"),
"name" : "J.R.R. Authorname 1",
"description" : "A widely respected test author.",
"created" : ISODate("2012-06-22T18:39:47.121Z"),
"books" : [
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000002"),
"name" : "The Great Book 2",
"created" : ISODate("2012-06-22T18:39:47.121Z")
},
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000003"),
"name" : "The Great Book 3",
"created" : ISODate("2012-06-22T18:39:47.121Z")
}
]
}
]
}
For Publisher 2:
{
"_id" : ObjectId("4fe4bbf3dfb5cde96800000a"),
"name" : "Acme Publishing 1, LLC",
"created" : ISODate("2012-06-22T18:39:47.122Z"),
"authors" : [
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000008"),
"name" : "J.R.R. Authorname 2",
"description" : "A widely respected test author.",
"created" : ISODate("2012-06-22T18:39:47.121Z"),
"books" : [
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000004"),
"name" : "The Great Book 4",
"created" : ISODate("2012-06-22T18:39:47.121Z")
},
{
"_id" : ObjectId("4fe4bbf3dfb5cde968000005"),
"name" : "The Great Book 5",
"created" : ISODate("2012-06-22T18:39:47.121Z")
}
]
}
]
}
NOTE: This was originally submitted as Pull Request #17. I am submitting it as a new pull request in order to direct it into the
next
branch, rather thanmaster
.WARNING: Accepting this pull request will break backwards compatibility with all previous versions of Phactory, as well as what's currently in master. I am submitting this for review and discussion more than blind acceptance into the Phactory master branch. Following discussion, you may feel that these modifications aren't good for the Phactory project or that they are best-suited in a Phactory2 repository, creating a logical split from the current version of the project. That's up to you.
This pull request introduces namespaces to Phactory. It also removes all static calls and singleton behavior, so that instances of Phactory objects must be created and passed around (dependency injection). These changes were made to solve the following problems I encountered:
As a result of these changes, backwards compatibility is broken with current master and all previous tags of Phactory. However, what is gained is:
Here is an example unit test using MongoDB and these updates to Phactory. This unit test will run as is, provided you have a local MongoDB database with a "testdb" database and a user with username "myuser" and password "mypass". It assumes you have this test in a file in the root of your project and that you have run
composer.phar install
so that there is avendor/
directory with your autoloader in it. Feel free to give it a try.This test will create structures in Mongo DB that look like this:
For Publisher 1:
For Publisher 2: