initial commit of laravel!

This commit is contained in:
Taylor Otwell
2011-06-08 23:45:08 -05:00
commit a188d62105
70 changed files with 6942 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
<?php namespace System\DB\Eloquent;
class Factory {
/**
* Factory for creating new model instances.
*
* @param string $class
* @return object
*/
public static function make($class)
{
// -----------------------------------------------------
// Create a new model instance.
// -----------------------------------------------------
$model = new $class;
// -----------------------------------------------------
// Set the active query instance on the model.
// -----------------------------------------------------
$model->query = \System\DB\Query::table(Meta::table($class));
return $model;
}
}

View File

@@ -0,0 +1,272 @@
<?php namespace System\DB\Eloquent;
class Hydrate {
/**
* Load the array of hydrated models.
*
* @param object $eloquent
* @return array
*/
public static function from($eloquent)
{
// -----------------------------------------------------
// Load the base models.
// -----------------------------------------------------
$results = static::base(get_class($eloquent), $eloquent->query->get());
// -----------------------------------------------------
// Load all of the eager relationships.
// -----------------------------------------------------
if (count($results) > 0)
{
foreach ($eloquent->includes as $include)
{
// -----------------------------------------------------
// Verify the relationship is defined.
// -----------------------------------------------------
if ( ! method_exists($eloquent, $include))
{
throw new \Exception("Attempting to eager load [$include], but the relationship is not defined.");
}
// -----------------------------------------------------
// Eagerly load the relationship.
// -----------------------------------------------------
static::eagerly($eloquent, $include, $results);
}
}
return $results;
}
/**
* Hydrate the base models for a query.
*
* @param string $class
* @param array $models
* @return array
*/
private static function base($class, $models)
{
// -----------------------------------------------------
// Initialize the hydrated model array.
// -----------------------------------------------------
$results = array();
// -----------------------------------------------------
// Hydrate the models from the results.
// -----------------------------------------------------
foreach ($models as $model)
{
// -----------------------------------------------------
// Instantiate a new model instance.
// -----------------------------------------------------
$result = new $class;
// -----------------------------------------------------
// Set the model's attributes.
// -----------------------------------------------------
$result->attributes = (array) $model;
// -----------------------------------------------------
// Indicate that the model already exists.
// -----------------------------------------------------
$result->exists = true;
// -----------------------------------------------------
// Add the hydrated model to the array of models.
// The array is keyed by the primary keys of the models.
// -----------------------------------------------------
$results[$result->id] = $result;
}
return $results;
}
/**
* Eagerly load a relationship.
*
* @param object $eloquent
* @param string $include
* @param array $results
* @return void
*/
private static function eagerly($eloquent, $include, &$results)
{
// -----------------------------------------------------
// Get the relationship Eloquent model.
//
// We spoof the "belongs_to" key to allow the query
// to be fetched without any problems.
// -----------------------------------------------------
$eloquent->attributes[$spoof = $include.'_id'] = 0;
$model = $eloquent->$include();
unset($eloquent->attributes[$spoof]);
// -----------------------------------------------------
// Reset the WHERE clause on the query.
// -----------------------------------------------------
$model->query->where = 'WHERE 1 = 1';
// -----------------------------------------------------
// Reset the bindings on the query.
// -----------------------------------------------------
$model->query->bindings = array();
// -----------------------------------------------------
// Initialize the relationship on the parent models.
// -----------------------------------------------------
foreach ($results as &$result)
{
$result->ignore[$include] = (strpos($eloquent->relating, 'has_many') === 0) ? array() : null;
}
// -----------------------------------------------------
// Eagerly load a 1:1 or 1:* relationship.
// -----------------------------------------------------
if ($eloquent->relating == 'has_one' or $eloquent->relating == 'has_many')
{
static::eagerly_load_one_or_many($eloquent->relating_key, $eloquent->relating, $include, $model, $results);
}
// -----------------------------------------------------
// Eagerly load a 1:1 (belonging) relationship.
// -----------------------------------------------------
elseif ($eloquent->relating == 'belongs_to')
{
static::eagerly_load_belonging($eloquent->relating_key, $include, $model, $results);
}
// -----------------------------------------------------
// Eagerly load a *:* relationship.
// -----------------------------------------------------
else
{
static::eagerly_load_many_to_many($eloquent->relating_key, $eloquent->relating_table, strtolower(get_class($eloquent)).'_id', $include, $model, $results);
}
}
/**
* Eagerly load a 1:1 or 1:* relationship.
*
* @param string $relating_key
* @param string $relating
* @param string $include
* @param object $model
* @param array $results
* @return void
*/
private static function eagerly_load_one_or_many($relating_key, $relating, $include, $model, &$results)
{
// -----------------------------------------------------
// Get the related models.
// -----------------------------------------------------
$inclusions = $model->where_in($relating_key, array_keys($results))->get();
// -----------------------------------------------------
// Match the child models with their parent.
// -----------------------------------------------------
foreach ($inclusions as $key => $inclusion)
{
if ($relating == 'has_one')
{
$results[$inclusion->$relating_key]->ignore[$include] = $inclusion;
}
else
{
$results[$inclusion->$relating_key]->ignore[$include][$inclusion->id] = $inclusion;
}
}
}
/**
* Eagerly load a 1:1 belonging relationship.
*
* @param string $relating_key
* @param string $include
* @param object $model
* @param array $results
* @return void
*/
private static function eagerly_load_belonging($relating_key, $include, $model, &$results)
{
// -----------------------------------------------------
// Gather the keys from the parent models.
// -----------------------------------------------------
$keys = array();
foreach ($results as &$result)
{
$keys[] = $result->$relating_key;
}
// -----------------------------------------------------
// Get the related models.
// -----------------------------------------------------
$inclusions = $model->where_in('id', array_unique($keys))->get();
// -----------------------------------------------------
// Match the child models with their parent.
// -----------------------------------------------------
foreach ($results as &$result)
{
$result->ignore[$include] = $inclusions[$result->$relating_key];
}
}
/**
* Eagerly load a many-to-many relationship.
*
* @param string $relating_key
* @param string $relating_table
* @param string $foreign_key
* @param string $include
* @param object $model
* @param array $results
* @return void
*/
private static function eagerly_load_many_to_many($relating_key, $relating_table, $foreign_key, $include, $model, &$results)
{
// -----------------------------------------------------
// Reset the SELECT clause.
// -----------------------------------------------------
$model->query->select = null;
// -----------------------------------------------------
// Retrieve the raw results as stdClasses.
//
// We also add the foreign key to the select which will allow us
// to match the models back to their parents.
// -----------------------------------------------------
$inclusions = $model->query->where_in($relating_key, array_keys($results))->get(Meta::table(get_class($model)).'.*', $relating_table.'.'.$foreign_key);
// -----------------------------------------------------
// Get the class name of the related model.
// -----------------------------------------------------
$class = get_class($model);
// -----------------------------------------------------
// Create the related models.
// -----------------------------------------------------
foreach ($inclusions as $inclusion)
{
$related = new $class;
$related->exists = true;
$related->attributes = (array) $inclusion;
// -----------------------------------------------------
// Remove the foreign key from the attributes since it
// was only added to the query to help us match the models.
// -----------------------------------------------------
unset($related->attributes[$foreign_key]);
// -----------------------------------------------------
// Add the related model to the parent model's array.
// -----------------------------------------------------
$results[$inclusion->$foreign_key]->ignore[$include][$inclusion->id] = $related;
}
}
}

View File

@@ -0,0 +1,24 @@
<?php namespace System\DB\Eloquent;
class Meta {
/**
* Get the table name for a model.
*
* @param string $class
* @return string
*/
public static function table($class)
{
// -----------------------------------------------------
// Check for a table name override.
// -----------------------------------------------------
if (property_exists($class, 'table'))
{
return $class::$table;
}
return \System\Str::lower(\System\Inflector::plural($class));
}
}

View File

@@ -0,0 +1,132 @@
<?php namespace System\DB\Eloquent;
class Relate {
/**
* Retrieve the query for a 1:1 relationship.
*
* @param string $model
* @param object $eloquent
* @return mixed
*/
public static function has_one($model, $eloquent)
{
// -----------------------------------------------------
// Set the relating type.
// -----------------------------------------------------
$eloquent->relating = __FUNCTION__;
// -----------------------------------------------------
// Return the Eloquent model.
// -----------------------------------------------------
return static::has_one_or_many($model, $eloquent);
}
/**
* Retrieve the query for a 1:* relationship.
*
* @param string $model
* @param object $eloquent
* @return mixed
*/
public static function has_many($model, $eloquent)
{
// -----------------------------------------------------
// Set the relating type.
// -----------------------------------------------------
$eloquent->relating = __FUNCTION__;
// -----------------------------------------------------
// Return the Eloquent model.
// -----------------------------------------------------
return static::has_one_or_many($model, $eloquent);
}
/**
* Retrieve the query for a 1:1 or 1:* relationship.
*
* @param string $model
* @param object $eloquent
* @return mixed
*/
private static function has_one_or_many($model, $eloquent)
{
// -----------------------------------------------------
// Set the relating key.
// -----------------------------------------------------
$eloquent->relating_key = \System\Str::lower(get_class($eloquent)).'_id';
return Factory::make($model)->where($eloquent->relating_key, '=', $eloquent->id);
}
/**
* Retrieve the query for a 1:1 belonging relationship.
*
* @param array $caller
* @param string $model
* @param object $eloquent
* @return mixed
*/
public static function belongs_to($caller, $model, $eloquent)
{
// -----------------------------------------------------
// Set the relating type.
// -----------------------------------------------------
$eloquent->relating = __FUNCTION__;
// -----------------------------------------------------
// Set the relating key.
// -----------------------------------------------------
$eloquent->relating_key = $caller['function'].'_id';
// -----------------------------------------------------
// Return the Eloquent model.
// -----------------------------------------------------
return Factory::make($model)->where('id', '=', $eloquent->attributes[$eloquent->relating_key]);
}
/**
* Retrieve the query for a *:* relationship.
*
* @param string $model
* @param object $eloquent
* @return mixed
*/
public static function has_many_and_belongs_to($model, $eloquent)
{
// -----------------------------------------------------
// Get the models involved in the relationship.
// -----------------------------------------------------
$models = array(\System\Str::lower($model), \System\Str::lower(get_class($eloquent)));
// -----------------------------------------------------
// Sort the model names involved in the relationship.
// -----------------------------------------------------
sort($models);
// -----------------------------------------------------
// Get the intermediate table name, which is the names
// of the two related models alphabetized.
// -----------------------------------------------------
$eloquent->relating_table = implode('_', $models);
// -----------------------------------------------------
// Set the relating type.
// -----------------------------------------------------
$eloquent->relating = __FUNCTION__;
// -----------------------------------------------------
// Set the relating key.
// -----------------------------------------------------
$eloquent->relating_key = $eloquent->relating_table.'.'.\System\Str::lower(get_class($eloquent)).'_id';
// -----------------------------------------------------
// Return the Eloquent model.
// -----------------------------------------------------
return Factory::make($model)
->select(Meta::table($model).'.*')
->join($eloquent->relating_table, Meta::table($model).'.id', '=', $eloquent->relating_table.'.'.\System\Str::lower($model).'_id')
->where($eloquent->relating_key, '=', $eloquent->id);
}
}

View File

@@ -0,0 +1,66 @@
<?php namespace System\DB\Eloquent;
class Warehouse {
/**
* Save an Eloquent model to the database.
*
* @param object $eloquent
* @return void
*/
public static function store($eloquent)
{
// -----------------------------------------------------
// Get the model name.
// -----------------------------------------------------
$model = get_class($eloquent);
// -----------------------------------------------------
// Get a fresh query instance for the model.
// -----------------------------------------------------
$eloquent->query = \System\DB\Query::table(Meta::table($model));
// -----------------------------------------------------
// Set the activity timestamps.
// -----------------------------------------------------
if (property_exists($model, 'timestamps') and $model::$timestamps)
{
static::timestamp($eloquent);
}
// -----------------------------------------------------
// If the model exists in the database, update it.
// Otherwise, insert the model and set the ID.
// -----------------------------------------------------
if ($eloquent->exists)
{
return $eloquent->query->where('id', '=', $eloquent->attributes['id'])->update($eloquent->dirty);
}
else
{
$eloquent->attributes['id'] = $eloquent->query->insert_get_id($eloquent->attributes);
}
// -----------------------------------------------------
// Set the existence flag to true.
// -----------------------------------------------------
$eloquent->exists = true;
}
/**
* Set the activity timestamps on a model.
*
* @param object $eloquent
* @return void
*/
private static function timestamp($eloquent)
{
$eloquent->updated_at = date('Y-m-d H:i:s');
if ( ! $eloquent->exists)
{
$eloquent->created_at = $eloquent->updated_at;
}
}
}