Skip to content
Permalink
Browse files

Add ability to define model factories statically

  • Loading branch information...
Marlinc committed Apr 26, 2016
1 parent 4697b8e commit fccfc6ec39d1740e26ba77354a68e14453820a10
@@ -13,6 +13,7 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
use Cake\Datasource\FactoryLocator;
use Cake\Routing\Router;
define('TIME_START', microtime(true));
@@ -0,0 +1,74 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Datasource;
use Cake\ORM\TableRegistry;
use InvalidArgumentException;
class FactoryLocator
{
/**
* A list of model factory functions.
*
* @var callable[]
*/
protected static $_modelFactories = [];
/**
* Register a callable to generate repositories of a given type.
*
* @param string $type The name of the repository type the factory function is for.
* @param callable $factory The factory function used to create instances.
* @return void
*/
public static function add($type, callable $factory)
{
static::$_modelFactories[$type] = $factory;
}
/**
* Drop a model factory.
*
* @param string $type The name of the repository type to drop the factory for.
* @return void
*/
public static function drop($type)
{
unset(static::$_modelFactories[$type]);
}
/**
* Get the factory for the specified repository type.
*
* @param string $type The repository type to get the factory for.
* @throws InvalidArgumentException If the specified repository type has no factory.
* @return callable The factory for the repository type.
*/
public static function get($type)
{
if (!isset(static::$_modelFactories['Table'])) {
static::$_modelFactories['Table'] = [TableRegistry::locator(), 'get'];
}
if (!isset(static::$_modelFactories[$type])) {
throw new InvalidArgumentException(sprintf(
'Unknown repository type "%s". Make sure you register a type before trying to use it.',
$type
));
}
return static::$_modelFactories[$type];
}
}
@@ -41,7 +41,7 @@ trait ModelAwareTrait
public $modelClass;
/**
* A list of model factory functions.
* A list of overridden model factory functions.
*
* @var array
*/
@@ -104,13 +104,12 @@ public function loadModel($modelClass = null, $modelType = null)
return $this->{$alias};
}
if (!isset($this->_modelFactories[$modelType])) {
throw new InvalidArgumentException(sprintf(
'Unknown repository type "%s". Make sure you register a type before trying to use it.',
$modelType
));
if (isset($this->_modelFactories[$modelType])) {
$factory = $this->_modelFactories[$modelType];
}
if (!isset($factory)) {
$factory = FactoryLocator::get($modelType);
}
$factory = $this->_modelFactories[$modelType];
$this->{$alias} = $factory($modelClass);
if (!$this->{$alias}) {
throw new MissingModelException([$modelClass, $modelType]);
@@ -119,7 +118,7 @@ public function loadModel($modelClass = null, $modelType = null)
}
/**
* Register a callable to generate repositories of a given type.
* Override a existing callable to generate repositories of a given type.
*
* @param string $type The name of the repository type the factory function is for.
* @param callable $factory The factory function used to create instances.
@@ -0,0 +1,168 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.3.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Test\TestCase\Datasource;
use Cake\Datasource\FactoryLocator;
use Cake\TestSuite\TestCase;
/**
* FactoryLocatorTest test case
*/
class FactoryLocatorTest extends TestCase
{
/**
* Test get factory
*
* @return void
*/
public function testGet()
{
$this->assertInternalType('callable', FactoryLocator::get('Table'));
}
/**
* Test get non existing factory
*
* @return void
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Unknown repository type "Test". Make sure you register a type before trying to use it.
*/
public function testGetNonExisting()
{
FactoryLocator::get('Test');
}
/**
* test add()
*
* @return void
*/
public function testAdd()
{
FactoryLocator::add('Test', function ($name) {
$mock = new \StdClass();
$mock->name = $name;
return $mock;
});
$this->assertInternalType('callable', FactoryLocator::get('Test'));
}
/**
* test drop()
*
* @return void
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Unknown repository type "Test". Make sure you register a type before trying to use it.
*/
public function testDrop()
{
FactoryLocator::drop('Test');
FactoryLocator::get('Test');
}
/**
* test loadModel() with plugin prefixed models
*
* Load model should not be called with Foo.Model Bar.Model Model
* But if it is, the first call wins.
*
* @return void
*/
public function testLoadModelPlugin()
{
$stub = new Stub();
$stub->setProps('Articles');
$stub->modelType('Table');
$result = $stub->loadModel('TestPlugin.Comments');
$this->assertInstanceOf('TestPlugin\Model\Table\CommentsTable', $result);
$this->assertInstanceOf('TestPlugin\Model\Table\CommentsTable', $stub->Comments);
$result = $stub->loadModel('Comments');
$this->assertInstanceOf('TestPlugin\Model\Table\CommentsTable', $result);
$this->assertInstanceOf('TestPlugin\Model\Table\CommentsTable', $stub->Comments);
}
/**
* test alternate model factories.
*
* @return void
*/
public function testModelFactory()
{
$stub = new Stub();
$stub->setProps('Articles');
$stub->modelFactory('Table', function ($name) {
$mock = new \StdClass();
$mock->name = $name;
return $mock;
});
$result = $stub->loadModel('Magic', 'Table');
$this->assertInstanceOf('\StdClass', $result);
$this->assertInstanceOf('\StdClass', $stub->Magic);
$this->assertEquals('Magic', $stub->Magic->name);
}
/**
* test alternate default model type.
*
* @return void
*/
public function testModelType()
{
$stub = new Stub();
$stub->setProps('Articles');
FactoryLocator::add('Test', function ($name) {
$mock = new \StdClass();
$mock->name = $name;
return $mock;
});
$stub->modelType('Test');
$result = $stub->loadModel('Magic');
$this->assertInstanceOf('\StdClass', $result);
$this->assertInstanceOf('\StdClass', $stub->Magic);
$this->assertEquals('Magic', $stub->Magic->name);
}
/**
* test MissingModelException being thrown
*
* @return void
* @expectedException \Cake\Datasource\Exception\MissingModelException
* @expectedExceptionMessage Model class "Magic" of type "Test" could not be found.
*/
public function testMissingModelException()
{
$stub = new Stub();
FactoryLocator::add('Test', function ($name) {
return false;
});
$stub->loadModel('Magic', 'Test');
}
public function tearDown()
{
FactoryLocator::drop('Test');
parent::tearDown();
}
}
@@ -13,6 +13,7 @@
*/
namespace Cake\Test\TestCase\Datasource;
use Cake\Datasource\FactoryLocator;
use Cake\Datasource\ModelAwareTrait;
use Cake\TestSuite\TestCase;
@@ -59,7 +60,6 @@ public function testLoadModel()
{
$stub = new Stub();
$stub->setProps('Articles');
$stub->modelFactory('Table', ['\Cake\ORM\TableRegistry', 'get']);
$stub->modelType('Table');
$result = $stub->loadModel();
@@ -83,7 +83,6 @@ public function testLoadModelPlugin()
{
$stub = new Stub();
$stub->setProps('Articles');
$stub->modelFactory('Table', ['\Cake\ORM\TableRegistry', 'get']);
$stub->modelType('Table');
$result = $stub->loadModel('TestPlugin.Comments');
@@ -105,13 +104,13 @@ public function testModelFactory()
$stub = new Stub();
$stub->setProps('Articles');
$stub->modelFactory('Test', function ($name) {
$stub->modelFactory('Table', function ($name) {
$mock = new \StdClass();
$mock->name = $name;
return $mock;
});
$result = $stub->loadModel('Magic', 'Test');
$result = $stub->loadModel('Magic', 'Table');
$this->assertInstanceOf('\StdClass', $result);
$this->assertInstanceOf('\StdClass', $stub->Magic);
$this->assertEquals('Magic', $stub->Magic->name);
@@ -127,7 +126,7 @@ public function testModelType()
$stub = new Stub();
$stub->setProps('Articles');
$stub->modelFactory('Test', function ($name) {
FactoryLocator::add('Test', function ($name) {
$mock = new \StdClass();
$mock->name = $name;
return $mock;
@@ -151,10 +150,17 @@ public function testMissingModelException()
{
$stub = new Stub();
$stub->modelFactory('Test', function ($name) {
FactoryLocator::add('Test', function ($name) {
return false;
});
$stub->loadModel('Magic', 'Test');
}
public function tearDown()
{
FactoryLocator::drop('Test');
parent::tearDown();
}
}

0 comments on commit fccfc6e

Please sign in to comment.
You can’t perform that action at this time.