d1rk
9/20/2012 - 10:58 AM

MongoDB-based model accessors (relationships) in Lithium

MongoDB-based model accessors (relationships) in Lithium

<?php

use my_app\models\Posts;

$post = Posts::first();
$author = $post->author();
$comments = $post->comments();

// $post == $comments->first()->post();

?>
<?php

namespace my_app\models;

class Posts extends Base {


	protected $_schema = array(
		'author' => array('type' => 'id')
	);

	public function author($post) {
		return $this->_accessor($post, __FUNCTION__, 'Users');
	}

	/**
	 * Note: realistically, you'd want comments to be an embedded array, this is just an example.
	 */
	public function comments($post) {
		return $this->_accessor($post, __FUNCTION__, 'Comments', array('find' => 'all'));
	}
}

?>
<?php

namespace my_app\models;

class Comments extends Base {


	protected $_schema = array(
		'post' => array('type' => 'id')
	);

	public function post($comment) {
		return $this->_accessor($comment, __FUNCTION__, 'Posts', array('find' => 'all'));
	}
}

?>
<?php

namespace my_app\models;

use MongoId;
use lithium\data\collection\DocumentArray;
use lithium\data\collection\DocumentSet;
use lithium\data\entity\Document;
use lithium\util\Inflector;
use lithium\core\Libraries;
use lithium\util\Set;

class Base extends \lithium\data\Model {

	protected function _accessor($entity, $key, $model, array $options = array()) {
		$defaults = array('find' => 'first', 'key' => '_id');
		$options += $defaults;
		$find = $options['find'];
		$model = Libraries::locate('models', $model);
		$query = array_diff_key($options, $defaults);

		if (!$entity->{$key}) {
			return;
		}
		$val = $entity->{$key};

		if ($val instanceof DocumentArray || $val instanceof Document) {
			$val = $val->data();
		}

		if ($val instanceof MongoId || is_string($val) || is_array($val)) {
			$conditions = array($options['key'] => $val);
			return $model::$find(Set::merge(compact('conditions'), $query));
		}
	}
}

?>