Skip to content

Instantly share code, notes, and snippets.

@cullymason
Created June 15, 2017 15:23
Show Gist options
  • Save cullymason/05818b3e3ee7096379ec84b7bc6d81a6 to your computer and use it in GitHub Desktop.
Save cullymason/05818b3e3ee7096379ec84b7bc6d81a6 to your computer and use it in GitHub Desktop.
<?php
class ApiController extends Controller
{
public function missingAction($actionID)
{
$request_type = $_SERVER['REQUEST_METHOD'];
/*------
==============
$url STRUCTURE
==============
example: 'api/categories/1'
would translate to:
$url = array('api','categories', *1)
*id is optional and may not be in the url var
-------*/
$url = $_GET['r'];
$url = explode("/", $url);
$modelName = $url[1];
$model = new EmberModel($modelName);
if (count($url) > 2) {
$model->setID($url[2]);
}
//fetch json
if ($request_type == "GET") {
$model->get($_SERVER['QUERY_STRING']);
$model->toJSON();
} // Create New
else if ($request_type == "POST" || $request_type == "PUT") {
$payload = file_get_contents('php://input');
$payload = json_decode($payload, true);
reset($payload);
$payloadKey = key($payload);
$payload = $payload[$payloadKey];
$model->save($payload);
$model->toJSON();
} // Delete
else if ($request_type == "DELETE") {
$model->trash();
}
}
public function actionApi()
{
echo "main action called";
}
public function filters()
{
return array(
'accessControl',
);
}
public function accessRules()
{
return array(
array('allow',
'actions' => array('adminBadge', 'categories'),
'users' => array('@'),
'roles' => array('edit_badge')
),
array('deny',
'actions' => array('adminBadge', 'categories')
),
);
}
}
/*-------------------------------
EmberModel Class
---------------------------------*/
/**
* Class EmberModel
*/
class EmberModel
{
protected $name = null;
protected $substring = null;
protected $id = null;
protected $hasRelationships = false;
protected $relationships = null;
protected $hasTransformations = false;
protected $transformations = null;
protected $results = null;
/**
* I'd love for appropriate Yii models to extend this class
* until then they need to be hardcoded here with this doc:
*
* Model Properties
* ----------------
* Key: pluralized Model Name
* - (string) table
* - (string) singular: the singular version of the model Name
* - (array) transform: replace the column name with another
* - (array) relationships: array of all of the relationship
* --------------
* - modelName: the plural name of the related model
* - type: relationship type (hasMany,hasOne,belongsTo)
* - key: (optional) the foreign key
* - name: (optional) if the model name is special put it here
*/
protected $modelArray = array(
'categories' => array(
'table' => 'tbl_badge_category',
'singular' => 'category',
'relationships' => array(
array('modelName' => 'badges', 'type' => 'hasMany', 'key' => 'category_id'),
array('name' => 'children', 'modelName' => 'categories', 'type' => 'hasMany', 'key' => 'parent')
)
),
'badges' => array(
'table' => 'tbl_badges',
'singular' => 'badge',
'relationships' => array(
array('modelName' => 'resources', 'type' => 'hasMany', 'key' => 'badge_id'),
array('name' => 'quiz', 'modelName' => 'quizzes', 'type' => 'hasOne', 'key' => 'badge_id'),
array('name' => 'mentor', 'modelName' => 'employees', 'type' => 'belongsTo', 'key' => 'mentor_id'),
array('name' => 'category', 'modelName' => 'categories', 'type' => 'belongsTo', 'key' => 'category_id')
),
'transformations' => array(
array('type' => 'ignoreProperty', 'target' => array('parent', 'quiz')),
array('type' => 'defaultValue', 'target' => array('required' => 0))
)
),
'resources' => array(
'table' => 'tbl_badges_resources',
'singular' => 'resource',
'relationships' => array(
array('name' => 'badge', 'modelName' => 'badges', 'type' => 'belongsTo', 'key' => 'badge_id')
)
),
'employees' => array(
'table' => 'tbl_employee',
'singular' => 'employee'
),
'quizzes' => array(
'table' => 'tbl_badge_quiz',
'singular' => 'quiz',
'relationships' => array(
array('modelName' => 'questions', 'type' => 'hasMany', 'key' => 'quiz_id'),
array('name' => 'badge', 'modelName' => 'badges', 'type' => 'belongsTo', 'key' => 'badge_id')
)
),
'questions' => array(
'table' => 'tbl_badge_quiz_question',
'singular' => 'question',
'relationships' => array(
array('modelName' => 'answers', 'type' => 'hasMany', 'key' => 'question_id'),
array('name' => 'quiz', 'modelName' => 'quizzes', 'type' => 'belongsTo', 'key' => 'quiz_id')
)
),
'answers' => array(
'table' => 'tbl_badge_quiz_answer',
'singular' => 'answer',
'relationships' => array(
array('name' => 'question', 'modelName' => 'questions', 'type' => 'belongsTo', 'key' => 'question_id')
),
'transformations' => array(
array('type' => 'columnName', 'target' => array('content' => 'text')),
array('type' => 'defaultValue', 'target' => array('correct_answer' => 0))
)
)
);
/**
* constructor that reads $modelArray and builds the class based on the passed $modelName
*
* @param string $modelName name of the model you would want to collect
*/
public function __construct($modelName)
{
if ($this->modelExists($modelName)) {
$this->name = $modelName;
$this->singular = $this->modelArray[$this->name]['singular'];
$this->table = $this->modelArray[$this->name]['table'];
$this->key = $this->singular . '_id';
if (array_key_exists('relationships', $this->modelArray[$this->name])) {
$this->relationships = array();
$this->hasRelationships = true;
$this->relationships = $this->parseRelationships();
} else {
$this->relationships = false;
}
if (array_key_exists('transformations', $this->modelArray[$this->name])) {
$this->hasTransformations = true;
$this->transformations = $this->parseTransformations();
} else {
$this->transformations = false;
}
}
}
/**
* sets the id of the model
*
* @param number $id id of the model
*/
public function setID($id)
{
$this->id = $id;
}
/**
* decides if the record needs to be updated or created
*
* @param array $payload associative array that follows $column=>$value
*/
public function save($payload)
{
$payload = $this->clean($payload);
if (isset($this->id)) {
$this->update($payload);
} else {
$this->create($payload);
}
}
/**
* parses the url, loads the substring, then fetches the query results
*
* @param string $url the entire query string from the url
*
*/
public function get($url)
{
$model = $this->parseURL($url);
$this->substring = $model->substring;
$this->results = $this->fetch();
}
/**
* inserts new record into database
*
* @param array $propertiesArray associative array that follows $column=>$value
*
*/
protected function create($propertiesArray)
{
$command = Yii::app()->db->createCommand();
$result = $command->insert($this->table, $propertiesArray);
$this->id = Yii::app()->db->getLastInsertID();
$this->results = $this->fetch();
}
/**
* updates record in database
*
* @param array $propertiesArray associative array that follows $column=>$value
*
*/
protected function update($propertiesArray)
{
$id = $this->id;
$key = ':' . $this->key;
$params = array($key => $id);
$command = Yii::app()->db->createCommand();
$result = $command->update($this->table, $propertiesArray, $this->key . '=' . $key, $params);
$this->results = $this->fetch();
}
/**
* deletes a record
*/
public function trash()
{
$id = $this->id;
$key = ':' . $this->key;
$params = array($key => $id);
$command = Yii::app()->db->createCommand();
$command->delete($this->table, $this->key . '=' . $key, $params);
echo "200";
}
/**
* "cleans" the properties array. removes anything mentioned in the ignore array
* for the model. If any of the relationship's type is "belongsTo", the "_id" is added back
* that Ember removed.
*
* @param array $propertiesArray associative array that follows $column=>$value
* @return array $propertiesArray
*/
protected function clean($propertiesArray)
{
if ($this->hasRelationships) {
foreach ($this->relationships as $relationship) {
if ($relationship->type == 'belongsTo') {
$newKey = $relationship->keyName;
$tempValue = $propertiesArray[$relationship->name];
$propertiesArray[$newKey] = $tempValue;
unset($propertiesArray[$relationship->name]);
}
}
}
if ($this->hasTransformations) {
foreach ($this->transformations as $transformation) {
switch ($transformation->type) {
case "columnName":
foreach ($transformation->target as $oldColumnName => $newColumnName) {
$propertiesArray[$newColumnName] = $propertiesArray[$oldColumnName];
unset($propertiesArray[$oldColumnName]);
}
break;
case "ignoreProperty":
foreach ($transformation->target as $property) {
unset($propertiesArray[$property]);
}
break;
case "defaultValue":
foreach ($transformation->target as $columnName => $defaultValue) {
if ($propertiesArray[$columnName] == "" || $propertiesArray[$columnName] == null) {
$propertiesArray[$columnName] = $defaultValue;
}
}
break;
}
}
}
return $propertiesArray;
}
/**
* reads the "relationship" array out of $modelArray for the given $modelName
* and puts sets them into the object $relationships property
*
* @return array $relationships array of object relationships
*/
private function parseRelationships()
{
$relationships = $this->modelArray[$this->name]['relationships'];
$tempArray = array();
foreach ($relationships as $relationship) {
$tempRelationship = new stdClass;
// set name
if (array_key_exists('name', $relationship)) {
$tempRelationship->name = $relationship['name'];
} else {
if ($relationship['type'] == 'hasMany') {
$tempRelationship->name = $relationship['modelName'];
} else {
$tempRelationship->name = $this->modelArray[$relationship['modelName']]['singular'];
}
}
// relationship model
$tempRelationship->model = $relationship['modelName'];
// set type
$tempRelationship->type = $relationship['type'];
// set table
$tempRelationship->table = $this->modelArray[$relationship['modelName']]['table'];
//set key
$tempRelationship->key = $this->modelArray[$relationship['modelName']]['singular'] . '_id';
// set keyName
if (array_key_exists('key', $relationship)) {
$tempRelationship->keyName = $relationship['key'];
} else {
$tempKeyName = $relationship['singular'];
$tempKeyName = $tempKeyName . '_id';
$tempRelationship->keyName = $tempKeyName;
}
array_push($tempArray, $tempRelationship);
unset($tempRelationship);
}
$relationships = $tempArray;
return $relationships;
}
/**
* Parses a transform array;
*
* @return array $transformations array of transformation objects
**/
protected function parseTransformations()
{
$transformations = $this->modelArray[$this->name]['transformations'];
$tempArray = array();
foreach ($transformations as $transformation) {
$tempTransformation = new stdClass;
$tempTransformation->type = $transformation['type'];
$tempTransformation->target = $transformation['target'];
array_push($tempArray, $tempTransformation);
}
$transformations = $tempArray;
return $transformations;
}
/**
* determines if the given model exists
*
* @param string $model model name (plural)
* @return boolean
*/
private function modelExists($model)
{
if (array_key_exists($model, $this->modelArray)) {
return true;
} else {
return false;
}
}
/**
* Return data to browser as JSON and end application.
*
* @internal param array $data
*/
public function toJSON()
{
header('Content-type: application/json');
if ($this->id) {
$name = $this->singular;
} else {
$name = $this->name;
}
$results = $this->results;
$results = CJSON::encode(array($name => $results));
echo $results;
foreach (Yii::app()->log->routes as $route) {
if ($route instanceof CWebLogRoute) {
$route->enabled = false; // disable any weblogroutes
}
}
Yii::app()->end();
}
/**
* runs select sql statement against model properties
* returns array $results
*/
private function fetch()
{
$results = false;
if ($this->id) {
$results = Yii::app()->db->createCommand()->select('*')->from($this->table)->where($this->key . '=' . $this->id)->queryRow();
if ($this->hasRelationships) {
$relationships = $this->fetchRelationships($this->id);
foreach ($relationships as $relationship => $value) {
$results[$relationship] = $value;
}
}
} else if ($this->substring) {
$results = Yii::app()->db->createCommand()->select('*')->from($this->table)->where(array('in', $this->key, $this->substring['ids']))->queryAll();
if ($this->hasRelationships) {
$tempArray = array();
foreach ($results as $result) {
$id = $result[$this->key];
$relationships = $this->fetchRelationships($id);
if (!empty($relationships)) {
foreach ($relationships as $relationship => $value) {
$result[$relationship] = $value;
array_push($tempArray, $result);
}
$results = $tempArray;
}
}
}
} else {
$results = Yii::app()->db->createCommand()->selectDistinct('*')->from($this->table)->queryAll();
if ($this->hasRelationships) {
$tempArray = array();
foreach ($results as $result) {
$id = $result[$this->key];
$relationships = $this->fetchRelationships($id);
foreach ($relationships as $relationship => $value) {
$result[$relationship] = $value;
array_push($tempArray, $result);
}
}
$results = $tempArray;
}
}
return $results;
}
/**
* fetches either an array of relationship ids or just one
*
* @param number $id
* @return array $relationshipArray
*/
private function fetchRelationships($id)
{
/*
SELECT $key FROM $table WHERE $keyname = $id
*/
$relationshipArray = array();
foreach ($this->relationships as $relationship) {
if ($relationship->type == "hasMany") {
$results = Yii::app()->db->createCommand()
->select($relationship->key)
->from($relationship->table)
->where($relationship->keyName . '=' . $id)->queryAll();
$relationshipArray[$relationship->name] = array();
foreach ($results as $result) {
foreach ($result as $r) {
array_push($relationshipArray[$relationship->name], $r);
}
}
} else if ($relationship->type == "hasOne") {
$result = Yii::app()->db->createCommand()
->select($relationship->key)
->from($relationship->table)
->where($relationship->keyName . '=' . $id)->queryRow();
$relationshipArray[$relationship->name] = $result[$relationship->key];
}
}
return $relationshipArray;
}
/**
* reads url and returns a model containing the $substring
* @param array $url
* @return object $model
*/
private function parseURL($url)
{
$model = new stdClass();
parse_str($url, $url);
$r = $url['r'];
$r = explode("/", $r);
if (count($url) > 1) {
unset($url['r']);
$tempArray = array();
foreach ($url as $key => $value) {
$tempArray[$key] = $value;
}
$model->substring = $tempArray;
} else {
$model->substring = false;
}
return $model;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment