├── .gitignore ├── README.md ├── composer.json ├── src ├── AbstractMongoArRepository.php ├── AbstractSqlArRepository.php ├── Exceptions │ └── RepositoryException.php ├── Interfaces │ └── iRepository.php └── Traits │ ├── MongoArRepositoryTrait.php │ └── SqlArRepositoryTrait.php └── tests └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | index.php 3 | composer.lock 4 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yii2 Repository Pattern implementation 2 | ====================================== 3 | Yii2 Repository Pattern implementation in Yii2 4 | 5 | you can read more about repository patterns here : 6 | http://deviq.com/repository-pattern/ 7 | http://martinfowler.com/eaaCatalog/repository.html 8 | http://shawnmc.cool/the-repository-pattern 9 | http://stackoverflow.com/questions/16176990/proper-repository-pattern-design-in-php 10 | 11 | ## Table of Contents 12 | 13 | - Installation 14 | - Composer 15 | - Methods 16 | - RepositoryInterface 17 | 18 | - Usage 19 | - Create a Model 20 | - Create a Repository 21 | - Attach your Repository to container 22 | - Repository Sample Usage 23 | 24 | 25 | ## Installation 26 | 27 | ### Composer 28 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/). 29 | 30 | Either run 31 | 32 | ``` 33 | composer require --prefer-dist mhndev/yii2-repository "1.*" 34 | ``` 35 | 36 | or add 37 | 38 | ``` 39 | "mhndev/yii2-repository": "1.*" 40 | ``` 41 | 42 | to the require section of your `composer.json` file. 43 | 44 | 45 | ## Methods 46 | 47 | ### mhndev\yii2Repository\Interfaces\iRepository 48 | 49 | ```php 50 | public function with(array $with = []); 51 | 52 | public function columns(array $columns = ['*']); 53 | 54 | public function limit($limit = 10); 55 | 56 | public function orderBy($orderBy, $sort = 'DESC'); 57 | 58 | public function create(array $data); 59 | 60 | public function createMany(array $data); 61 | 62 | public function findOneById($id, $returnArray = false); 63 | 64 | public function findOneBy($key, $value, $operation = '=', $returnArray = false); 65 | 66 | public function findManyBy($key, $value, $operation = '=', $withPagination = true, $returnArray = false); 67 | 68 | public function findManyByIds(array $ids, $withPagination = true, $returnArray = false); 69 | 70 | public function findAll($withPagination = true, $returnArray = false); 71 | 72 | public function findManyByCriteria(array $criteria = [], $withPagination = true, $with = [], $returnArray = false); 73 | 74 | public function updateOneById($id, array $data = []); 75 | 76 | public function updateOneBy($key, $value, array $data = []); 77 | 78 | public function updateOneByCriteria(array $criteria, array $data = []); 79 | 80 | public function updateManyBy($key, $value, array $data = [], $operation = '='); 81 | 82 | public function updateManyByCriteria(array $criteria = [], array $data = []); 83 | 84 | public function updateManyByIds(array $ids, array $data = []); 85 | 86 | public function deleteOneById($id); 87 | 88 | public function allExist(array $ids); 89 | 90 | public function deleteOneBy($key, $value, $operation = '='); 91 | 92 | public function deleteOneByCriteria(array $criteria = []); 93 | 94 | public function deleteManyBy($key, $value, $operation = '='); 95 | 96 | public function deleteManyByCriteria(array $criteria = []); 97 | 98 | public function searchByCriteria(); 99 | 100 | public function deleteManyByIds(array $ids); 101 | 102 | public function inc($id, $field, $count = 1); 103 | 104 | public function dec($id, $field, $count = 1); 105 | ``` 106 | 107 | ## Usage 108 | 109 | ### Create a Model 110 | 111 | create your ActiveRecord Model : 112 | 113 | ```php 114 | namespace app\models; 115 | 116 | 117 | use yii\db\ActiveRecord; 118 | 119 | /** 120 | * Class City 121 | * @package app\models 122 | */ 123 | class Post extends ActiveRecord 124 | { 125 | 126 | /** 127 | * @return string 128 | */ 129 | public static function tableName() 130 | { 131 | return 'posts'; 132 | 133 | } 134 | 135 | /** 136 | * @return array 137 | */ 138 | public function rules() 139 | { 140 | return [ 141 | 142 | [['title'], 'required'], 143 | 144 | ]; 145 | } 146 | 147 | 148 | } 149 | 150 | ``` 151 | 152 | ### Create a Repository Interface 153 | ```php 154 | namespace app\repositories\interfaces; 155 | use mhndev\yii2Repository\Interfaces\iRepository; 156 | 157 | interface iPostRepository extends iRepository 158 | { 159 | 160 | } 161 | 162 | ``` 163 | ### Create a Repository class 164 | 165 | ```php 166 | namespace app\repositories; 167 | 168 | use app\repositories\interfaces\iPostRepository; 169 | use mhndev\yii2Repository\AbstractSqlArRepository; 170 | 171 | class PostRepository extends AbstractSqlArRepository implements iPostRepository 172 | { 173 | 174 | } 175 | 176 | ``` 177 | 178 | or 179 | 180 | ### create a Repository as a Yii component 181 | 182 | ```php 183 | class PostRepository extends Component implements iPostRepository 184 | { 185 | 186 | const PRIMARY_KEY = 'id'; 187 | 188 | const APPLICATION_KEY = 'id'; 189 | 190 | 191 | use SqlArRepositoryTrait { 192 | init as repositoryInit; 193 | } 194 | 195 | 196 | public function init() 197 | { 198 | parent::init(); 199 | 200 | $this->repositoryInit(); 201 | } 202 | } 203 | 204 | 205 | ``` 206 | 207 | this approach is useful when toy have a class which is already extending a class 208 | and can't extend AbstractRepository class just like yii components 209 | by using traits you can use this classes as yii component. 210 | 211 | 212 | 213 | if your model is using sql as it's data source and your model actually is extending yii\db\ActiveRecord 214 | your repository should extend mhndev\yii2Repository\AbstractSqlArRepository. 215 | 216 | and if your data source is mongodb and your model actually is extending yii\mongodb\ActiveRecord 217 | your repository should extend mhndev\yii2Repository\AbstractMongoArRepository. 218 | 219 | 220 | and consider your application can use power of both sql and document-based databses (mongo) 221 | ### Attach your Repository to container 222 | ```php 223 | 224 | Yii::$container->set(\app\repositories\interfaces\iPostRepository::class, [ 225 | 'class' => \app\repositories\PostRepository::class 226 | ]); 227 | 228 | 229 | Yii::$container->set('postRepository', function($container, $params, $config){ 230 | return new \app\repositories\PostRepository(new \app\models\Post()); 231 | }); 232 | 233 | 234 | ``` 235 | if you are coding in a module you can put above code in your module bootstrap file. 236 | and also you can don't use container and create repository object every where you want like this : 237 | 238 | ```php 239 | $postRepository = new \app\repositories\PostRepository(new \app\models\Post()); 240 | 241 | ``` 242 | 243 | ### Repository Sample Usage 244 | 245 | sample usage which I show by using a controller. 246 | 247 | ```php 248 | namespace app\controllers; 249 | 250 | use app\repositories\interfaces\iPostRepository; 251 | use Yii; 252 | use yii\web\Controller; 253 | use yii\web\Response; 254 | 255 | /** 256 | * PostController 257 | */ 258 | class PostController extends Controller 259 | { 260 | 261 | /** 262 | * @var iPostRepository 263 | */ 264 | protected $postRepository; 265 | 266 | 267 | /** 268 | * @var bool 269 | */ 270 | public $enableCsrfValidation = false; 271 | 272 | 273 | /** 274 | * init 275 | */ 276 | public function init() 277 | { 278 | parent::init(); 279 | $this->postRepository = Yii::$container->get('postRepository'); 280 | 281 | Yii::$app->response->format = Response::FORMAT_JSON; 282 | } 283 | 284 | /** 285 | * @return array 286 | */ 287 | public function verbs() 288 | { 289 | return [ 290 | 'create' => ['POST'], 291 | 'delete' => ['DELETE'], 292 | 'update' => ['PUT'], 293 | 'index' => ['GET'], 294 | 'show' => ['GET'], 295 | 'delete-multiple' => ['DELETE'] 296 | ]; 297 | } 298 | 299 | 300 | /** 301 | * @return mixed 302 | */ 303 | public function actionCreate() 304 | { 305 | $data = Yii::$app->request->post(); 306 | 307 | $post = $this->postRepository->create($data); 308 | 309 | return $post; 310 | } 311 | 312 | 313 | /** 314 | * @param $id 315 | */ 316 | public function actionDelete($id) 317 | { 318 | $this->postRepository->deleteOneById($id); 319 | } 320 | 321 | /** 322 | * @param $id 323 | * @return bool 324 | */ 325 | public function actionUpdate($id) 326 | { 327 | $data = Yii::$app->request->post(); 328 | 329 | $post = $this->postRepository->updateOneById($id, $data); 330 | 331 | return $post; 332 | } 333 | 334 | 335 | /** 336 | * @return mixed 337 | */ 338 | public function actionIndex() 339 | { 340 | return $this->postRepository->searchByCriteria(); 341 | } 342 | 343 | 344 | /** 345 | * @param $id 346 | * @return mixed 347 | */ 348 | public function actionShow($id) 349 | { 350 | return $this->postRepository->findOneById($id); 351 | } 352 | 353 | 354 | /** 355 | * 356 | */ 357 | public function actionDeleteMultiple() 358 | { 359 | $ids = Yii::$app->request->post()['ids']; 360 | 361 | $deletedCount = $this->postRepository->deleteManyByIds($ids); 362 | } 363 | 364 | 365 | } 366 | 367 | ``` 368 | 369 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mhndev/yii2-repository", 3 | "description": "repository implementation in Yii2", 4 | "type": "library", 5 | "keywords": ["yii2","repository pattern","design pattern"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "majid abdolhosseini", 10 | "email": "majid8911303@gmail.com" 11 | } 12 | ], 13 | "require": { 14 | "yiisoft/yii2": "*" 15 | }, 16 | 17 | "suggest": { 18 | "yiisoft/yii2-mongodb": "needed if you want to use mongodb as your dbms instead of relational dbms" 19 | }, 20 | 21 | 22 | "autoload": { 23 | "psr-4": { 24 | "mhndev\\yii2Repository\\": "src/" 25 | } 26 | }, 27 | 28 | "minimum-stability": "stable" 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/AbstractMongoArRepository.php: -------------------------------------------------------------------------------- 1 | findManyBy('title','title5','like'); 17 | * 18 | * $posts = $postRepository->findManyBy('title','title5'); 19 | * 20 | * $posts = $postRepository->findManyByIds([1,2,3]); 21 | * 22 | * $posts = $postRepository->findManyWhereIn('text',['text1','text2']); 23 | * 24 | * $posts = $postRepository->findManyByCriteria([ 25 | * ['like', 'title','title'] , ['=','text','text1'] 26 | * ]); 27 | * 28 | * $posts = $postRepository->findOneById(2); 29 | * 30 | * $postRepository->updateOneById(2, ['title'=>'new new']); 31 | * 32 | * $postRepository->updateManyByIds([1,2,3], ['title'=>'new new new']); 33 | * 34 | * $postRepository->updateManyBy('title','salam', ['text'=>'sssssssssss'], 'like'); 35 | * 36 | * $postRepository->updateManyByCriteria([['like','title','salam'],['like','text','text2']], ['text'=>'salam']); 37 | * 38 | * $postRepository->deleteManyByIds([2,3]); 39 | * 40 | * $postRepository->deleteManyBy('title','title5','like'); 41 | * 42 | * $posts = $postRepository->findManyWhereIn('title',['salam','salam2'], false); 43 | * 44 | * Class AbstractMongoArRepository 45 | * @package mhndev\yii2Repository 46 | */ 47 | class AbstractMongoArRepository implements iRepository 48 | { 49 | 50 | const PRIMARY_KEY = '_id'; 51 | 52 | const APPLICATION_KEY = 'id'; 53 | 54 | use MongoArRepositoryTrait; 55 | 56 | /** 57 | * AbstractMongoRepository constructor. 58 | * @param ActiveRecord $model 59 | */ 60 | public function __construct(ActiveRecord $model) 61 | { 62 | $this->model = $model; 63 | 64 | $this->initRepositoryParams(); 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/AbstractSqlArRepository.php: -------------------------------------------------------------------------------- 1 | findManyBy('title','title5','like'); 18 | * 19 | * $posts = $postRepository->findManyBy('title','title5'); 20 | * 21 | * $posts = $postRepository->findManyByIds([1,2,3]); 22 | * 23 | * $posts = $postRepository->findManyWhereIn('text',['text1','text2']); 24 | * 25 | * $posts = $postRepository->findManyByCriteria([ 26 | * ['like', 'title','title'] , ['=','text','text1'] 27 | * ]); 28 | * 29 | * $posts = $postRepository->findOneById(2); 30 | * 31 | * $postRepository->updateOneById(2, ['title'=>'new new']); 32 | * 33 | * $postRepository->updateManyByIds([1,2,3], ['title'=>'new new new']); 34 | * 35 | * $postRepository->updateManyBy('title','salam', ['text'=>'sssssssssss'], 'like'); 36 | * 37 | * $postRepository->updateManyByCriteria([['like','title','salam'],['like','text','text2']], ['text'=>'salam']); 38 | * 39 | * $postRepository->deleteManyByIds([2,3]); 40 | * 41 | * $postRepository->deleteManyBy('title','title5','like'); 42 | * 43 | * $posts = $postRepository->findManyWhereIn('title',['salam','salam2'], false); 44 | * 45 | * Class AbstractSqlArRepository 46 | * @package mhndev\yii2Repository 47 | */ 48 | class AbstractSqlArRepository implements iRepository 49 | { 50 | 51 | const PRIMARY_KEY = 'id'; 52 | 53 | const APPLICATION_KEY = 'id'; 54 | 55 | 56 | use SqlArRepositoryTrait; 57 | 58 | /** 59 | * AbstractMongoRepository constructor. 60 | * @param ActiveRecord $model 61 | */ 62 | public function __construct(ActiveRecord $model) 63 | { 64 | $this->model = $model; 65 | 66 | $this->initRepositoryParams(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/Exceptions/RepositoryException.php: -------------------------------------------------------------------------------- 1 | findManyBy('title','title5','like'); 22 | * 23 | * $posts = $postRepository->findManyBy('title','title5'); 24 | * 25 | * $posts = $postRepository->findManyByIds([1,2,3]); 26 | * 27 | * $posts = $postRepository->findManyWhereIn('text',['text1','text2']); 28 | * 29 | * $posts = $postRepository->findManyByCriteria([ 30 | * ['like', 'title','title'] , ['=','text','text1'] 31 | * ]); 32 | * 33 | * $posts = $postRepository->findOneById(2); 34 | * 35 | * $postRepository->updateOneById(2, ['title'=>'new new']); 36 | * 37 | * $postRepository->updateManyByIds([1,2,3], ['title'=>'new new new']); 38 | * 39 | * $postRepository->updateManyBy('title','salam', ['text'=>'sssssssssss'], 'like'); 40 | * 41 | * 42 | * $postRepository->updateManyByCriteria([['like','title','salam'],['like','text','text2']], ['text'=>'salam']); 43 | * 44 | * $postRepository->deleteManyByIds([2,3]); 45 | * 46 | * $postRepository->deleteManyBy('title','title5','like'); 47 | * 48 | * $posts = $postRepository->findManyWhereIn('title',['salam','salam2'], false); 49 | * 50 | * 51 | * 52 | * trait MongoArRepositoryTrait 53 | * @package mhndev\yii2Repository 54 | */ 55 | trait MongoArRepositoryTrait 56 | { 57 | /** 58 | * @var ActiveRecord 59 | */ 60 | protected $model; 61 | 62 | 63 | /** 64 | * @var string 65 | */ 66 | public $modelClass; 67 | 68 | /** 69 | * @var array $data 70 | * query parameters (sort, filters, pagination) 71 | */ 72 | protected $data; 73 | 74 | /** 75 | * @var array 76 | */ 77 | protected $with = []; 78 | 79 | /** 80 | * @var array 81 | */ 82 | protected $columns = ['*']; 83 | 84 | /** 85 | * @var string 86 | */ 87 | protected $orderBy; 88 | 89 | /** 90 | * @var int 91 | */ 92 | protected $limit = 10; 93 | 94 | /** 95 | * @var int 96 | */ 97 | protected $offset = 0; 98 | 99 | 100 | /** 101 | * @var Query 102 | */ 103 | protected $query; 104 | 105 | 106 | /** 107 | * @var Connection 108 | */ 109 | protected $connection; 110 | 111 | 112 | 113 | /** 114 | * @throws RepositoryException 115 | */ 116 | public function init() 117 | { 118 | if($this->model){ 119 | return; 120 | } 121 | 122 | if(empty($this->modelClass)){ 123 | throw new RepositoryException('what the f ...'); 124 | } 125 | 126 | $this->model = new $this->modelClass; 127 | 128 | $this->initRepositoryParams(); 129 | } 130 | 131 | 132 | /** 133 | * @return $this 134 | */ 135 | protected function initRepositoryParams() 136 | { 137 | $this->columns(); 138 | $this->orderBy(self::PRIMARY_KEY, self::desc); 139 | 140 | $this->connection = Yii::$app->mongodb; 141 | $this->query = $this->model->find(); 142 | 143 | return $this; 144 | } 145 | 146 | /** 147 | * @param $returnArray 148 | * @param $columns 149 | * @param $with 150 | */ 151 | protected function initFetch($returnArray, $columns, $with) 152 | { 153 | foreach ($with as $relation){ 154 | $this->query = $this->query->with($relation); 155 | } 156 | 157 | 158 | if($columns != ['*']){ 159 | $this->query->select($columns); 160 | } 161 | 162 | if($returnArray){ 163 | $this->query->asArray(); 164 | } 165 | } 166 | 167 | 168 | 169 | /** 170 | * @return ActiveRecord 171 | */ 172 | protected function makeQuery() 173 | { 174 | return $this->model; 175 | } 176 | 177 | 178 | /** 179 | * @param array $with 180 | * @return $this 181 | * @throws RepositoryException 182 | */ 183 | public function with(array $with = []) 184 | { 185 | if (is_array($with) === false) { 186 | throw new RepositoryException; 187 | } 188 | 189 | $this->with = $with; 190 | 191 | return $this; 192 | } 193 | 194 | /** 195 | * @param array $columns 196 | * @return $this 197 | * @throws RepositoryException 198 | */ 199 | public function columns(array $columns = ['*']) 200 | { 201 | if (is_array($columns) === false) { 202 | throw new RepositoryException; 203 | } 204 | 205 | else{ 206 | $this->columns = $columns; 207 | } 208 | 209 | return $this; 210 | } 211 | 212 | 213 | /** 214 | * @param int $offset 215 | * @return $this 216 | * @throws RepositoryException 217 | */ 218 | public function offset($offset = 0) 219 | { 220 | if (!is_numeric($offset) || $offset < 0) { 221 | throw new RepositoryException; 222 | } 223 | 224 | $this->offset = $offset; 225 | 226 | return $this; 227 | } 228 | 229 | 230 | /** 231 | * @param int $limit 232 | * @return $this 233 | * @throws RepositoryException 234 | */ 235 | public function limit($limit = 10) 236 | { 237 | if (!is_numeric($limit) || $limit < 1) { 238 | throw new RepositoryException; 239 | } 240 | 241 | $this->limit = $limit; 242 | 243 | return $this; 244 | } 245 | 246 | /** 247 | * @param $orderBy 248 | * @param string $sort 249 | * @return $this 250 | * @throws RepositoryException 251 | */ 252 | public function orderBy($orderBy, $sort = 'DESC') 253 | { 254 | if(! is_array($orderBy)){ 255 | if ($orderBy === null) 256 | return $this; 257 | 258 | 259 | if (!in_array(strtoupper($sort), ['DESC', 'ASC'])) { 260 | throw new RepositoryException; 261 | } 262 | 263 | $this->orderBy = [$orderBy .' '. $sort]; 264 | } 265 | 266 | else{ 267 | 268 | foreach ($orderBy as $field => $method){ 269 | if (!in_array(strtoupper($method), ['DESC', 'ASC'])) { 270 | throw new RepositoryException; 271 | } 272 | } 273 | 274 | $this->orderBy = $orderBy; 275 | } 276 | 277 | 278 | return $this; 279 | } 280 | 281 | /** 282 | * @param array $data 283 | * @return mixed 284 | */ 285 | public function create(array $data) 286 | { 287 | foreach($data as $key => $value){ 288 | $this->model->{$key} = $value; 289 | } 290 | 291 | if($this->model->save()){ 292 | return $this->formatEntity($this->model); 293 | }else{ 294 | return $this->model->errors; 295 | } 296 | } 297 | 298 | 299 | /** 300 | * @param array $data 301 | * @return mixed|void 302 | * @throws RepositoryException 303 | */ 304 | public function createMany(array $data) 305 | { 306 | if(depth($data) < 2){ 307 | throw new RepositoryException; 308 | } 309 | 310 | /** @var ActiveRecord $modelClassName */ 311 | $modelClassName = get_class($this->model); 312 | 313 | foreach ($data as $record){ 314 | /** @var ActiveRecord $model */ 315 | $model = new $modelClassName; 316 | 317 | foreach($record as $key => $value){ 318 | $model->{$key} = $value; 319 | } 320 | 321 | if(!$model->validate()){ 322 | break; 323 | } 324 | 325 | } 326 | 327 | $this->connection->createCommand() 328 | ->batchInsert($modelClassName::collectionName(), $modelClassName->attributes(), $data)->execute(); 329 | } 330 | 331 | 332 | 333 | 334 | /** 335 | * @param $id 336 | * @param bool $returnArray 337 | * @return mixed 338 | */ 339 | public function findOneById($id, $returnArray = false) 340 | { 341 | $this->initFetch($returnArray, $this->columns, $this->with); 342 | 343 | $entity = $this->query->where([self::PRIMARY_KEY=>$id])->one(); 344 | 345 | return $this->formatEntityObject($entity); 346 | } 347 | 348 | 349 | /** 350 | * @param $entity 351 | * @return mixed 352 | */ 353 | protected function formatEntityObject($entity) 354 | { 355 | $primaryKey = self::PRIMARY_KEY; 356 | $appKey = self::APPLICATION_KEY; 357 | 358 | if(!empty($entity->{$primaryKey}) ){ 359 | 360 | if($entity->{$primaryKey} instanceof ObjectID){ 361 | $entity->{$primaryKey} = $entity->{$primaryKey}->__toString(); 362 | } 363 | 364 | $entity->{$appKey} = $entity->{$primaryKey}; 365 | unset($entity->{$primaryKey}); 366 | } 367 | 368 | return $entity; 369 | } 370 | 371 | 372 | /** 373 | * @param $entity 374 | * @return mixed 375 | */ 376 | protected function formatEntityArray($entity) 377 | { 378 | if(in_array(self::APPLICATION_KEY, $this->model->attributes())){ 379 | 380 | 381 | $entity[self::APPLICATION_KEY] = $entity[self::PRIMARY_KEY]; 382 | 383 | if($entity[self::PRIMARY_KEY] instanceof ObjectID){ 384 | $entity[self::APPLICATION_KEY] = $entity[self::PRIMARY_KEY]->__toString(); 385 | } 386 | 387 | } 388 | 389 | unset($entity[self::PRIMARY_KEY]); 390 | 391 | return $entity; 392 | } 393 | 394 | 395 | /** 396 | * @param $entity 397 | * @return mixed 398 | */ 399 | public function formatEntity($entity) 400 | { 401 | if(is_array($entity)){ 402 | $model = $this->formatEntityArray($entity); 403 | }else{ 404 | $model = $this->formatEntityObject($entity); 405 | } 406 | 407 | return $model; 408 | } 409 | 410 | /** 411 | * @param array $entities 412 | * @return array 413 | */ 414 | protected function formatEntities(array $entities) 415 | { 416 | $result = []; 417 | 418 | foreach ($entities as $entity){ 419 | if(!in_array(self::APPLICATION_KEY, $this->model->attributes())){ 420 | 421 | unset($entity->{self::PRIMARY_KEY}); 422 | } 423 | $model = $this->formatEntity($entity); 424 | 425 | $result[] = $model; 426 | } 427 | 428 | return $result; 429 | } 430 | 431 | 432 | /** 433 | * @param $key 434 | * @param $value 435 | * @param string $operation 436 | * @param bool $returnArray 437 | * @return mixed 438 | */ 439 | public function findOneBy($key, $value, $operation = '=', $returnArray = false) 440 | { 441 | $this->initFetch($returnArray, $this->columns, $this->with); 442 | $condition = ($operation == '=') ? [$key => $value] : [$operation, $key ,$value]; 443 | 444 | return $this->query->where($condition)->one(); 445 | } 446 | 447 | 448 | /** 449 | * @param $key 450 | * @param $value 451 | * @param string $operation 452 | * @param bool $withPagination 453 | * @param bool $returnArray 454 | * @return mixed 455 | */ 456 | public function findManyBy($key, $value, $operation = '=', $withPagination = true, $returnArray = false) 457 | { 458 | $this->initFetch($returnArray, $this->columns, $this->with); 459 | 460 | $this->query = $this->query->where([$operation, $key , $value])->orderBy($this->orderBy); 461 | 462 | return $withPagination ? $this->paginate() : $this->formatEntity($this->query->all() ); 463 | } 464 | 465 | /** 466 | * @param array $ids 467 | * @param bool $withPagination 468 | * @param bool $returnArray 469 | * @return mixed 470 | */ 471 | public function findManyByIds(array $ids, $withPagination = true, $returnArray = false) 472 | { 473 | $this->initFetch($returnArray, $this->columns, $this->with); 474 | 475 | $this->query = $this->query->where([self::PRIMARY_KEY=>$ids])->orderBy($this->orderBy); 476 | 477 | return $withPagination ? $this->paginate() : $this->formatEntities($this->query->all() ); 478 | } 479 | 480 | 481 | /** 482 | * @param $field 483 | * @param array $values 484 | * @param bool $withPagination 485 | * @param bool $returnArray 486 | * @return array 487 | */ 488 | public function findManyWhereIn($field, array $values, $withPagination = true, $returnArray = false) 489 | { 490 | $this->initFetch($returnArray, $this->columns, $this->with); 491 | 492 | $this->query = $this->query->where([$field => $values])->orderBy($this->orderBy); 493 | 494 | return $withPagination ? $this->paginate() : $this->formatEntities($this->query->all() ); 495 | } 496 | 497 | 498 | 499 | /** 500 | * @param bool $withPagination 501 | * @param bool $returnArray 502 | * @return mixed 503 | */ 504 | public function findAll($withPagination = true, $returnArray = false) 505 | { 506 | $this->initFetch($returnArray, $this->columns, $this->with); 507 | 508 | $this->query = $this->query->orderBy($this->orderBy); 509 | 510 | return $withPagination ? $this->paginate() : $this->formatEntities($this->query->all() ); 511 | } 512 | 513 | 514 | /** 515 | * @return array 516 | */ 517 | protected function paginate() 518 | { 519 | $response = []; 520 | 521 | $count = $this->query->count(); 522 | 523 | $perPage = !empty($_GET['perPage']) ? $_GET['perPage'] : $this->limit; 524 | $currentPage = !empty($_GET['page']) ? $_GET['page'] : 1; 525 | $pagination = new Pagination(['totalCount' => $count,'pageSize' => $perPage ]); 526 | 527 | $result = $this->query 528 | ->offset($pagination->offset) 529 | ->limit($pagination->limit) 530 | ->all(); 531 | 532 | $response['items'] = $this->formatEntities($result); 533 | $response['_meta']['totalCount'] = $count; 534 | $response['_meta']['pageCount'] = $pagination->pageCount; 535 | $response['_meta']['currentPage'] = $currentPage; 536 | $response['_meta']['perPage'] = $pagination->limit; 537 | 538 | $response['_links'] = $pagination->getLinks(); 539 | 540 | return $response; 541 | } 542 | 543 | 544 | /** 545 | * @param array $criteria 546 | * @param bool $withPagination 547 | * @param array $with 548 | * @param bool $returnArray 549 | * @return mixed 550 | */ 551 | public function findManyByCriteria(array $criteria = [], $withPagination = true, $with = [], $returnArray = false) 552 | { 553 | $mainCriteria = []; 554 | 555 | if(depth($criteria) > 1){ 556 | 557 | if(count($criteria) > 1 ){ 558 | array_unshift($mainCriteria, 'and'); 559 | } 560 | 561 | foreach ($criteria as $condition){ 562 | if($condition[0] == '='){ 563 | array_push($mainCriteria, [$condition[1] => $condition[2]]); 564 | } 565 | else{ 566 | array_push($mainCriteria, $condition); 567 | } 568 | } 569 | 570 | }else{ 571 | if($criteria[0] == '='){ 572 | array_push($mainCriteria, [$criteria[1] => $criteria[2]]); 573 | }else{ 574 | $mainCriteria = $criteria; 575 | } 576 | } 577 | 578 | 579 | if(count($mainCriteria) == 1 && depth($mainCriteria) > 1){ 580 | $mainCriteria = $mainCriteria[0]; 581 | } 582 | 583 | $this->initFetch($returnArray, $this->columns, $this->with); 584 | 585 | 586 | $this->query = $this->query->where($mainCriteria)->orderBy($this->orderBy); 587 | 588 | return $withPagination ? $this->paginate() : $this->formatEntities($this->query->all() ); 589 | } 590 | 591 | 592 | /** 593 | * @param ActiveRecord $entity 594 | * @param array $data 595 | * @return ActiveRecord 596 | */ 597 | protected function updateEntity(ActiveRecord $entity, array $data) 598 | { 599 | $entity->setAttributes($data); 600 | $entity->save(); 601 | 602 | return $entity; 603 | } 604 | 605 | 606 | 607 | /** 608 | * @param $id 609 | * @param array $data 610 | * @return boolean 611 | */ 612 | public function updateOneById($id, array $data = []) 613 | { 614 | $entity = $this->makeQuery()->findOne([self::PRIMARY_KEY=>$id]); 615 | 616 | return $this->updateEntity($entity, $data); 617 | } 618 | 619 | /** 620 | * @param $key 621 | * @param $value 622 | * @param array $data 623 | * @return boolean 624 | */ 625 | public function updateOneBy($key, $value, array $data = []) 626 | { 627 | if($key == self::APPLICATION_KEY){ 628 | $key = self::PRIMARY_KEY; 629 | } 630 | 631 | $entity = $this->makeQuery()->findOne([ $key => $value ]); 632 | 633 | return $this->updateEntity($entity, $data); 634 | } 635 | 636 | /** 637 | * @param array $criteria 638 | * @param array $data 639 | * @return boolean 640 | */ 641 | public function updateOneByCriteria(array $criteria, array $data = []) 642 | { 643 | $entity = $this->model->findOne($criteria); 644 | 645 | return $this->updateEntity($entity, $data); 646 | } 647 | 648 | /** 649 | * @param $key 650 | * @param $value 651 | * @param array $data 652 | * @param string $operation 653 | * @return bool 654 | */ 655 | public function updateManyBy($key, $value, array $data = [], $operation = '=') 656 | { 657 | if($key == self::APPLICATION_KEY){ 658 | $key = self::PRIMARY_KEY; 659 | } 660 | 661 | return $this->model->updateAll($data, [$operation, $key, $value]); 662 | } 663 | 664 | /** 665 | * @param array $criteria 666 | * @param array $data 667 | * @return boolean 668 | */ 669 | public function updateManyByCriteria(array $criteria = [], array $data = []) 670 | { 671 | if(depth($criteria) > 1) 672 | array_unshift($criteria, 'and'); 673 | 674 | return $this->model->updateAll($data, $criteria); 675 | } 676 | 677 | /** 678 | * @param array $ids 679 | * @param array $data 680 | * @return bool 681 | */ 682 | public function updateManyByIds(array $ids, array $data = []) 683 | { 684 | return $this->model->updateAll($data, ['in', self::PRIMARY_KEY, $ids]); 685 | } 686 | 687 | /** 688 | * @param $id 689 | * @return boolean 690 | */ 691 | public function deleteOneById($id) 692 | { 693 | $entity = $this->model->findOne([self::PRIMARY_KEY=>$id]); 694 | 695 | return $entity->delete(); 696 | } 697 | 698 | /** 699 | * @param array $ids 700 | * @return bool 701 | */ 702 | public function allExist(array $ids) 703 | { 704 | // TODO: Implement allExist() method. 705 | } 706 | 707 | /** 708 | * @param $key 709 | * @param $value 710 | * @param string $operation 711 | * @return bool 712 | */ 713 | public function deleteOneBy($key, $value, $operation = '=') 714 | { 715 | if($key == self::APPLICATION_KEY){ 716 | $key = self::PRIMARY_KEY; 717 | } 718 | 719 | $condition = ($operation == '=') ? [$key => $value] : [$operation, $key ,$value]; 720 | 721 | $entity = $this->model->findOne([$condition]); 722 | 723 | return $entity->delete(); 724 | } 725 | 726 | /** 727 | * @param array $criteria 728 | * @return boolean 729 | */ 730 | public function deleteOneByCriteria(array $criteria = []) 731 | { 732 | $entity = $this->model->findOne($criteria); 733 | 734 | return $entity->delete(); 735 | } 736 | 737 | /** 738 | * @param $key 739 | * @param $value 740 | * @param string $operation 741 | * @return bool 742 | */ 743 | public function deleteManyBy($key, $value, $operation = '=') 744 | { 745 | if($key == self::APPLICATION_KEY){ 746 | $key = self::PRIMARY_KEY; 747 | } 748 | 749 | return $this->model->deleteAll([$operation, $key, $value]); 750 | } 751 | 752 | /** 753 | * @param array $criteria 754 | * @return boolean 755 | */ 756 | public function deleteManyByCriteria(array $criteria = []) 757 | { 758 | if(depth($criteria) > 1) 759 | array_unshift($criteria, 'and'); 760 | 761 | return $this->model->deleteAll($criteria); 762 | } 763 | 764 | /** 765 | * @return mixed 766 | * @throws RepositoryException 767 | */ 768 | public function searchByCriteria() 769 | { 770 | $search = !empty($_GET['search']) ? explode(',',$_GET['search']) : null; 771 | 772 | if(!empty($_GET['fields'])){ 773 | $fields = explode(',',$_GET['fields']); 774 | $this->columns($fields); 775 | } 776 | 777 | if(!empty($perPage)){ 778 | $this->limit($perPage); 779 | } 780 | 781 | if(!empty($_GET['with'])){ 782 | $with = explode(',',$_GET['with']); 783 | $this->with($with); 784 | } 785 | 786 | if(!empty($search)){ 787 | $criteria = []; 788 | foreach ($search as $string){ 789 | $components = explode(':', $string); 790 | 791 | if( empty($components[0]) || empty($components[1]) || empty($components[2]) ){ 792 | throw new RepositoryException('search parameters are not specified correctly.'); 793 | } 794 | 795 | if($components[0] == self::APPLICATION_KEY){ 796 | $components[0] = self::PRIMARY_KEY; 797 | } 798 | 799 | array_push($criteria ,[$components[1],$components[0],$components[2]]); 800 | } 801 | 802 | return $this->findManyByCriteria($criteria); 803 | 804 | }else{ 805 | return $this->findAll(); 806 | } 807 | 808 | } 809 | 810 | /** 811 | * @param array $ids 812 | * @return mixed 813 | */ 814 | public function deleteManyByIds(array $ids) 815 | { 816 | return $this->model->deleteAll(['in', self::PRIMARY_KEY, $ids]); 817 | } 818 | 819 | /** 820 | * @param $id 821 | * @param $field 822 | * @param int $count 823 | */ 824 | public function inc($id, $field, $count = 1) 825 | { 826 | /** @var \yii\db\ActiveRecord $entity */ 827 | $entity = $this->query->one([self::PRIMARY_KEY=>$id]); 828 | 829 | $entity->updateCounters([$field => $count]); 830 | } 831 | 832 | /** 833 | * @param $id 834 | * @param $field 835 | * @param $count 836 | */ 837 | public function dec($id, $field, $count = 1) 838 | { 839 | /** @var ActiveRecord $entity */ 840 | $entity = $this->query->one([self::PRIMARY_KEY=>$id]); 841 | 842 | $entity->updateCounters([$field => $count]); 843 | } 844 | } 845 | -------------------------------------------------------------------------------- /src/Traits/SqlArRepositoryTrait.php: -------------------------------------------------------------------------------- 1 | findManyBy('title','title5','like'); 21 | * 22 | * $posts = $postRepository->findManyBy('title','title5'); 23 | * 24 | * $posts = $postRepository->findManyByIds([1,2,3]); 25 | * 26 | * $posts = $postRepository->findManyWhereIn('text',['text1','text2']); 27 | * 28 | * $posts = $postRepository->findManyByCriteria([ 29 | * ['like', 'title','title'] , ['=','text','text1'] 30 | * ]); 31 | * 32 | * $posts = $postRepository->findOneById(2); 33 | * 34 | * $postRepository->updateOneById(2, ['title'=>'new new']); 35 | * 36 | * $postRepository->updateManyByIds([1,2,3], ['title'=>'new new new']); 37 | * 38 | * $postRepository->updateManyBy('title','salam', ['text'=>'sssssssssss'], 'like'); 39 | * 40 | * 41 | * $postRepository->updateManyByCriteria([['like','title','salam'],['like','text','text2']], ['text'=>'salam']); 42 | * 43 | * $postRepository->deleteManyByIds([2,3]); 44 | * 45 | * $postRepository->deleteManyBy('title','title5','like'); 46 | * 47 | * $posts = $postRepository->findManyWhereIn('title',['salam','salam2'], false); 48 | * 49 | * trait SqlArRepositoryTrait 50 | * @package mhndev\yii2Repository 51 | */ 52 | trait SqlArRepositoryTrait 53 | { 54 | /** 55 | * @var Connection 56 | */ 57 | protected $connection; 58 | 59 | 60 | /** 61 | * @var string 62 | */ 63 | public $modelClass; 64 | 65 | /** 66 | * @var ActiveRecord 67 | */ 68 | protected $model; 69 | 70 | /** 71 | * @var Query 72 | */ 73 | protected $query; 74 | 75 | /** 76 | * @var array $data 77 | * query parameters (sort, filters, pagination) 78 | */ 79 | protected $data; 80 | 81 | /** 82 | * @var array 83 | */ 84 | protected $with = []; 85 | 86 | /** 87 | * @var array 88 | */ 89 | protected $columns = ['*']; 90 | 91 | /** 92 | * @var array|string 93 | */ 94 | protected $orderBy = [self::PRIMARY_KEY => self::desc]; 95 | 96 | /** 97 | * @var int 98 | */ 99 | protected $limit = 10; 100 | 101 | /** 102 | * @var int 103 | */ 104 | protected $offset = 0; 105 | 106 | 107 | /** 108 | * @throws RepositoryException 109 | */ 110 | public function init() 111 | { 112 | if($this->model){ 113 | return; 114 | } 115 | 116 | if(empty($this->modelClass)){ 117 | throw new RepositoryException('what the f ...'); 118 | } 119 | 120 | $this->model = new $this->modelClass; 121 | 122 | $this->columns(); 123 | 124 | $this->orderBy(self::PRIMARY_KEY, self::desc); 125 | 126 | $this->connection = \Yii::$app->db; 127 | $this->query = $this->model->find(); 128 | } 129 | 130 | 131 | /** 132 | * @return $this 133 | */ 134 | protected function initRepositoryParams() 135 | { 136 | $this->columns(); 137 | $this->orderBy(self::PRIMARY_KEY, self::desc); 138 | 139 | $this->connection = Yii::$app->db; 140 | $this->query = $this->model->find(); 141 | 142 | return $this; 143 | } 144 | 145 | /** 146 | * @param array $with 147 | * @return $this 148 | * @throws RepositoryException 149 | */ 150 | public function with(array $with = []) 151 | { 152 | if (is_array($with) === false) { 153 | throw new RepositoryException; 154 | } 155 | 156 | $this->with = $with; 157 | 158 | return $this; 159 | } 160 | 161 | /** 162 | * @param array $columns 163 | * @return $this 164 | * @throws RepositoryException 165 | */ 166 | public function columns(array $columns = ['*']) 167 | { 168 | if (is_array($columns) === false) { 169 | throw new RepositoryException; 170 | } 171 | 172 | $this->columns = $columns; 173 | 174 | return $this; 175 | } 176 | 177 | 178 | /** 179 | * @param int $offset 180 | * @return $this 181 | * @throws RepositoryException 182 | */ 183 | public function offset($offset = 0) 184 | { 185 | if (!is_numeric($offset) || $offset < 0) { 186 | throw new RepositoryException; 187 | } 188 | 189 | $this->offset = $offset; 190 | 191 | return $this; 192 | } 193 | 194 | 195 | /** 196 | * @param int $limit 197 | * @return $this 198 | * @throws RepositoryException 199 | */ 200 | public function limit($limit = 10) 201 | { 202 | if (!is_numeric($limit) || $limit < 1) { 203 | throw new RepositoryException; 204 | } 205 | 206 | $this->limit = $limit; 207 | 208 | return $this; 209 | } 210 | 211 | /** 212 | * @param $orderBy 213 | * @param string $sort 214 | * @return $this 215 | * @throws RepositoryException 216 | */ 217 | public function orderBy($orderBy, $sort = 'DESC') 218 | { 219 | if(! is_array($orderBy)){ 220 | if ($orderBy === null) 221 | return $this; 222 | 223 | 224 | if (!in_array(strtoupper($sort), ['DESC', 'ASC'])) { 225 | throw new RepositoryException; 226 | } 227 | 228 | $this->orderBy = [$orderBy => 'SORT_'.$sort]; 229 | } 230 | 231 | else{ 232 | 233 | foreach ($orderBy as $field => $method){ 234 | if (!in_array(strtoupper($method), ['DESC', 'ASC'])) { 235 | throw new RepositoryException; 236 | } 237 | } 238 | 239 | $this->orderBy = $orderBy; 240 | } 241 | 242 | 243 | return $this; 244 | } 245 | 246 | /** 247 | * @param array $data 248 | * @return mixed 249 | */ 250 | public function create(array $data) 251 | { 252 | $this->model->setAttributes($data); 253 | $this->model->save(); 254 | 255 | return $this->model; 256 | } 257 | 258 | 259 | /** 260 | * @param array $data 261 | * @return mixed|void 262 | * @throws RepositoryException 263 | */ 264 | public function createMany(array $data) 265 | { 266 | if(depth($data) < 2){ 267 | throw new RepositoryException; 268 | } 269 | 270 | $modelClassName = get_class($this->model); 271 | 272 | foreach ($data as $record){ 273 | /** @var ActiveRecord $model */ 274 | $model = new $modelClassName; 275 | 276 | foreach($record as $key => $value){ 277 | $model->{$key} = $value; 278 | } 279 | 280 | if(!$model->validate()){ 281 | break; 282 | } 283 | 284 | } 285 | 286 | $this->connection->createCommand() 287 | ->batchInsert($modelClassName::tableName(), $modelClassName->attributes(), $data)->execute(); 288 | } 289 | 290 | 291 | /** 292 | * @param $id 293 | * @param bool $returnArray 294 | * @return mixed 295 | */ 296 | public function findOneById($id, $returnArray = false) 297 | { 298 | foreach ($this->with as $relation){ 299 | $this->query = $this->query->with($relation); 300 | } 301 | 302 | $this->initFetch($returnArray, $this->columns); 303 | return $this->query->where([self::PRIMARY_KEY=>$id])->limit(1)->one(); 304 | } 305 | 306 | /** 307 | * @param $key 308 | * @param $value 309 | * @param string $operation 310 | * @param bool $returnArray 311 | * @return mixed 312 | */ 313 | public function findOneBy($key, $value, $operation = '=', $returnArray = false) 314 | { 315 | foreach ($this->with as $relation){ 316 | $this->query = $this->query->with($relation); 317 | } 318 | $this->initFetch($returnArray, $this->columns); 319 | 320 | return $this->query->where([$operation, $key ,$value])->limit(1)->one(); 321 | } 322 | 323 | /** 324 | * @param $key 325 | * @param $value 326 | * @param string $operation 327 | * @param bool $withPagination 328 | * @param bool $returnArray 329 | * @return mixed 330 | */ 331 | public function findManyBy($key, $value, $operation = '=', $withPagination = true, $returnArray = false) 332 | { 333 | foreach ($this->with as $relation){ 334 | $this->query = $this->query->with($relation); 335 | } 336 | 337 | $this->initFetch($returnArray, $this->columns); 338 | $this->query = $this->query->where([$operation, $key , $value])->orderBy($this->orderBy); 339 | 340 | return $withPagination ? $this->paginate() : $this->query->all(); 341 | } 342 | 343 | /** 344 | * @param array $ids 345 | * @param bool $withPagination 346 | * @param bool $returnArray 347 | * @return mixed 348 | */ 349 | public function findManyByIds(array $ids, $withPagination = true, $returnArray = false) 350 | { 351 | foreach ($this->with as $relation){ 352 | $this->query = $this->query->with($relation); 353 | } 354 | 355 | $this->initFetch($returnArray, $this->columns); 356 | $this->query = $this->query->where([self::PRIMARY_KEY=>$ids])->orderBy($this->orderBy); 357 | 358 | return $withPagination ? $this->paginate() : $this->query->all(); 359 | } 360 | 361 | 362 | /** 363 | * @param $field 364 | * @param array $values 365 | * @param bool $withPagination 366 | * @param bool $returnArray 367 | * @return array 368 | */ 369 | public function findManyWhereIn($field, array $values, $withPagination = true, $returnArray = false) 370 | { 371 | foreach ($this->with as $relation){ 372 | $this->query = $this->query->with($relation); 373 | } 374 | 375 | $this->initFetch($returnArray, $this->columns); 376 | $this->query = $this->query->where([$field => $values])->orderBy($this->orderBy); 377 | 378 | return $withPagination ? $this->paginate() : $this->query->all(); 379 | } 380 | 381 | 382 | /** 383 | * @param int $perPage 384 | * @return array 385 | */ 386 | protected function paginate($perPage = 10) 387 | { 388 | $response = []; 389 | 390 | $count = $this->query->count(); 391 | 392 | $pagination = new Pagination(['totalCount' => $count,'pageSize' => $perPage ]); 393 | 394 | 395 | $result = $this->query 396 | ->offset($pagination->offset) 397 | ->limit($pagination->limit) 398 | ->all(); 399 | 400 | $response['items'] = $result; 401 | $response['_meta']['totalCount'] = $count; 402 | $response['_meta']['pageCount'] = floor($count / $pagination->limit )+ 1; 403 | $response['_meta']['currentPage'] = !empty($_GET['page']) ? $_GET['page'] : 1; 404 | $response['_meta']['perPage'] = $pagination->limit; 405 | 406 | $response['_links'] = $pagination->getLinks(); 407 | 408 | return $response; 409 | } 410 | 411 | 412 | /** 413 | * @param $returnArray 414 | * @param $columns 415 | */ 416 | protected function initFetch($returnArray, $columns) 417 | { 418 | if($columns != ['*']){ 419 | $this->query->select($columns); 420 | } 421 | 422 | if($returnArray){ 423 | $this->query->asArray(); 424 | } 425 | } 426 | 427 | /** 428 | * @param bool $withPagination 429 | * @param bool $returnArray 430 | * @return mixed 431 | */ 432 | public function findAll($withPagination = true, $returnArray = false) 433 | { 434 | foreach ($this->with as $relation){ 435 | $this->query = $this->query->with($relation); 436 | } 437 | 438 | $this->initFetch($returnArray, $this->columns); 439 | 440 | $this->query = $this->query->orderBy($this->orderBy); 441 | 442 | return $withPagination ? $this->paginate() : $this->query->all(); 443 | } 444 | 445 | /** 446 | * @param array $criteria 447 | * @param bool $withPagination 448 | * @param array $with 449 | * @param bool $returnArray 450 | * @return mixed 451 | */ 452 | public function findManyByCriteria(array $criteria = [], $withPagination = true, $with = [], $returnArray = false) 453 | { 454 | if(depth($criteria) > 1) 455 | array_unshift($criteria, 'and'); 456 | 457 | foreach ($this->with as $relation){ 458 | $this->query = $this->query->with($relation); 459 | } 460 | 461 | $this->initFetch($returnArray, $this->columns); 462 | $this->query = $this->query->where($criteria)->orderBy($this->orderBy); 463 | 464 | 465 | return $withPagination ? $this->paginate() : $this->query->all(); 466 | } 467 | 468 | /** 469 | * @param $id 470 | * @param $field 471 | * @param int $count 472 | */ 473 | public function inc($id, $field, $count = 1) 474 | { 475 | $entity = $this->query->where([self::PRIMARY_KEY=>$id])->one(); 476 | 477 | $entity->updateCounters([$field => $count]); 478 | } 479 | 480 | /** 481 | * @param $id 482 | * @param $field 483 | * @param int $count 484 | */ 485 | public function dec($id, $field, $count = -1) 486 | { 487 | $entity = $this->query->where([self::PRIMARY_KEY=>$id])->one(); 488 | 489 | $entity->updateCounters([$field => $count]); 490 | } 491 | 492 | /** 493 | * @param ActiveRecord $entity 494 | * @param array $data 495 | * @return ActiveRecord 496 | */ 497 | protected function updateEntity(ActiveRecord $entity, array $data) 498 | { 499 | $entity->setAttributes($data); 500 | $entity->save(); 501 | 502 | return $entity; 503 | } 504 | 505 | /** 506 | * @param $id 507 | * @param array $data 508 | * @return mixed 509 | */ 510 | public function updateOneById($id, array $data = []) 511 | { 512 | $entity = $this->query->where([self::PRIMARY_KEY=>$id])->limit(1)->one(); 513 | 514 | return $this->updateEntity($entity, $data); 515 | 516 | } 517 | 518 | /** 519 | * @param $key 520 | * @param $value 521 | * @param array $data 522 | * @return mixed 523 | */ 524 | public function updateOneBy($key, $value, array $data = []) 525 | { 526 | $entity = $this->query->where([ $key => $value ])->limit(1)->one(); 527 | 528 | return $this->updateEntity($entity, $data); 529 | 530 | } 531 | 532 | /** 533 | * @param array $criteria 534 | * @param array $data 535 | * @return mixed 536 | */ 537 | public function updateOneByCriteria(array $criteria, array $data = []) 538 | { 539 | $entity = $this->query->where($criteria)->one(); 540 | 541 | return $this->updateEntity($entity, $data); 542 | } 543 | 544 | 545 | /** 546 | * @param $key 547 | * @param $value 548 | * @param array $data 549 | * @param string $operation 550 | * @return int number of records updated 551 | */ 552 | public function updateManyBy($key, $value, array $data = [], $operation = '=') 553 | { 554 | return $this->model->updateAll($data, [$operation, $key, $value]); 555 | } 556 | 557 | /** 558 | * @param array $criteria 559 | * @param array $data 560 | * @return int number of records updated 561 | */ 562 | public function updateManyByCriteria(array $criteria = [], array $data = []) 563 | { 564 | if(depth($criteria) > 1) 565 | array_unshift($criteria, 'and'); 566 | 567 | return $this->model->updateAll($data, $criteria); 568 | } 569 | 570 | /** 571 | * @param array $ids 572 | * @param array $data 573 | * @return int number of records updated 574 | */ 575 | public function updateManyByIds(array $ids, array $data = []) 576 | { 577 | return $this->model->updateAll($data, ['in', self::PRIMARY_KEY, $ids]); 578 | } 579 | 580 | 581 | /** 582 | * @param array $ids 583 | * @return bool 584 | */ 585 | public function allExist(array $ids) 586 | { 587 | // TODO: Implement allExist() method. 588 | } 589 | 590 | /** 591 | * @param $id 592 | * @return boolean|integer number of rows deleted 593 | */ 594 | public function deleteOneById($id) 595 | { 596 | $entity = $this->model->findOne([self::PRIMARY_KEY=>$id]); 597 | 598 | return $entity->delete(); 599 | } 600 | 601 | 602 | /** 603 | * @param $key 604 | * @param $value 605 | * @param string $operation 606 | * @return bool|int number of rows deleted 607 | */ 608 | public function deleteOneBy($key, $value, $operation = '=') 609 | { 610 | $entity = $this->model->findOne([$operation, $key, $value]); 611 | 612 | return $entity->delete(); 613 | } 614 | 615 | /** 616 | * @param array $criteria 617 | * @return boolean|integer number of rows deleted 618 | */ 619 | public function deleteOneByCriteria(array $criteria = []) 620 | { 621 | $entity = $this->model->findOne($criteria); 622 | 623 | return $entity->delete(); 624 | } 625 | 626 | /** 627 | * @param $key 628 | * @param $value 629 | * @param string $operation 630 | * @return bool|int number of rows deleted 631 | */ 632 | public function deleteManyBy($key, $value, $operation = '=') 633 | { 634 | return $this->model->deleteAll([$operation, $key, $value]); 635 | } 636 | 637 | /** 638 | * @param array $criteria 639 | * @return boolean|integer number of rows deleted 640 | */ 641 | public function deleteManyByCriteria(array $criteria = []) 642 | { 643 | if(depth($criteria) > 1) 644 | array_unshift($criteria, 'and'); 645 | 646 | return $this->model->deleteAll($criteria); 647 | } 648 | 649 | 650 | 651 | /** 652 | * @param array $ids 653 | * @return boolean|integer number of rows deleted 654 | */ 655 | public function deleteManyByIds(array $ids) 656 | { 657 | return $this->model->deleteAll(['in', self::PRIMARY_KEY, $ids]); 658 | } 659 | 660 | 661 | /** 662 | * @return mixed 663 | */ 664 | public function searchByCriteria() 665 | { 666 | $search = !empty($_GET['search']) ? explode(',',$_GET['search']) : null; 667 | 668 | if(!empty($_GET['fields'])){ 669 | $fields = explode(',',$_GET['fields']); 670 | $this->columns($fields); 671 | } 672 | 673 | if(!empty($perPage)){ 674 | $this->limit($perPage); 675 | } 676 | 677 | if(!empty($_GET['with'])){ 678 | $with = explode(',',$_GET['with']); 679 | $this->with($with); 680 | } 681 | 682 | 683 | if(!empty($_GET['perPage'])){ 684 | $this->limit($_GET['perPage']); 685 | } 686 | 687 | if(!empty($_GET['page'])){ 688 | $this->offset($_GET['page'] * $this->limit); 689 | } 690 | 691 | 692 | if(!empty($search)){ 693 | $criteria = []; 694 | foreach ($search as $string){ 695 | $components = explode(':', $string); 696 | 697 | array_push($criteria ,[$components[1],$components[0],$components[2]]); 698 | } 699 | 700 | return $this->findManyByCriteria($criteria); 701 | 702 | }else{ 703 | return $this->findAll(); 704 | } 705 | 706 | } 707 | 708 | 709 | } 710 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore --------------------------------------------------------------------------------