Created
January 10, 2019 23:53
-
-
Save tyaslab/22478923c2f360aa03f6efe7037c46e5 to your computer and use it in GitHub Desktop.
Yii Components
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 | |
namespace app\components; | |
class ActiveRecord extends \yii\db\ActiveRecord { | |
public function saveRelatedModel($modelClass, $data, $relatedPk, $removable=TRUE) { | |
$pk = static::primaryKey()[0]; | |
$modelPk = call_user_func([$modelClass, 'primaryKey'])[0]; | |
if ($removable) { | |
// if data is empty then remove all related | |
if (count($data) == 0) { | |
$objectList = call_user_func([$modelClass, 'find'])->where([ | |
$relatedPk => $this->$pk | |
])->all(); | |
// remove all related | |
foreach ($objectList as $object) { | |
$object->delete(); | |
} | |
return TRUE; | |
} | |
// delete if not exist in pk_in_data | |
$pkInData = []; | |
foreach ($data as $d) { | |
if (isset($d[$modelPk]) && $d[$modelPk]) { | |
array_push($pkInData, $d[$modelPk]); | |
} | |
} | |
$objectToDeleteList = call_user_func([$modelClass, 'find'])->where( | |
['not in', $modelPk, $pkInData] | |
)->andWhere(['=', $relatedPk, $this->$pk])->all(); | |
foreach ($objectToDeleteList as $otd) { | |
$otd->delete(); | |
} | |
} | |
// save data | |
foreach ($data as $d) { | |
if (isset($d[$modelPk]) && $d[$modelPk]) { | |
$object = call_user_func_array([$modelClass, 'findOne'], [$d[$modelPk]]); | |
if (!$object) { | |
continue; | |
} | |
} else { | |
$object = new $modelClass(); | |
} | |
$object->load($d, ''); | |
$object->$relatedPk = $this->id; | |
$object->save(); | |
} | |
} | |
public function addRelatedModel($modelClass, $data, $relatedPk) { | |
$this->saveRelatedModel($modelClass, [], $relatedPk, FALSE); | |
} | |
public function clearRelatedModel($modelClass, $relatedPk) { | |
$this->saveRelatedModel($modelClass, [], $relatedPk, TRUE); | |
} | |
public function saveRelated($data, $viaTable, $modelPk, $relatedPk, $removable=TRUE) { | |
if ($removable) { | |
if (count($data) == 0) { | |
// remove all | |
\Yii::$app->db->createCommand() | |
->delete($viaTable, "{$modelPk} = :modelPk") | |
->bindValue(':modelPk', $this->id) | |
->execute(); | |
return; | |
} | |
$implodedData = '(' . implode(', ', $data) . ')'; | |
\Yii::$app->db->createCommand() | |
->delete($viaTable, "{$modelPk} = :modelPk AND {$relatedPk} NOT IN {$implodedData}") | |
->bindValue(':modelPk', $this->id) | |
->execute(); | |
} | |
// insert if new | |
foreach ($data as $d) { | |
$query = new \yii\db\Query(); | |
$dataExists = $query | |
->from($viaTable) | |
->where([ | |
$modelPk => $this->id, | |
$relatedPk => $d | |
]) | |
->exists(); | |
if (!$dataExists) { | |
\Yii::$app->db->createCommand()->insert($viaTable, [ | |
$modelPk => $this->id, | |
$relatedPk => $d | |
])->execute(); | |
} | |
} | |
} | |
public function addRelated($data, $viaTable, $modelPk, $relatedPk) { | |
return $this->saveRelated($data, $viaTable, $modelPk, $relatedPk, FALSE); | |
} | |
public function clearRelated($viaTable, $modelPk) { | |
// no use $relatedPk so I simply add null | |
return $this->saveRelated([], $viaTable, $modelPk, NULL, TRUE); | |
} | |
} |
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 | |
namespace app\components; | |
use yii\web\Controller; | |
class ApiController extends Controller { | |
public $modelClass = NULL; | |
public $object = NULL; | |
public $limit = 10; | |
public $offset = 0; | |
public $limitArg = 'limit'; | |
public $offsetArg = 'offset'; | |
public $orderArg = 'order'; | |
public $dirArg = 'dir'; | |
public $searchArg = 'search'; | |
public $enableCsrfValidation = FALSE; | |
public $user = NULL; | |
public $returnObjectAfterSave = TRUE; | |
public $scenario = \yii\base\Model::SCENARIO_DEFAULT; | |
public function __construct($id, $module, $config = []) { | |
parent::__construct($id, $module, $config); | |
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; | |
} | |
public function getData() { | |
$data = json_decode(\Yii::$app->request->getRawBody(), true); | |
return $data; | |
} | |
public function actionList() { | |
if (!\Yii::$app->request->isGet) throw new \yii\web\MethodNotAllowedHttpException(); | |
$this->checkAuthentication(); | |
$this->checkPermission(); | |
$limit = $this->getLimit(); | |
$offset = $this->getOffset(); | |
$objectList = $this->getObjectList(); | |
$order = $this->getOrder(); | |
// TODO: validate ordering field | |
if ($order) { | |
$objectList = $objectList->orderBy($order); | |
} | |
$search = $this->getSearch(); | |
if ($search) { | |
$this->searchResult($objectList, $search); | |
} | |
$this->filterResult($objectList); | |
$total = $objectList->count(); | |
$objectList = $objectList->limit($limit)->offset($offset)->all(); | |
$result = []; | |
foreach ($objectList as $object) { | |
array_push($result, $this->toJson($object)); | |
} | |
return $this->finish([ | |
'limit' => (int) $limit, | |
'offset' => (int) $offset, | |
'order' => $order, | |
'total' => (int) $total, | |
// 'total' => (int) $this->getTotal(), | |
'data' => $result | |
]); | |
} | |
public function actionDetail($id) { | |
if (\Yii::$app->request->isPut) return $this->actionUpdate($id); | |
if (\Yii::$app->request->isDelete) return $this->actionDelete($id); | |
if (!\Yii::$app->request->isGet) throw new \yii\web\MethodNotAllowedHttpException(); | |
$this->checkAuthentication(); | |
$this->checkPermission(); | |
$object = $this->getObjectDetail($id); | |
$this->object = $object; | |
if (!$object) { | |
throw new \yii\web\HttpException(404, 'Object not found'); | |
} | |
$this->checkObjectPermission($object); | |
return $this->finish($this->toJson($object)); | |
} | |
public function actionCreate() { | |
if (!\Yii::$app->request->isPost) throw new \yii\web\MethodNotAllowedHttpException(); | |
$this->checkAuthentication(); | |
$this->checkPermission(); | |
$object = new $this->modelClass(); | |
$this->object = $object; | |
$data = $this->getData(); | |
$object->load($data, ''); | |
$object->scenario = $this->getScenario(); | |
if ($object->validate()) { | |
$object = $this->saveObject($object, $data); | |
if ($this->returnObjectAfterSave) { | |
\Yii::$app->response->setStatusCode(200); | |
return $this->finish($this->toJson($object)); | |
} else { | |
// created, no content | |
\Yii::$app->response->setStatusCode(204); | |
\Yii::$app->response->headers->set('Id', $object->id); | |
return $this->finish(''); | |
} | |
} else { | |
\Yii::$app->response->setStatusCode(400); | |
return $this->finish($object->errors); | |
} | |
} | |
public function actionUpdate($id) { | |
if (!\Yii::$app->request->isPut) throw new \yii\web\MethodNotAllowedHttpException(); | |
$this->checkAuthentication(); | |
$this->checkPermission(); | |
$object = $this->getObjectDetail($id); | |
$this->object = $object; | |
$this->checkObjectPermission($object); | |
$data = $this->getData(); | |
$object->load($data, ''); | |
$object->scenario = $this->getScenario(); | |
if ($object->validate()) { | |
$object = $this->saveObject($object, $data); | |
if ($this->returnObjectAfterSave) { | |
\Yii::$app->response->setStatusCode(200); | |
return $this->finish($this->toJson($object)); | |
} else { | |
// saved, no content | |
\Yii::$app->response->setStatusCode(201); | |
\Yii::$app->response->headers->set('Id', $object->id); | |
return $this->finish(''); | |
} | |
} else { | |
\Yii::$app->response->setStatusCode(400); | |
return $this->finish($object->errors); | |
} | |
} | |
public function actionDelete($id) { | |
if (!\Yii::$app->request->isDelete) throw new \yii\web\MethodNotAllowedHttpException(); | |
$this->checkAuthentication(); | |
$this->checkPermission(); | |
$object = $this->getObjectDetail($id); | |
if (!$object) { | |
throw new \yii\web\HttpException(404, 'Object not found'); | |
} | |
$this->checkObjectPermission($object); | |
return $this->deleteObject($object); | |
} | |
public function checkAuthentication() { | |
$authToken = \Yii::$app->request->headers->get('X-Auth-Token'); | |
if (!$authToken) throw new \yii\web\UnauthorizedHttpException(); | |
$user = \app\models\User::getUserFromToken($authToken); | |
if ($user === FALSE) { | |
throw new \yii\web\UnauthorizedHttpException(); | |
} | |
$this->user = $user; | |
return TRUE; | |
} | |
public function checkPermission() { | |
return TRUE; | |
} | |
public function checkObjectPermission($object) { | |
return TRUE; | |
} | |
public function getScenario() { | |
return $this->scenario; | |
} | |
// unfiltered by user | |
public function getObjectList() { | |
return call_user_func([$this->modelClass, 'find'])->where([]); | |
} | |
public function getObjectDetail($id) { | |
return call_user_func([$this->modelClass, 'findOne'], $id); | |
} | |
public function saveObject(&$object, $data) { | |
$object->save(); | |
return $object; | |
} | |
public function deleteObject($object) { | |
\Yii::$app->response->statusCode = 204; | |
try { | |
$object->delete(); | |
} catch (\yii\db\IntegrityException $e) { | |
throw new \yii\web\HttpException(400, 'Data cannot be deleted because of its integrity'); | |
} | |
return NULL; | |
} | |
public function getLimit() { | |
$limit = \Yii::$app->request->get($this->limitArg); | |
if (!$limit) $limit = $this->limit; | |
return $limit; | |
} | |
public function getOffset() { | |
$offset = \Yii::$app->request->get($this->offsetArg); | |
if (!$offset) $offset = $this->offset; | |
return $offset; | |
} | |
public function getOrder() { | |
$order = \Yii::$app->request->get($this->orderArg); | |
if ($order) { | |
$dir = \Yii::$app->request->get($this->dirArg); | |
if ($dir == 'desc') { | |
$order .= ' DESC'; | |
} else { | |
$order .= ' ASC'; | |
} | |
} | |
return $order; | |
} | |
public function getSearch() { | |
return \Yii::$app->request->get($this->searchArg); | |
} | |
public function searchResult(&$objectList, $search) { | |
return $objectList; | |
} | |
public function filterResult(&$objectList) { | |
return $objectList; | |
} | |
public function getTotal() { | |
return call_user_func([$this->modelClass, 'find'])->count(); | |
} | |
public function toJson($object) { | |
throw new \Exception('toJson Must be implemented'); | |
} | |
public function finish($result) { | |
return $result; | |
} | |
public function behaviors() { | |
return array_merge(parent::behaviors(), [ | |
// For cross-domain AJAX request | |
'corsFilter' => [ | |
'class' => \yii\filters\Cors::className(), | |
'cors' => [ | |
// restrict access to domains: | |
'Origin' => ['*'], | |
'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'DELETE'], | |
'Access-Control-Allow-Headers' => ['Content-Type', 'X-Auth-Token'], | |
'Access-Control-Request-Headers' => ['Content-Type', 'X-Auth-Token'], | |
'Access-Control-Allow-Credentials' => true, | |
'Access-Control-Max-Age' => 3600, // Cache (seconds) | |
'Access-Control-Allow-Origin' => ['*'] | |
], | |
], | |
]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment