Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port DumbledORM ResultSet #14

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Features
* Built on top of [PDO](http://php.net/pdo).
* Uses [prepared statements](http://uk.php.net/manual/en/pdo.prepared-statements.php) throughout to protect against [SQL injection](http://en.wikipedia.org/wiki/SQL_injection) attacks.
* Database agnostic. Currently supports SQLite and MySQL. May support others, please give it a try!
* Supports jQuery-like syntax for working with collections of models

Changelog
---------
Expand Down Expand Up @@ -116,7 +117,9 @@ The only differences between using Idiorm and using Paris for querying are as fo

2. The `find_one` and `find_many` methods will return instances of *your model subclass*, instead of the base `ORM` class. Like Idiorm, `find_one` will return a single instance or `false` if no rows matched your query, while `find_many` will return an array of instances, which may be empty if no rows matched.

3. Custom filtering, see next section.
3. The `find_many` method will return an instance of ResultSet instead of an array. See the section on working with result sets.

4. Custom filtering, see next section.

You may also retrieve a count of the number of rows returned by your query. This method behaves exactly like Idiorm's `count` method:

Expand Down Expand Up @@ -372,6 +375,27 @@ Despite this, Paris doesn't provide any built-in support for validation. This is

However, there are several simple ways that you could add validation to your models without any help from Paris. You could override the `save()` method, check the data is valid, and return `false` on failure, or call `parent::save()` on success. You could create your own subclass of the `Model` base class and add your own generic validation methods. Or you could write your own external validation framework which you pass model instances to for checking. Choose whichever approach is most suitable for your own requirements.

### Working with result sets ###

Paris makes it easy to work with collections of model instances, such as those returned by a `find_many` call. Unlike Idiorm, which returns an array of objects, Paris returns a `ResultSet` object. A `ResultSet` object can be used in any way that an array can be used with one additional feature: any method calls made on the `ResultSet` will be called on *all* the objects in the set. Aditionally, such calls will always return the `ResultSet` object itself, making for a fluent interface. This allows for a jQuery-like syntax when working with result sets:

// Instead of this...
$people = Model::factory('Person')->find_many();
foreach ($people as $person) {
$person->age = 50;
$person->save();
}

// ...you can do this
Model::factory('Person')->find_many()
->set('age', 50)
->save();

// Convenient mass-delete
Model::factory('Widget')->filter('expired')->find_many()->delete();

You can use this syntax with any method defined in your model.

### Configuration ###

The only 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. **See [Idiorm's documentation](http://github.com/j4mie/idiorm/) for full details.**
Expand Down
28 changes: 26 additions & 2 deletions paris.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ public function find_one($id=null) {

/**
* Wrap Idiorm's find_many method to return
* an array of instances of the class associated
* a ResultSet of instances of the class associated
* with this wrapper instead of the raw ORM class.
*/
public function find_many() {
return array_map(array($this, '_create_model_instance'), parent::find_many());
return new ResultSet(array_map(array($this, '_create_model_instance'), parent::find_many()));
}

/**
Expand All @@ -134,6 +134,30 @@ public function create($data=null) {
}
}

/**
* A simple class to work with collections of model instances
*/
class ResultSet extends ArrayIterator {

/**
* Call a method on all children of a result set
* This allows fancy jQuery-like construct such as:
*
* Model::factory('Widget')->find_many()
* ->set('field', 'value')
* ->save();
*
* Inspired by DumbledORM
* https://github.com/jasonmoo/DumbledORM/blob/master/dumbledorm.php
*/
public function __call($method, $params = array()) {
foreach ($this as $object) {
call_user_func_array(array($object, $method), $params);
}
return $this;
}
}

/**
* Model base class. Your model objects should extend
* this class. A minimal subclass would look like:
Expand Down
9 changes: 9 additions & 0 deletions test/test_queries.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,5 +195,14 @@ public function authors() {
$expected = "SELECT `author_two`.* FROM `author_two` JOIN `wrote_the_book` ON `author_two`.`id` = `wrote_the_book`.`custom_author_id` WHERE `wrote_the_book`.`custom_book_id` = '1'";
Tester::check_equal("has_many_through relation with custom intermediate model and key names", $expected);

class ResultSetItem extends Model {
}

$items = Model::factory('ResultSetItem')->find_many()
->set('field', 'value')
->save();
$expected = "UPDATE `result_set_item` SET `field` = 'value' WHERE `id` = '1'";
Tester::check_equal("Calling model methods on ResultSet", $expected);

Tester::report();
?>