Skip to content

Commit

Permalink
Allow a prefix for model class names
Browse files Browse the repository at this point in the history
  • Loading branch information
treffynnon committed Jan 29, 2013
1 parent 219e92a commit 0ca5d55
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 43 deletions.
22 changes: 12 additions & 10 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,28 @@ Changelog

#### 1.3.0 - released XXXX-XX-XX

* Add support for multiple database connections
* Documentation moved to [paris.rtfd.org](http://paris.rtfd.org) and now built using [Sphinx](http://sphinx-doc.org/)
* Add support for multiple database connections - closes [issue #15](https://github.com/j4mie/idiorm/issues/15) [[tag](https://github.com/tag)]
* Allow a prefix for model class names - see Configuration in the documentation - closes [issues #33](https://github.com/j4mie/paris/issues/33)
* Exclude tests and git files from git exports (used by composer)
* Update included Idiorm version for tests
* Implement `set_expr` - closes issue #39
* Add `is_new` - closes issue #40
* Add support for the new IdiormResultSet object
* Change Composer to use a classmap so that autoloading is better supported [[javierd](https://github.com/javiervd)] - issue #44
* Implement `set_expr` - closes [issue #39](https://github.com/j4mie/paris/issues/39)
* Add `is_new` - closes [issue #40](https://github.com/j4mie/paris/issues/40)
* Add support for the new IdiormResultSet object in Idiorm - closes [issue #14](https://github.com/j4mie/paris/issues/14)
* Change Composer to use a classmap so that autoloading is better supported [[javierd](https://github.com/javiervd)] - [issue #44](https://github.com/j4mie/paris/issues/44)
* Move tests into PHPUnit to match Idiorm
* Update included Idiorm version for tests
* Move documentation to use Sphinx

#### 1.2.0 - released 2012-11-14

* Setup composer for installation via packagist (j4mie/paris)
* Add in basic namespace support, see issue #20
* Allow properties to be set as an associative array in `set()`, see issue #13
* Patch in idiorm now allows empty models to be saved (j4mie/idiorm see issue #58)
* Add in basic namespace support, see [issue #20](https://github.com/j4mie/paris/issues/20)
* Allow properties to be set as an associative array in `set()`, see [issue #13](https://github.com/j4mie/paris/issues/13)
* Patch in idiorm now allows empty models to be saved (j4mie/idiorm see [issue #58](https://github.com/j4mie/paris/issues/58))

#### 1.1.1 - released 2011-01-30

* Fix incorrect tests, see issue #12
* Fix incorrect tests, see [issue #12](https://github.com/j4mie/paris/issues/12)

#### 1.1.0 - released 2011-01-24

Expand Down
33 changes: 30 additions & 3 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,37 @@ For example, if you are using MySQL:
ORM::configure('username', 'database_user');
ORM::configure('password', 'top_secret');

Configuration
~~~~~~~~~~~~~
Model prefixing
~~~~~~~~~~~~~~~

Setting: ``Model::$auto_prefix_models``

To save having type out model class name prefixes whenever code utilises ``Model::for_table()``
it is possible to specify a prefix that will be prepended onto the class name.

The model prefix is treated the same way as any other class name when Paris
attempts to convert it to a table name. This is documented in the :doc:`Models`
section of the documentation.

Here is a namespaced example to make it clearer:

::

Model::$auto_prefix_models = '\\Tests\\';
Model::factory('Simple')->find_many(); // SQL executed: SELECT * FROM `tests_simple`
Model::factory('SimpleUser')->find_many(); // SQL executed: SELECT * FROM `tests_simple_user`

.. note::

It is possible to define the table name by setting ``$_table`` in your
individual model classes. As documented in the :doc:`Models` section of
the documentation.


Further Configuration
~~~~~~~~~~~~~~~~~~~~~

The only configuration options provided by Paris itself are the
The only other configuration options provided by Paris itself are the
``$_table`` and ``$_id_column`` static properties on model classes. To
configure the database connection, you should use Idiorm’s configuration
system via the ``ORM::configure`` method.
Expand Down
13 changes: 13 additions & 0 deletions docs/models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ your table names are in *lowercase\_with\_underscores* style. It will
convert between the two automatically. For example, if your class is
called ``CarTyre``, Paris will look for a table named ``car_tyre``.

If you are using namespaces then they will be converted to a table name
in a similar way. For example ``\\Models\\CarTyre`` would be converted to
``models_car_tyre``. Note here that backslashes are replaced with underscores
in addition to the *CapWords* replacement discussed in the previous paragraph.

To override this default behaviour, add a **public static** property to
your class called ``$_table``:

Expand All @@ -40,6 +45,14 @@ your class called ``$_table``:
public static $_table = 'my_user_table';
}

Auto Prefixing
^^^^^^^^^^^^^^

To save having type out model class name prefixes whenever code utilises ``Model::for_table()``
it is possible to specify a prefix that will be prepended onto the class name.

See the :doc:`Configuration` documentation for more details.

ID Column
~~~~~~~~~

Expand Down
13 changes: 11 additions & 2 deletions paris.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ class Model {
// Default foreign key suffix used by relationship methods
const DEFAULT_FOREIGN_KEY_SUFFIX = '_id';

/**
* Set a prefix for model names. This can be a namespace or any other
* abitrary prefix such as the PEAR naming convention.
* @example Model::$auto_prefix_models = 'MyProject_MyModels_'; //PEAR
* @example Model::$auto_prefix_models = '\MyProject\MyModels\'; //Namespaces
* @var string
*/
public static $auto_prefix_models = null;

/**
* The ORM instance used by this model
* instance to communicate with the database.
Expand Down Expand Up @@ -207,7 +216,7 @@ protected static function _class_name_to_table_name($class_name) {
return strtolower(preg_replace(
array('/\\\\/', '/(?<=[a-z])([A-Z])/', '/__/'),
array('_', '_$1', '_'),
$class_name
ltrim($class_name, '\\')
));
}

Expand Down Expand Up @@ -242,7 +251,7 @@ protected static function _build_foreign_key_name($specified_foreign_key_name, $
* its find_one or find_many methods are called.
*/
public static function factory($class_name, $connection_name = null) {

$class_name = self::$auto_prefix_models . $class_name;
$table_name = self::_get_table_name($class_name);

if ($connection_name == null) {
Expand Down
58 changes: 58 additions & 0 deletions test/ModelPrefixingTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

class ModelPrefixingTest extends PHPUnit_Framework_TestCase {

public function setUp() {
// Set up the dummy database connection
ORM::set_db(new MockPDO('sqlite::memory:'));

// Enable logging
ORM::configure('logging', true);

Model::$auto_prefix_models = null;
}

public function tearDown() {
ORM::configure('logging', false);
ORM::set_db(null);

Model::$auto_prefix_models = null;
}

public function testStaticPropertyExists() {
$this->assertClassHasStaticAttribute('auto_prefix_models', 'Model');
$this->assertInternalType('null', Model::$auto_prefix_models);
}

public function testSettingAndUnsettingStaticPropertyValue() {
$model_prefix = 'My_Model_Prefix_';
$this->assertInternalType('null', Model::$auto_prefix_models);
Model::$auto_prefix_models = $model_prefix;
$this->assertInternalType('string', Model::$auto_prefix_models);
$this->assertEquals($model_prefix, Model::$auto_prefix_models);
Model::$auto_prefix_models = null;
$this->assertInternalType('null', Model::$auto_prefix_models);
}

public function testNoPrefixOnAutoTableName() {
Model::$auto_prefix_models = null;
Model::factory('Simple')->find_many();
$expected = 'SELECT * FROM `simple`';
$this->assertEquals($expected, ORM::get_last_query());
}

public function testPrefixOnAutoTableName() {
Model::$auto_prefix_models = 'MockPrefix_';
Model::factory('Simple')->find_many();
$expected = 'SELECT * FROM `mock_prefix_simple`';
$this->assertEquals($expected, ORM::get_last_query());
}

public function testPrefixOnAutoTableNameWithTableSpecified() {
Model::$auto_prefix_models = 'MockPrefix_';
Model::factory('TableSpecified')->find_many();
$expected = 'SELECT * FROM `simple`';
$this->assertEquals($expected, ORM::get_last_query());
}

}
73 changes: 73 additions & 0 deletions test/ModelPrefixingTest53.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace Paris\Tests {
use ORM, Model, MockPDO, PHPUnit_Framework_TestCase;

class ModelPrefixingTest53 extends PHPUnit_Framework_TestCase {

public function setUp() {
// Set up the dummy database connection
ORM::set_db(new MockPDO('sqlite::memory:'));

// Enable logging
ORM::configure('logging', true);

Model::$auto_prefix_models = null;
}

public function tearDown() {
ORM::configure('logging', false);
ORM::set_db(null);

Model::$auto_prefix_models = null;
}

public function testNoPrefixOnAutoTableName() {
Model::$auto_prefix_models = null;
Model::factory('\Tests\Simple')->find_many();
$expected = 'SELECT * FROM `tests_simple`';
$this->assertEquals($expected, ORM::get_last_query());
}

public function testPrefixOnAutoTableName() {
Model::$auto_prefix_models = '\\Tests\\';
Model::factory('Simple')->find_many();
$expected = 'SELECT * FROM `tests_simple`';
$this->assertEquals($expected, ORM::get_last_query());
}

public function testPrefixOnAutoTableNameWithTableSpecified() {
Model::$auto_prefix_models = '\\Tests\\';
Model::factory('TableSpecified')->find_many();
$expected = 'SELECT * FROM `simple`';
$this->assertEquals($expected, ORM::get_last_query());
}

public function testNamespacePrefixSwitching() {
Model::$auto_prefix_models = '\\Tests\\';
Model::factory('TableSpecified')->find_many();
$expected = 'SELECT * FROM `simple`';
$this->assertEquals($expected, ORM::get_last_query());

Model::$auto_prefix_models = '\\Tests2\\';
Model::factory('TableSpecified')->find_many();
$expected = 'SELECT * FROM `simple`';
$this->assertEquals($expected, ORM::get_last_query());
}
}
}

namespace Tests {
use ORM, Model, MockPDO;
class Simple extends Model { }
class TableSpecified extends Model {
public static $_table = 'simple';
}
}
namespace Tests2 {
use ORM, Model, MockPDO;
class Simple extends Model { }
class TableSpecified extends Model {
public static $_table = 'simple';
}
}
47 changes: 47 additions & 0 deletions test/MultipleConnectionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

class MultipleConnectionsTest extends PHPUnit_Framework_TestCase {

const ALTERNATE = 'alternate';

public function setUp() {

// Set up the dummy database connection
ORM::set_db(new MockPDO('sqlite::memory:'));
ORM::set_db(new MockDifferentPDO('sqlite::memory:'), self::ALTERNATE);

// Enable logging
ORM::configure('logging', true);
ORM::configure('logging', true, self::ALTERNATE);
}

public function tearDown() {
ORM::configure('logging', false);
ORM::configure('logging', false, self::ALTERNATE);

ORM::set_db(null);
ORM::set_db(null, self::ALTERNATE);
}

public function testMultipleConnections() {
$simple = Model::factory('Simple')->find_one(1);
$statement = ORM::get_last_statement();
$this->assertInstanceOf('MockPDOStatement', $statement);

$simple = Model::factory('Simple', self::ALTERNATE); // Change the object's default connection
$simple->find_one(1);
$statement = ORM::get_last_statement();
$this->assertInstanceOf('MockDifferentPDOStatement', $statement);

$temp = Model::factory('Simple', self::ALTERNATE)->find_one(1);
$statement = ORM::get_last_statement();
$this->assertInstanceOf('MockDifferentPDOStatement', $statement);
}

public function testCustomConnectionName() {
$person3 = Model::factory('ModelWithCustomConnection')->find_one(1);
$statement = ORM::get_last_statement();
$this->assertInstanceOf('MockDifferentPDOStatement', $statement);
}

}
28 changes: 1 addition & 27 deletions test/ParisTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,16 @@ class ParisTest extends PHPUnit_Framework_TestCase {
const ALTERNATE = 'alternate';

public function setUp() {

// Set up the dummy database connection
ORM::set_db(new MockPDO('sqlite::memory:'));
ORM::set_db(new MockDifferentPDO('sqlite::memory:'), self::ALTERNATE);

// Enable logging
ORM::configure('logging', true);
ORM::configure('logging', true, self::ALTERNATE);
}

public function tearDown() {
ORM::configure('logging', false);
ORM::configure('logging', false, self::ALTERNATE);

ORM::set_db(null);
ORM::set_db(null, self::ALTERNATE);
}

public function testSimpleAutoTableName() {
Expand Down Expand Up @@ -153,24 +147,4 @@ public function testHasManyThroughRelationWithCustomIntermediateModelAndKeyNames
$this->assertEquals($expected, ORM::get_last_query());
}

public function testMultipleConnections() {
$simple = Model::factory('Simple')->find_one(1);
$statement = ORM::get_last_statement();
$this->assertInstanceOf('MockPDOStatement', $statement);

$simple = Model::factory('Simple', self::ALTERNATE); // Change the object's default connection
$simple->find_one(1);
$statement = ORM::get_last_statement();
$this->assertInstanceOf('MockDifferentPDOStatement', $statement);

$temp = Model::factory('Simple', self::ALTERNATE)->find_one(1);
$statement = ORM::get_last_statement();
$this->assertInstanceOf('MockDifferentPDOStatement', $statement);
}

public function testCustomConnectionName() {
$person3 = Model::factory('ModelWithCustomConnection')->find_one(1);
$statement = ORM::get_last_statement();
$this->assertInstanceOf('MockDifferentPDOStatement', $statement);
}
}
}
6 changes: 5 additions & 1 deletion test/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,8 @@ class BookTwo extends Model {
public function authors() {
return $this->has_many_through('Author', 'AuthorBook', 'custom_book_id', 'custom_author_id');
}
}
}
class MockPrefix_Simple extends Model { }
class MockPrefix_TableSpecified extends Model {
public static $_table = 'simple';
}

0 comments on commit 0ca5d55

Please sign in to comment.