├── .gitignore ├── .scrutinizer.yml ├── LICENSE ├── README.md ├── composer.json ├── config └── model-json-storage.php ├── phpunit.xml ├── src ├── BuilderOverride.php ├── BuildsQueriesOverride.php ├── ModelJsonStorage.php ├── ModelJsonStorageServiceProviderProvider.php └── ModelOverride.php └── tests ├── Fakers └── UsersFaker.php ├── ModelJsonStorageTestCase.php ├── Models ├── UserDatabase.php ├── UserJson.php └── UserJsonWithoutPrimaryKey.php ├── Unit ├── BuilderOverrideTest.php ├── BuildsQueriesOverrideTest.php └── ModelOverrideTest.php └── database └── migrations └── 2014_10_12_000000_create_users_test_table.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.phar 2 | composer.lock 3 | vendor 4 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | paths: [src/*] 3 | excluded_paths: [test/*] 4 | checks: 5 | php: true 6 | tools: 7 | php_mess_detector: true 8 | php_sim: true 9 | php_cpd: false # Must be disabled to use php_sim instead 10 | php_pdepend: true 11 | php_code_coverage: true 12 | php_code_sniffer: 13 | config: 14 | standard: PSR4 15 | filter: 16 | paths: ['src'] 17 | sensiolabs_security_checker: true 18 | php_loc: 19 | enabled: true 20 | excluded_dirs: [vendor, test] 21 | php_cpd: 22 | enabled: true 23 | excluded_dirs: [vendor, test] 24 | build: 25 | nodes: 26 | analysis: 27 | project_setup: 28 | override: true 29 | tests: 30 | override: 31 | - php-scrutinizer-run --enable-security-analysis 32 | - 33 | command: 'vendor/bin/phpunit --coverage-clover=code-coverage' 34 | coverage: 35 | file: 'code-coverage' 36 | format: 'clover' 37 | environment: 38 | php: 39 | version: "7.1" 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Arthur LORENT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-model-json-storage 2 | 3 | [![Source Code](https://img.shields.io/badge/source-okipa/laravel--model--json--storage-blue.svg)](https://github.com/Okipa/laravel-model-json-storage) 4 | [![Latest Version](https://img.shields.io/github/release/okipa/laravel-model-json-storage.svg?style=flat-square)](https://github.com/Okipa/laravel-model-json-storage/releases) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/okipa/laravel-model-json-storage.svg?style=flat-square)](https://packagist.org/packages/okipa/laravel-model-json-storage) 6 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) 7 | [![Build Status](https://scrutinizer-ci.com/g/Okipa/laravel-model-json-storage/badges/build.png?b=master)](https://scrutinizer-ci.com/g/Okipa/laravel-model-json-storage/build-status/master) 8 | [![Code Coverage](https://scrutinizer-ci.com/g/Okipa/laravel-model-json-storage/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/Okipa/laravel-model-json-storage/?branch=master) 9 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Okipa/laravel-model-json-storage/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Okipa/laravel-model-json-storage/?branch=master) 10 | 11 | **:warning: This package has been abandonned :warning:** 12 | Do not hesitate to contact me if you want to make it evolve and to maintain it. 13 | 14 | Storing your models in a json file rather than in database (single or few lines recording) can be a good option. 15 | This package saves you to create a table for a ridiculous amount of lines, improves the data recovery performances, and allows you to store and access to your models from a json files as you would do it in database. 16 | 17 | ------------------------------------------------------------------------------------------------------------------------ 18 | 19 | ## To read before use 20 | Please keep in mind that : 21 | - The purpose of this package is to store your model instances in json. 22 | - Consequently, the json file is always entirely read when you access to your data 23 | - Consequently, you should **NOT** use this package if you have a lot of instances to store, it could cause performance issues rather than improve it. 24 | - All the query-related and model-related functionalities are not available (especially those which use database), this package has been made for quite simple use cases. 25 | - This package enables you to manipulate models as if it they would been stored in database but it always uses the [Illuminate\Support\Collection methods](https://laravel.com/docs/5.4/collections) methods under the hood. 26 | 27 | ------------------------------------------------------------------------------------------------------------------------ 28 | 29 | ## Installation 30 | - Install the package with composer : 31 | ```bash 32 | composer require okipa/laravel-model-json-storage 33 | ``` 34 | 35 | - Laravel 5.5+ uses Package Auto-Discovery, so doesn't require you to manually add the ServiceProvider. 36 | If you don't use auto-discovery or if you use a Laravel 5.0- version, add the package service provider in the `register()` method from your `app/Providers/AppServiceProvider.php` : 37 | ```php 38 | // laravel model json storage 39 | // https://github.com/Okipa/laravel-model-json-storage 40 | $this->app->register(Okipa\LaravelModelJsonStorage\ModelJsonStorageServiceProvider::class); 41 | ``` 42 | 43 | ------------------------------------------------------------------------------------------------------------------------ 44 | 45 | ## Usage 46 | First, add the `ModelJsonStorage` trait in your model. 47 | 48 | ```php 49 | class MyTestModel extends Illuminate\Database\Eloquent\Model 50 | { 51 | use Okipa\LaravelModelJsonStorage\ModelJsonStorage; 52 | 53 | [...] 54 | } 55 | ``` 56 | 57 | Then, just manipulate your model normally. 58 | After a storage, you will see a json file named with your model title in the path defined in the `model-json-storage` config file. 59 | 60 | ```php 61 | $testModel = app(MyTestModel::class)->create([ 62 | 'name' => 'John Doe', 63 | 'email' => 'john@doe.com', 64 | 'password' => Hash::make('secret'), 65 | ]); 66 | ``` 67 | 68 | ```php 69 | $testModel = app(MyTestModel::class)->all(); 70 | ``` 71 | 72 | ```php 73 | $testModel = app(MyTestModel::class)->where('email', 'john@doe.com')->first(); 74 | ``` 75 | 76 | ```php 77 | $testModel->update([ 78 | 'name' => 'Gary Cook' 79 | ]); 80 | ``` 81 | 82 | ```php 83 | $testModel->delete(); 84 | ``` 85 | 86 | ------------------------------------------------------------------------------------------------------------------------ 87 | 88 | ## Customize configuration 89 | To personalize the package configuration, you have to publish it first with the following script : 90 | ```bash 91 | php artisan vendor:publish --tag=model-json-storage::config 92 | ``` 93 | Then, open the published package configuration file (`config/model-json-storage.php`) and override the default configuration by setting your own values for the following items : 94 | - json storage path 95 | - ... that's all for now. 96 | 97 | ------------------------------------------------------------------------------------------------------------------------ 98 | 99 | ## API 100 | The most used query-related and model-related methods have been overridden to allow you to use your json stored model as usual. 101 | Retrieve the list of the available methods bellow. 102 | However, if you want to add a method for your personal needs, do not hesitate to improve this package with a PR. 103 | 104 | ### Available Illuminate\Database\Eloquent\Model methods 105 | - [save()](https://laravel.com/api/5.0/Illuminate/Database/Eloquent/Model.html#method_save) 106 | - [update()](https://laravel.com/api/5.0/Illuminate/Database/Eloquent/Model.html#method_update) 107 | - [delete()](https://laravel.com/api/5.0/Illuminate/Database/Eloquent/Model.html#method_delete) 108 | - [all()](https://laravel.com/api/5.0/Illuminate/Database/Eloquent/Model.html#method_all) 109 | 110 | ### Available Illuminate\Database\Query\Builder methods 111 | - [get()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_get) 112 | - [Select()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_select) 113 | - [addSelect()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_addSelect) 114 | - [where()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_where) 115 | - [whereNull()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_whereNull) 116 | - [whereNotNull()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_whereNotNull) 117 | - [orderBy()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_orderBy) 118 | - [orderByDesc()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_orderByDesc) 119 | - [whereIn()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_whereIn) 120 | - [whereNotIn()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_whereNotIn) 121 | - [find()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_find) 122 | - [findOrFail()](https://laravel.com/api/5.0/Illuminate/Database/Eloquent/Builder.html#method_findOrFail) 123 | - [paginate()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_paginate) 124 | - [value()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_value) 125 | - [pluck()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_pluck) 126 | - [count()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_count) 127 | - [min()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_min) 128 | - [max()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_max) 129 | - [avg()](https://laravel.com/api/5.0/Illuminate/Database/Query/Builder.html#method_avg) 130 | 131 | ### Available Illuminate\Database\Concerns\BuildsQueries methods 132 | - [first()](https://laravel.com/api/5.0/Illuminate/Database/Concerns/BuildsQueries.html#method_first) 133 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "okipa/laravel-model-json-storage", 3 | "description": "Storing your models in a json file rather than in database (single or few lines recording) can be a good option. This package saves you to create a table for a ridiculous amount of lines, improves the data recovery performances, and allows you to store and access to your models from a json files as you would do it in database.", 4 | "keywords": [ 5 | "okipa", 6 | "package", 7 | "laravel", 8 | "php", 9 | "model", 10 | "json", 11 | "storage" 12 | ], 13 | "homepage": "https://github.com/Okipa/laravel-model-json-storage", 14 | "license": "MIT", 15 | "authors": [ 16 | { 17 | "name": "Arthur LORENT", 18 | "email": "arthur.lorent@gmail.com", 19 | "role": "Developer" 20 | } 21 | ], 22 | "require": { 23 | "php": ">=7.0", 24 | "illuminate/support": "~5.0" 25 | }, 26 | "require-dev": { 27 | "orchestra/testbench": "^3.6" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Okipa\\LaravelModelJsonStorage\\": "src/" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "Okipa\\LaravelModelJsonStorage\\Test\\": "tests/" 37 | } 38 | }, 39 | "extra": { 40 | "laravel": { 41 | "providers": [ 42 | "Okipa\\LaravelModelJsonStorage\\ModelJsonStorageServiceProvider" 43 | ] 44 | } 45 | }, 46 | "minimum-stability": "stable" 47 | } 48 | -------------------------------------------------------------------------------- /config/model-json-storage.php: -------------------------------------------------------------------------------- 1 | 'app/json', 6 | ]; -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/ 14 | ./tests/database/ 15 | ./tests/Fakers/ 16 | ./tests/Models/ 17 | 18 | 19 | 20 | 21 | ./src/ 22 | 23 | ./src/ModelJsonStorageServiceProviderProvider.php 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/BuilderOverride.php: -------------------------------------------------------------------------------- 1 | selects[] = $column; 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Add a new select column to the query. 66 | * 67 | * @param string $column 68 | * 69 | * @return $this 70 | */ 71 | public function addSelect(string $column) 72 | { 73 | $this->selects[] = $column; 74 | 75 | return $this; 76 | } 77 | 78 | /** 79 | * Add a "where in" clause to the query. 80 | * 81 | * @param string $column 82 | * @param array $values 83 | * 84 | * @return $this 85 | */ 86 | public function whereIn(string $column, array $values) 87 | { 88 | $this->whereIns[] = compact('column', 'values'); 89 | 90 | return $this; 91 | } 92 | 93 | /** 94 | * Add a "where not in" clause to the query. 95 | * 96 | * @param string $column 97 | * @param array $values 98 | * 99 | * @return $this 100 | */ 101 | public function whereNotIn(string $column, array $values) 102 | { 103 | $this->whereNotIns[] = compact('column', 'values'); 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * Add an "order by" clause to the query. 110 | * 111 | * @param string $column 112 | * @param string $direction 113 | * 114 | * @return $this 115 | */ 116 | public function orderBy(string $column, string $direction = 'asc') 117 | { 118 | $this->orderBys[] = compact('column', 'direction'); 119 | 120 | return $this; 121 | } 122 | 123 | /** 124 | * Find a model by its primary key or throw an exception. 125 | * 126 | * @param mixed $id 127 | * @param array $columns 128 | * 129 | * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection 130 | * @throws \Illuminate\Database\Eloquent\ModelNotFoundException 131 | */ 132 | public function findOrFail(int $id, array $columns = ['*']) 133 | { 134 | $result = $this->find($id, $columns); 135 | if (! is_null($result)) { 136 | return $result; 137 | } 138 | throw (new ModelNotFoundException)->setModel( 139 | get_class($this), $id 140 | ); 141 | } 142 | 143 | /** 144 | * Execute a query for a single record by ID. 145 | * 146 | * @param int $id 147 | * @param array $columns 148 | * 149 | * @return mixed|static 150 | */ 151 | public function find(int $id, array $columns = ['*']) 152 | { 153 | return $this->where('id', '=', $id)->first($columns); 154 | } 155 | 156 | /** 157 | * Execute the query and get the first result. 158 | * 159 | * @param array $columns 160 | * 161 | * @return Model|null 162 | */ 163 | abstract public function first(array $columns = ['*']); 164 | 165 | /** 166 | * Add a basic where clause to the query. 167 | * 168 | * @param string $column 169 | * @param mixed $operator 170 | * @param mixed $value 171 | * 172 | * @return $this 173 | */ 174 | public function where(string $column, $operator = null, $value = null) 175 | { 176 | if (! isset($value)) { 177 | $value = $operator; 178 | $operator = '='; 179 | } 180 | $this->wheres[] = compact('column', 'operator', 'value'); 181 | 182 | return $this; 183 | } 184 | 185 | /** 186 | * Get a single column's value from the first result of a query. 187 | * 188 | * @param string $column 189 | * The "pluck" collection method is used under the hood. 190 | * 191 | * @return Collection 192 | */ 193 | public function value(string $column) 194 | { 195 | return $this->get()->pluck($column)->first(); 196 | } 197 | 198 | /** 199 | * Execute the query as a "select" statement. 200 | * 201 | * @param array $columns 202 | * 203 | * @return Collection 204 | */ 205 | public function get(array $columns = ['*']) 206 | { 207 | if ($columns !== ['*']) { 208 | $this->selects = $columns; 209 | } 210 | $modelsCollection = $this->loadModelsFromJson(); 211 | $this->applyWhereClauses($modelsCollection); 212 | $this->applyWhereInClauses($modelsCollection); 213 | $this->applyWhereNotInClauses($modelsCollection); 214 | $this->applyOrderByClauses($modelsCollection); 215 | $this->applySelectClauses($modelsCollection); 216 | 217 | return $modelsCollection->values(); 218 | } 219 | 220 | /** 221 | * Apply the "where" clauses on the collection. 222 | * 223 | * @param $modelsCollection 224 | * 225 | * @return void 226 | */ 227 | protected function applyWhereClauses(Collection &$modelsCollection) 228 | { 229 | if (! empty($this->wheres) && ! $modelsCollection->isEmpty()) { 230 | foreach ($this->wheres as $where) { 231 | $modelsCollection = $modelsCollection->where($where['column'], $where['operator'], $where['value']); 232 | } 233 | } 234 | } 235 | 236 | /** 237 | * Apply the "whereIn" clauses on the collection. 238 | * 239 | * @param $modelsCollection 240 | * 241 | * @return void 242 | */ 243 | protected function applyWhereInClauses(Collection &$modelsCollection) 244 | { 245 | if (! empty($this->whereIns) && ! $modelsCollection->isEmpty()) { 246 | foreach ($this->whereIns as $whereIn) { 247 | $modelsCollection = $modelsCollection->whereIn($whereIn['column'], $whereIn['values']); 248 | } 249 | } 250 | } 251 | 252 | /** 253 | * Apply the "whereNotIn" clauses on the collection. 254 | * 255 | * @param $modelsCollection 256 | * 257 | * @return void 258 | */ 259 | protected function applyWhereNotInClauses(Collection &$modelsCollection) 260 | { 261 | if (! empty($this->whereNotIns) && ! $modelsCollection->isEmpty()) { 262 | foreach ($this->whereNotIns as $whereNotIn) { 263 | $modelsCollection = $modelsCollection->whereNotIn($whereNotIn['column'], $whereNotIn['values']); 264 | } 265 | } 266 | } 267 | 268 | /** 269 | * Apply the "orderBy" clauses on the collection. 270 | * 271 | * @param $modelsCollection 272 | * 273 | * @return void 274 | */ 275 | protected function applyOrderByClauses(Collection &$modelsCollection) 276 | { 277 | if (! empty($this->orderBys) && ! $modelsCollection->isEmpty()) { 278 | foreach ($this->orderBys as $orders) { 279 | $modelsCollection = $modelsCollection->sortBy( 280 | $orders['column'], 281 | SORT_REGULAR, 282 | $orders['direction'] === 'desc' 283 | ); 284 | } 285 | } 286 | } 287 | 288 | /** 289 | * Apply the "select" clauses on the collection. 290 | * 291 | * @param $modelsCollection 292 | * 293 | * @return void 294 | */ 295 | protected function applySelectClauses(Collection &$modelsCollection) 296 | { 297 | if (! empty($this->selects) && $this->selects !== ['*'] && ! $modelsCollection->isEmpty()) { 298 | $selectCollection = new Collection(); 299 | $modelsCollection->each(function($model) use ($selectCollection) { 300 | $selectCollection->push(collect($model->toArray())->only(array_unique($this->selects))); 301 | }); 302 | $modelsCollection = $selectCollection; 303 | } 304 | } 305 | 306 | /** 307 | * Get an array with the values of a given column. 308 | * 309 | * @param string $column 310 | * @param string null|$key 311 | * 312 | * @return Collection 313 | */ 314 | public function pluck(string $column, string $key = null) 315 | { 316 | return $this->get()->pluck($column, $key); 317 | } 318 | 319 | /** 320 | * Retrieve the "count" result of the query. 321 | * 322 | * @param array $columns 323 | * 324 | * @return int 325 | */ 326 | public function count(array $columns = ['*']) 327 | { 328 | return $this->get($columns)->count(); 329 | } 330 | 331 | /** 332 | * Retrieve the minimum value of a given column. 333 | * 334 | * @param $column 335 | * 336 | * @return int 337 | */ 338 | public function min(string $column) 339 | { 340 | return $this->get()->min($column); 341 | } 342 | 343 | /** 344 | * Retrieve the maximum value of a given column. 345 | * 346 | * @param string $column 347 | * 348 | * @return int 349 | */ 350 | public function max(string $column) 351 | { 352 | return $this->get()->max($column); 353 | } 354 | 355 | /** 356 | * Retrieve the average of the values of a given column. 357 | * 358 | * @param string $column 359 | * 360 | * @return mixed 361 | */ 362 | public function avg($column) 363 | { 364 | return $this->get()->avg($column); 365 | } 366 | 367 | /** 368 | * Paginate the given query. 369 | * 370 | * @param int|null $perPage 371 | * @param array $columns 372 | * @param string $pageName 373 | * @param int|null $page 374 | * 375 | * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 376 | * @throws \InvalidArgumentException 377 | */ 378 | public function paginate(int $perPage = null, array $columns = ['*'], string $pageName = 'page', int $page = null) 379 | { 380 | $page = $page ?: Paginator::resolveCurrentPage($pageName); 381 | $perPage = $perPage ?: $this->getPerPage(); 382 | $modelsCollection = $this->get($columns); 383 | $items = $modelsCollection->forPage($page, $perPage)->values(); 384 | $total = $modelsCollection->count(); 385 | 386 | return new LengthAwarePaginator( 387 | $items, 388 | $total, 389 | $perPage, 390 | $page, 391 | [ 392 | 'path' => Paginator::resolveCurrentPath(), 393 | 'pageName' => $pageName, 394 | ] 395 | ); 396 | } 397 | 398 | /** 399 | * Load all of the models from the json file in the "modelsFromJson" variable. 400 | * 401 | * @return Collection 402 | */ 403 | abstract protected function loadModelsFromJson(); 404 | } 405 | -------------------------------------------------------------------------------- /src/BuildsQueriesOverride.php: -------------------------------------------------------------------------------- 1 | get($columns)->first(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ModelJsonStorage.php: -------------------------------------------------------------------------------- 1 | getRawArrayFromJson(); 65 | foreach ($modelsArray as $key => $modelArray) { 66 | $modelsArray[$key] = app($this->getMorphClass())->setRawAttributes($modelArray); 67 | } 68 | 69 | return collect($modelsArray); 70 | } 71 | 72 | /** 73 | * Get an array containing all of the models from the json file. 74 | * 75 | * @return array 76 | */ 77 | protected function getRawArrayFromJson() 78 | { 79 | $modelsArray = []; 80 | if (file_exists($this->getJsonStoragePath())) { 81 | $modelsArray = $this->fromJson(File::get($this->getJsonStoragePath())); 82 | } 83 | 84 | return $modelsArray; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/ModelJsonStorageServiceProviderProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 12 | __DIR__ . '/../config/model-json-storage.php' => config_path('model-json-storage.php'), 13 | ], 'model-json-storage::config'); 14 | } 15 | 16 | public function register() 17 | { 18 | $this->mergeConfigFrom( 19 | __DIR__ . '/../config/model-json-storage.php', 'model-json-storage' 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ModelOverride.php: -------------------------------------------------------------------------------- 1 | get($columns); 21 | } 22 | 23 | /** 24 | * Add a "where not in" clause to the query. 25 | * 26 | * @param string $column 27 | * @param array $values 28 | * 29 | * @return $this 30 | */ 31 | abstract public function whereNotIn(string $column, array $values); 32 | 33 | 34 | 35 | /** 36 | * Get the class name of the parent model. 37 | * 38 | * @return string 39 | */ 40 | abstract public function getMorphClass(); 41 | 42 | /** 43 | * Load all of the models from the json file in the "modelsFromJson" variable. 44 | * 45 | * @return Collection 46 | */ 47 | abstract protected function loadModelsFromJson(); 48 | 49 | /** 50 | * Execute the query as a "select" statement. 51 | * 52 | * @param array $columns 53 | * 54 | * @return Collection 55 | */ 56 | abstract public function get(array $columns = ['*']); 57 | 58 | /** 59 | * Fill the model with an array of attributes. 60 | * 61 | * @param array $attributes 62 | * 63 | * @return $this 64 | * @throws \Illuminate\Database\Eloquent\MassAssignmentException 65 | */ 66 | abstract public function fill(array $attributes); 67 | 68 | /** 69 | * Determine if the model uses timestamps. 70 | * 71 | * @return bool 72 | */ 73 | abstract public function usesTimestamps(); 74 | 75 | /** 76 | * Get a fresh timestamp for the model. 77 | * 78 | * @return string 79 | */ 80 | abstract public function freshTimestampString(); 81 | 82 | /** 83 | * Set the value of the "created at" attribute. 84 | * 85 | * @param mixed $value 86 | * 87 | * @return $this 88 | */ 89 | abstract public function setCreatedAt($value); 90 | 91 | /** 92 | * Set the value of the "updated at" attribute. 93 | * 94 | * @param mixed $value 95 | * 96 | * @return $this 97 | */ 98 | abstract public function setUpdatedAt($value); 99 | 100 | /** 101 | * Get an attribute from the model. 102 | * 103 | * @param string $key 104 | * 105 | * @return mixed 106 | */ 107 | abstract public function getAttribute($key); 108 | 109 | /** 110 | * Get all of the current attributes on the model. 111 | * 112 | * @return array 113 | */ 114 | abstract public function getAttributes(); 115 | 116 | /** 117 | * Make the given, typically hidden, attributes visible. 118 | * 119 | * @param array|string $attributes 120 | * 121 | * @return $this 122 | */ 123 | abstract public function makeVisible($attributes); 124 | 125 | /** 126 | * Set the array of model attributes. No checking is done. 127 | * 128 | * @param array $attributes 129 | * @param bool $sync 130 | * 131 | * @return $this 132 | */ 133 | abstract public function setRawAttributes(array $attributes, $sync = false); 134 | 135 | /** 136 | * Get the hidden attributes for the model. 137 | * 138 | * @return array 139 | */ 140 | abstract public function getHidden(); 141 | 142 | /** 143 | * Get the primary key for the model. 144 | * 145 | * @return string 146 | */ 147 | abstract public function getKeyName(); 148 | 149 | /** 150 | * Save the model to the json file. 151 | * 152 | * @param array $options 153 | * 154 | * @return bool 155 | */ 156 | public function save(array $options = []) 157 | { 158 | return $this->saveToJson(); 159 | } 160 | 161 | /** 162 | * Save the model to the json file. 163 | * 164 | * @return bool 165 | */ 166 | protected function saveToJson() 167 | { 168 | if ($this->{$this->getKeyName()}) { 169 | $this->updateModelInJson(); 170 | } else { 171 | $this->createModelInJson(); 172 | } 173 | 174 | return true; 175 | } 176 | 177 | /** 178 | * Update the model in the json file. 179 | * 180 | * @return void 181 | */ 182 | protected function updateModelInJson() 183 | { 184 | if ($this->usesTimestamps()) { 185 | $this->setTimestampFields(true); 186 | } 187 | $withoutCurrentModel = $this->whereNotIn( 188 | $this->getKeyName(), 189 | [$this->getAttribute($this->getKeyName())] 190 | )->get(); 191 | $models = $withoutCurrentModel->push($this->makeVisible($this->getHidden()))->sortBy($this->getKeyName()); 192 | File::put($this->getJsonStoragePath(), $models->toJson()); 193 | } 194 | 195 | /** 196 | * Set the model timestamp field 197 | * 198 | * @param bool $update 199 | * 200 | * @return void 201 | */ 202 | protected function setTimestampFields($update = false) 203 | { 204 | $now = $this->freshTimestampString(); 205 | $this->setUpdatedAt($now); 206 | if (! $update) { 207 | $this->setCreatedAt($now); 208 | } 209 | } 210 | 211 | /** 212 | * Get the storage path for the model json file. 213 | * 214 | * @return string 215 | */ 216 | public function getJsonStoragePath() 217 | { 218 | $modelName = str_slug(last(explode('\\', $this->getMorphClass()))); 219 | $configStoragePath = storage_path(config('model-json-storage.storage_path')); 220 | if (! is_dir($configStoragePath)) { 221 | mkdir($configStoragePath, 0777, true); 222 | } 223 | $jsonStoragePath = $configStoragePath . '/' . $modelName . '.json'; 224 | 225 | return $jsonStoragePath; 226 | } 227 | 228 | /** 229 | * Save a new model in the json file. 230 | * 231 | * @return void 232 | */ 233 | protected function createModelInJson() 234 | { 235 | if ($this->usesTimestamps()) { 236 | $this->setTimestampFields(); 237 | } 238 | $this->setModelPrimaryKeyValue(); 239 | $models = $this->all()->push($this->makeVisible($this->getHidden())); 240 | File::put($this->getJsonStoragePath(), $models->toJson()); 241 | } 242 | 243 | /** 244 | * Set the model primary key by incrementing from the bigger id found in the json file. 245 | * 246 | * @return void 247 | */ 248 | protected function setModelPrimaryKeyValue() 249 | { 250 | $modelPrimaryKeyValue = 1; 251 | $modelsCollection = $this->loadModelsFromJson(); 252 | if (! $modelsCollection->isEmpty()) { 253 | $lastModelId = $modelsCollection->sortBy('id')->last()->getAttribute($this->getKeyName()); 254 | $modelPrimaryKeyValue = $lastModelId + 1; 255 | } 256 | $this->setRawAttributes(array_merge(['id' => $modelPrimaryKeyValue], $this->getAttributes())); 257 | } 258 | 259 | /** 260 | * Update the model in the json file. 261 | * 262 | * @param array $attributes 263 | * @param array $options 264 | * 265 | * @return mixed 266 | */ 267 | public function update(array $attributes = [], array $options = []) 268 | { 269 | return $this->fill($attributes)->save($options); 270 | } 271 | 272 | /** 273 | * Delete the model from the json file. 274 | * 275 | * @return bool|null 276 | * @throws Exception 277 | */ 278 | public function delete() 279 | { 280 | if (is_null($this->getKeyName())) { 281 | throw new Exception('No primary key defined on model.'); 282 | } 283 | $this->deleteModelFromJson(); 284 | 285 | return true; 286 | } 287 | 288 | /** 289 | * Delete the model from the json file. 290 | * 291 | * @return void 292 | */ 293 | protected function deleteModelFromJson() 294 | { 295 | $withoutCurrentModel = $this->whereNotIn( 296 | $this->getKeyName(), 297 | [$this->getAttribute($this->getKeyName())] 298 | )->get(); 299 | File::put($this->getJsonStoragePath(), $withoutCurrentModel->values()->toJson()); 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /tests/Fakers/UsersFaker.php: -------------------------------------------------------------------------------- 1 | generateFakeUserData(); 18 | $databaseUser = $this->createUniqueDatabaseUser($fakeUserData); 19 | $jsonUser = $this->createUniqueJsonUser($fakeUserData); 20 | 21 | return collect([ 22 | 'databaseUser' => $databaseUser, 23 | 'jsonUser' => $jsonUser, 24 | ]); 25 | } 26 | 27 | public function generateFakeUserData() 28 | { 29 | $this->clearPassword = $this->faker->password; 30 | 31 | return [ 32 | 'name' => $this->faker->name, 33 | 'email' => $this->faker->email, 34 | 'password' => Hash::make($this->clearPassword), 35 | ]; 36 | } 37 | 38 | public function createUniqueDatabaseUser(array $data) 39 | { 40 | $databaseUser = app(UserDatabase::class)->create($data); 41 | 42 | return app(UserDatabase::class)->find($databaseUser->id); 43 | } 44 | 45 | public function createUniqueJsonUser(array $data) 46 | { 47 | return app(UserJson::class)->create($data); 48 | } 49 | 50 | public function createMultipleDatabaseUsers(int $count) 51 | { 52 | $databaseUsers = new Collection(); 53 | $jsonUsers = new Collection(); 54 | foreach ($this->generateFakeUsersData($count) as $fakeUserData) { 55 | $databaseUsers->push($this->createUniqueDatabaseUser($fakeUserData)); 56 | $jsonUsers->push($this->createUniqueJsonUser($fakeUserData)); 57 | } 58 | 59 | return collect([ 60 | 'databaseUsers' => $databaseUsers, 61 | 'jsonUsers' => $jsonUsers, 62 | ]); 63 | } 64 | 65 | public function generateFakeUsersData(int $count) 66 | { 67 | $data = []; 68 | for ($ii = 0; $ii < $count; $ii++) { 69 | $data[] = [ 70 | 'name' => $this->faker->name, 71 | 'email' => $this->faker->email, 72 | 'password' => Hash::make($this->clearPassword), 73 | ]; 74 | } 75 | 76 | return $data; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tests/ModelJsonStorageTestCase.php: -------------------------------------------------------------------------------- 1 | set('database.default', 'testing'); 24 | $app['config']->set('database.connections.testing', [ 25 | 'driver' => 'sqlite', 26 | 'database' => ':memory:', 27 | 'prefix' => '', 28 | ]); 29 | $app['config']->set('model-json-storage.storage_path', 'app/json'); 30 | } 31 | 32 | /** 33 | * Setup the test environment. 34 | */ 35 | protected function setUp() 36 | { 37 | parent::setUp(); 38 | $this->loadMigrationsFrom([ 39 | '--database' => 'testing', 40 | '--path' => realpath(__DIR__ . '/database/migrations'), 41 | ]); 42 | File::deleteDirectory(storage_path(config('model-json-storage.storage_path'))); 43 | $this->faker = Factory::create(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/Models/UserDatabase.php: -------------------------------------------------------------------------------- 1 | createMultipleDatabaseUsers(3); 22 | $getDatabaseUsersArray = app(UserDatabase::class)->get()->toArray(); 23 | $getJsonUsersArray = app(UserJson::class)->get()->toArray(); 24 | // notice : we remove the created_at and updated_at fields that are not relevant and can be different 25 | foreach ($getDatabaseUsersArray as $key => $databaseUserArray) { 26 | unset($databaseUserArray['created_at']); 27 | unset($databaseUserArray['updated_at']); 28 | $getDatabaseUsersArray[$key] = $databaseUserArray; 29 | } 30 | foreach ($getJsonUsersArray as $key => $jsonUserArray) { 31 | unset($jsonUserArray['created_at']); 32 | unset($jsonUserArray['updated_at']); 33 | $getJsonUsersArray[$key] = $jsonUserArray; 34 | } 35 | $this->assertEquals($getDatabaseUsersArray, $getJsonUsersArray); 36 | $getIdAndEmailDatabaseUsers = app(UserDatabase::class)->get(['id', 'email']); 37 | $getIdAndEmailJsonUsers = app(UserJson::class)->get(['id', 'email']); 38 | // notice : we compare the models one by one because query builder does return objects from get() in a random way 39 | $getIdAndEmailDatabaseUsers->each(function($databaseUser) use ($getIdAndEmailJsonUsers) { 40 | $jsonUserToCompare = $getIdAndEmailJsonUsers->where('id', $databaseUser->id)->first(); 41 | $this->assertEquals($databaseUser->toArray(), $jsonUserToCompare->toArray()); 42 | }); 43 | } 44 | 45 | public function testSelect() 46 | { 47 | $this->createMultipleDatabaseUsers(3); 48 | $selectedDatabaseUser = app(UserDatabase::class)->select('name')->get(); 49 | $selectedJsonUser = app(UserJson::class)->select('name')->get(); 50 | $this->assertEquals($selectedDatabaseUser->toArray(), $selectedJsonUser->toArray()); 51 | } 52 | 53 | public function testAddSelect() 54 | { 55 | $this->createMultipleDatabaseUsers(3); 56 | $selectedDatabaseUser = app(UserDatabase::class)->select('id')->addSelect('name')->get(); 57 | $selectedJsonUser = app(UserJson::class)->select('id')->addSelect('name')->get(); 58 | $this->assertEquals($selectedDatabaseUser->toArray(), $selectedJsonUser->toArray()); 59 | } 60 | 61 | public function testWhere() 62 | { 63 | $this->createMultipleDatabaseUsers(3); 64 | $whereDatabaseUsers = app(UserDatabase::class)->where('id', 2)->get(); 65 | $whereJsonUsers = app(UserJson::class)->where('id', 2)->get(); 66 | $this->assertEquals($whereDatabaseUsers->toArray(), $whereJsonUsers->toArray()); 67 | } 68 | 69 | public function testWhereIn() 70 | { 71 | $this->createMultipleDatabaseUsers(3); 72 | $whereInDatabaseUsers = app(UserDatabase::class)->whereIn('id', [2, 3])->get(); 73 | $whereInJsonUsers = app(UserJson::class)->whereIn('id', [2, 3])->get(); 74 | $this->assertEquals($whereInDatabaseUsers->toArray(), $whereInJsonUsers->toArray()); 75 | } 76 | 77 | public function testWhereNotIn() 78 | { 79 | $this->createMultipleDatabaseUsers(3); 80 | $whereInDatabaseUsers = app(UserDatabase::class)->whereNotIn('id', [1, 3])->get(); 81 | $whereInJsonUsers = app(UserJson::class)->whereNotIn('id', [1, 3])->get(); 82 | $this->assertEquals($whereInDatabaseUsers->toArray(), $whereInJsonUsers->toArray()); 83 | } 84 | 85 | public function testOrderBy() 86 | { 87 | $this->createMultipleDatabaseUsers(3); 88 | $orderedByIdDescDatabaseUsers = app(UserDatabase::class)->orderBy('id', 'desc')->get(); 89 | $orderedByIdDescJsonUsers = app(UserJson::class)->orderBy('id', 'desc')->get(); 90 | $orderedByNameAscDatabaseUsers = app(UserDatabase::class)->orderBy('name', 'asc')->get(); 91 | $orderedByNameAscJsonUsers = app(UserJson::class)->orderBy('name', 'asc')->get(); 92 | $this->assertEquals($orderedByIdDescDatabaseUsers->toArray(), $orderedByIdDescJsonUsers->toArray()); 93 | $this->assertEquals($orderedByNameAscDatabaseUsers->toArray(), $orderedByNameAscJsonUsers->toArray()); 94 | } 95 | 96 | public function testFind() 97 | { 98 | $this->createMultipleDatabaseUsers(5); 99 | $foundDatabaseUser = app(UserDatabase::class)->find(4); 100 | $foundJsonUser = app(UserJson::class)->find(4); 101 | $this->assertEquals($foundDatabaseUser->toArray(), $foundJsonUser->toArray()); 102 | } 103 | 104 | public function testFailedFind() 105 | { 106 | $foundDatabaseUser = app(UserDatabase::class)->find(4); 107 | $this->assertEmpty($foundDatabaseUser); 108 | } 109 | 110 | public function testFindOrFail() 111 | { 112 | $this->createMultipleDatabaseUsers(5); 113 | $foundDatabaseUser = app(UserDatabase::class)->findOrFail(4); 114 | $foundJsonUser = app(UserJson::class)->findOrFail(4); 115 | $this->assertEquals($foundDatabaseUser->toArray(), $foundJsonUser->toArray()); 116 | } 117 | 118 | /** 119 | * @expectedException \Illuminate\Database\Eloquent\ModelNotFoundException 120 | * @expectedExceptionMessage No query results for model [Okipa\LaravelModelJsonStorage\Test\Models\UserDatabase] 4 121 | */ 122 | public function testFailedFindOrFail() 123 | { 124 | app(UserDatabase::class)->findOrFail(4); 125 | } 126 | 127 | public function testPaginate() 128 | { 129 | $this->createMultipleDatabaseUsers(10); 130 | $firstPageDatabaseUsers = app(UserDatabase::class)->paginate(); 131 | $firstPageJsonUsers = app(UserJson::class)->paginate(); 132 | $secondPageDatabaseUsers = app(UserDatabase::class)->paginate(5, ['name'], 'page', 2); 133 | $secondPageJsonUsers = app(UserJson::class)->paginate(5, ['name'], 'page', 2); 134 | // notice : we remove the created_at and updated_at fields that are not relevant and can be different 135 | foreach ($firstPageDatabaseUsers as $key => $firstPageDatabaseUser) { 136 | unset($firstPageDatabaseUser->created_at); 137 | unset($firstPageDatabaseUser->updated_at); 138 | } 139 | foreach ($firstPageJsonUsers as $key => $firstPageJsonUser) { 140 | unset($firstPageJsonUser->created_at); 141 | unset($firstPageJsonUser->updated_at); 142 | } 143 | $this->assertEquals($secondPageDatabaseUsers->toArray(), $secondPageJsonUsers->toArray()); 144 | $this->assertEquals($secondPageDatabaseUsers->toArray(), $secondPageJsonUsers->toArray()); 145 | } 146 | 147 | public function testValue() 148 | { 149 | $this->createMultipleDatabaseUsers(3); 150 | $valueDatabaseUser = app(UserDatabase::class)->where('id', 2)->value('email'); 151 | $valueUserJson = app(UserJson::class)->where('id', 2)->value('email'); 152 | $this->assertEquals($valueDatabaseUser, $valueUserJson); 153 | } 154 | 155 | public function testPluck() 156 | { 157 | $this->createMultipleDatabaseUsers(3); 158 | $countDatabaseUser = app(UserDatabase::class)->pluck('name', 'email'); 159 | $countUserJson = app(UserJson::class)->pluck('name', 'email'); 160 | $this->assertEquals($countDatabaseUser, $countUserJson); 161 | } 162 | 163 | public function testCount() 164 | { 165 | $this->createMultipleDatabaseUsers(10); 166 | $countDatabaseUser = app(UserDatabase::class)->count(); 167 | $countUserJson = app(UserJson::class)->count(); 168 | $this->assertEquals($countDatabaseUser, $countUserJson); 169 | } 170 | 171 | public function testMin() 172 | { 173 | $this->createMultipleDatabaseUsers(10); 174 | $minDatabaseUser = app(UserDatabase::class)->min('id'); 175 | $minUserJson = app(UserJson::class)->min('id'); 176 | $this->assertEquals($minDatabaseUser, $minUserJson); 177 | } 178 | 179 | public function testMax() 180 | { 181 | $this->createMultipleDatabaseUsers(10); 182 | $maxDatabaseUser = app(UserDatabase::class)->max('id'); 183 | $maxUserJson = app(UserJson::class)->max('id'); 184 | $this->assertEquals($maxDatabaseUser, $maxUserJson); 185 | } 186 | 187 | public function testAvg() 188 | { 189 | $this->createMultipleDatabaseUsers(10); 190 | $avgDatabaseUser = app(UserDatabase::class)->avg('id'); 191 | $avgUserJson = app(UserJson::class)->avg('id'); 192 | $this->assertEquals($avgDatabaseUser, $avgUserJson); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /tests/Unit/BuildsQueriesOverrideTest.php: -------------------------------------------------------------------------------- 1 | createMultipleDatabaseUsers(3); 17 | $firstDatabaseUsers = app(UserDatabase::class)->first(); 18 | $firstJsonUsers = app(UserJson::class)->first(); 19 | $this->assertEquals($firstDatabaseUsers->toArray(), $firstJsonUsers->toArray()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tests/Unit/ModelOverrideTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 20 | storage_path(config('model-json-storage.storage_path') . '/userjson.json'), 21 | app(UserJson::class)->getJsonStoragePath() 22 | ); 23 | } 24 | 25 | public function testSave() 26 | { 27 | $usersCollection = $this->createUniqueDatabaseAndJsonUser(); 28 | $userDatabase = $usersCollection->get('databaseUser'); 29 | $userJson = $usersCollection->get('jsonUser'); 30 | $newEmail = $this->faker->email; 31 | $userDatabase->email = $newEmail; 32 | $userDatabase->save(); 33 | $userJson->email = $newEmail; 34 | $userJson->save(); 35 | $this->assertEquals( 36 | app(UserDatabase::class)->find($userDatabase->id)->email, 37 | array_first(app(UserDatabase::class)->fromJson(File::get($userJson->getJsonStoragePath())))['email'] 38 | ); 39 | } 40 | 41 | public function testUpdate() 42 | { 43 | $usersCollection = $this->createUniqueDatabaseAndJsonUser(); 44 | $userDatabase = $usersCollection->get('databaseUser'); 45 | $userJson = $usersCollection->get('jsonUser'); 46 | $newName = $this->faker->name; 47 | $userDatabase->update([ 48 | 'name' => $newName, 49 | ]); 50 | $userJson->update([ 51 | 'name' => $newName, 52 | ]); 53 | $this->assertEquals( 54 | app(UserDatabase::class)->find($userDatabase->id)->name, 55 | array_first(app(UserDatabase::class)->fromJson(File::get($userJson->getJsonStoragePath())))['name'] 56 | ); 57 | } 58 | 59 | public function testCreate() 60 | { 61 | $usersCollection = $this->createUniqueDatabaseAndJsonUser(); 62 | $userDatabase = $usersCollection->get('databaseUser'); 63 | $userJson = $usersCollection->get('jsonUser'); 64 | $this->assertFileExists($userJson->getJsonStoragePath()); 65 | $this->assertEquals( 66 | [app(UserDatabase::class)->find($userDatabase->id)->getAttributes()], 67 | app(UserDatabase::class)->fromJson(File::get($userJson->getJsonStoragePath())) 68 | ); 69 | } 70 | 71 | public function testAll() 72 | { 73 | $this->createMultipleDatabaseUsers(3); 74 | $allDatabaseUsersArray = app(UserDatabase::class)->all()->toArray(); 75 | $allJsonUsersArray = app(UserJson::class)->all()->toArray(); 76 | $this->assertEquals($allDatabaseUsersArray, $allJsonUsersArray); 77 | } 78 | 79 | public function testDelete() 80 | { 81 | $usersCollection = $this->createMultipleDatabaseUsers(3); 82 | $firstDatabaseUser = $usersCollection->get('databaseUsers')->where('id', 1)->first(); 83 | $firstJsonUser = $usersCollection->get('jsonUsers')->where('id', 1)->first(); 84 | $databaseDeleteResult = $firstDatabaseUser->delete(); 85 | $jsonDeleteResult = $firstJsonUser->delete(); 86 | $allDatabaseUsersArray = app(UserDatabase::class)->all()->toArray(); 87 | $allJsonUsersArray = app(UserJson::class)->all()->toArray(); 88 | $this->assertEquals($databaseDeleteResult, $jsonDeleteResult); 89 | $this->assertEquals($allDatabaseUsersArray, $allJsonUsersArray); 90 | } 91 | 92 | /** 93 | * @expectedException \Exception 94 | * @expectedExceptionMessage No primary key defined on model. 95 | */ 96 | public function testModelWithNoPrimary() 97 | { 98 | app(UserJsonWithoutPrimaryKey::class)->delete(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /tests/database/migrations/2014_10_12_000000_create_users_test_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->string('password'); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('users_test'); 33 | } 34 | } 35 | --------------------------------------------------------------------------------