Last active
August 29, 2015 14:21
-
-
Save davekiss/e5b16006fd98dfde1e15 to your computer and use it in GitHub Desktop.
Low Level ORM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class API { | |
/** | |
* Create a new section for a given course. | |
* | |
* @return mixed | |
*/ | |
public function create() { | |
$course = WP_Coach_Course::find( 1 ); | |
$section = $course->sections->create(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class WP_Coach_Collection implements IteratorAggregate, JsonSerializable { | |
private $collection = array(); | |
private $owner; | |
private $target_class; | |
private $target_post_type; | |
private static $class_dict = array( | |
'course' => 'WP_Coach_Course', | |
'sections' => 'WP_Coach_Section', | |
'lessons' => 'WP_Coach_Lesson', | |
); | |
/** | |
* Set the collection that should be iterated | |
* @param mixed $collection empty, single WP_Coach_{model}, or array of WP_Coach_{model} | |
*/ | |
public function __construct( $owner, $prop_name ) { | |
$this->owner = $owner; | |
$this->target_class = self::_get_class_from_prop_name( $prop_name ); | |
$this->target_post_type = strtolower( $this->target_class ); | |
$this->collection = self::_get_associated($this->owner, $this->target_class, $this->target_post_type); | |
} | |
/** | |
* [create description] | |
* @return [type] [description] | |
*/ | |
public function create( $args = array() ) { | |
$target = $this->target_class; | |
$owner = $this->owner; | |
$result = $target::create( $args ); | |
update_post_meta($result->ID, '_' . $owner::POST_TYPE . '_id', $owner->ID ); | |
return $result; | |
} | |
/** | |
* Tells the iterator which array to use | |
* during iterations. | |
* | |
* @return [type] [description] | |
*/ | |
public function getIterator() { | |
return new ArrayIterator($this->collection); | |
} | |
/** | |
* Tells the serializer to use the collection when encoding to JSON | |
* | |
* @return array | |
*/ | |
public function jsonSerialize() { | |
return $this->collection; | |
} | |
/** | |
* [_get_class_from_prop_name description] | |
* @param [type] $property [description] | |
* @return [type] [description] | |
*/ | |
private static function _get_class_from_prop_name($property) { | |
return self::$class_dict[$property]; | |
} | |
/** | |
* [_get_associated description] | |
* @return [type] [description] | |
*/ | |
private static function _get_associated($owner, $target_class, $target_post_type) { | |
// Run an association query with meta key | |
$query = array( | |
'posts_per_page' => -1, | |
'post_type' => $target_post_type, | |
'perm' => 'readable', | |
'post_status'=> 'any', | |
'meta_query' => array( | |
array( | |
'key' => '_' . $owner::POST_TYPE . '_id', | |
'value' => $owner->ID, | |
'compare' => '=', | |
), | |
), | |
); | |
$posts = get_posts( $query ); | |
$collection = call_user_func_array( array( 'self', 'init_instance' ) , array($posts, $target_class) ); | |
return $collection; | |
} | |
/** | |
* Creates a new model instance for each of the given | |
* WP_Post objects | |
* | |
* @param mixed $posts empty, single or array of WP_Post | |
* @param string $klass Model name | |
* @return mixed empty, single or array of Model instances | |
*/ | |
private static function init_instance($posts, $klass) { | |
if ( empty( $posts ) ) { | |
return array(); | |
} | |
if ( is_array($posts) ) { | |
$result = array(); | |
foreach( $posts as $post) { | |
$result[] = new $klass($post); | |
} | |
} else { | |
$result = new $klass($post); | |
} | |
return $result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Exit if accessed directly | |
if ( ! defined( 'ABSPATH' ) ) exit; | |
class WP_Coach_Course extends WP_Coach_Model { | |
const POST_TYPE = 'wp_coach_course'; | |
const HAS_MANY = 'sections'; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Exit if accessed directly | |
if ( ! defined( 'ABSPATH' ) ) exit; | |
abstract class WP_Coach_Model { | |
public function __construct( $WP_Post ) { | |
$post_vars = get_object_vars( $WP_Post ); | |
if ( is_array( $post_vars) ) { | |
foreach ($post_vars as $key => $value) { | |
$this->{$key} = $value; | |
} | |
} | |
} | |
/** | |
* Returns a model containing the post | |
* | |
* @param int $id Post ID | |
* @return object | |
*/ | |
public static function find( $id ) { | |
$klass = get_called_class(); | |
$post = get_post( $id ); | |
return new $klass( $post ); | |
} | |
/** | |
* Create a new record for the calling model | |
* | |
* @return object New record | |
*/ | |
public static function create( $args = array() ) { | |
$class_name = get_called_class(); | |
$post_type = strtolower( $class_name ); | |
$id = wp_insert_post( array( | |
'post_status' => 'draft', | |
'post_type' => $post_type, | |
) | |
); | |
if ( $id !== 0 ) { | |
return get_post( $id ); | |
} else { | |
throw new WP_Coach_Exception( __( sprintf('Failed to insert new record for $1%s', $post_type), 'wp-coach') ); | |
} | |
} | |
/** | |
* Check the property being called to determine if we're | |
* trying to return an associated object | |
* | |
* @param string $name Property name | |
* @param mixed $arguments passed arguments | |
* @return [type] [description] | |
*/ | |
public function __get( $prop_name ) { | |
// If it is a normal or cached property, just return it | |
if ( property_exists($this, $prop_name) ) { | |
return; | |
} | |
$class_name = get_class($this); | |
if ( defined($class_name . '::HAS_MANY') && $this::HAS_MANY === $prop_name ) { | |
# We don't want to set the prop name directly on the calling class due | |
# to some nasty recursion that would occur in the collection ($owner property) | |
# | |
# Figure out where we can cache this instead of just returning it. | |
# $this->{$prop_name} = new WP_Coach_Collection($this, $prop_name); | |
return new WP_Coach_Collection($this, $prop_name); | |
} | |
throw new Exception( __('Property does not exist on model', 'wp-coach') ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Exit if accessed directly | |
if ( ! defined( 'ABSPATH' ) ) exit; | |
class WP_Coach_Section extends WP_Coach_Model { | |
const POST_TYPE = 'wp_coach_section'; | |
const BELONGS_TO = 'course'; | |
const HAS_MANY = 'lessons'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment