├── .editorconfig ├── .env.example ├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── app ├── Exceptions │ ├── ApiExceptionHandler.php │ └── Handler.php ├── Http │ ├── Controllers │ │ ├── Auth │ │ │ └── AuthController.php │ │ ├── Controller.php │ │ ├── RoleController.php │ │ └── UserController.php │ └── Middleware │ │ ├── Authenticate.php │ │ ├── CheckForMaintenanceMode.php │ │ ├── EncryptCookies.php │ │ ├── PreventRequestsDuringMaintenance.php │ │ ├── RedirectIfAuthenticated.php │ │ ├── TrimStrings.php │ │ ├── TrustHosts.php │ │ ├── TrustProxies.php │ │ └── VerifyCsrfToken.php ├── Models │ ├── BaseModel.php │ ├── Policies │ │ └── BasePolicy.php │ ├── Role.php │ └── User.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── EventServiceProvider.php │ ├── RouteServiceProvider.php │ └── TelescopeServiceProvider.php ├── Services │ └── RestfulService.php └── Transformers │ └── BaseTransformer.php ├── artisan ├── bootstrap ├── app.php ├── cache │ └── .gitignore └── providers.php ├── composer.json ├── config ├── api.php ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── cors.php ├── database.php ├── filesystems.php ├── hashing.php ├── jwt.php ├── logging.php ├── mail.php ├── queue.php ├── services.php ├── session.php ├── stubs.php ├── telescope.php └── view.php ├── database ├── .gitignore ├── factories │ └── UserFactory.php ├── migrations │ ├── 0001_01_01_000000_create_users_table.php │ ├── 0001_01_01_000001_create_cache_table.php │ └── 0001_01_01_000002_create_jobs_table.php └── seeders │ ├── BaseSeeder.php │ ├── DatabaseSeeder.php │ ├── RoleTableSeeder.php │ └── UserStorySeeder.php ├── docker-compose.yml ├── docs ├── example-apache-vhost ├── example-nginx-vhost └── postman │ ├── collection.json │ └── environment.json ├── env ├── build.sh ├── docker │ ├── .gitignore │ ├── nginx │ │ ├── Dockerfile │ │ ├── nginx.conf │ │ ├── sites │ │ │ └── laravel.conf │ │ └── upstream.conf │ ├── php-fpm │ │ ├── Dockerfile │ │ ├── laravel.ini │ │ ├── opcache.ini │ │ ├── php.ini │ │ ├── xdebug.ini │ │ └── xlaravel.pool.conf │ ├── postgres │ │ ├── Dockerfile │ │ └── create_test_db.sh │ └── workspace │ │ ├── .zshrc │ │ ├── Dockerfile │ │ ├── aliases.sh │ │ ├── crontab │ │ └── laradock │ │ └── xdebug.ini └── workspace.sh ├── phpcs.xml ├── phpunit.xml ├── phpunit.xml.travis ├── public ├── .htaccess ├── css │ └── app.css ├── favicon.ico ├── index.php ├── js │ └── app.js ├── robots.txt ├── vendor │ └── telescope │ │ ├── app-dark.css │ │ ├── app.css │ │ ├── app.js │ │ ├── favicon.ico │ │ └── mix-manifest.json └── web.config ├── readme.md ├── resources └── lang │ └── en │ ├── auth.php │ ├── pagination.php │ ├── passwords.php │ └── validation.php ├── routes ├── api.php ├── channels.php ├── console.php └── web.php ├── server.php ├── storage ├── app │ ├── .gitignore │ ├── private │ │ └── .gitignore │ └── public │ │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ ├── .gitignore │ │ └── data │ │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore └── tests ├── Api └── UserControllerTest.php ├── ApiTestCase.php ├── CreatesApplication.php ├── Feature └── ExampleTest.php ├── TestCase.php ├── Unit └── A │ └── FirstTest.php └── bootstrap.php /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 4 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [*.{yml,yaml}] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [*.{js,json}] 20 | indent_style = space 21 | indent_size = 4 22 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Laravel 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_TIMEZONE=UTC 6 | APP_URL=http://localhost 7 | 8 | APP_LOCALE=en 9 | APP_FALLBACK_LOCALE=en 10 | APP_FAKER_LOCALE=en_US 11 | 12 | APP_MAINTENANCE_DRIVER=file 13 | # APP_MAINTENANCE_STORE=database 14 | 15 | PHP_CLI_SERVER_WORKERS=4 16 | 17 | BCRYPT_ROUNDS=12 18 | 19 | LOG_CHANNEL=stack 20 | LOG_STACK=single 21 | LOG_DEPRECATIONS_CHANNEL=null 22 | LOG_LEVEL=debug 23 | 24 | DB_CONNECTION=pgsql 25 | DB_HOST=your_project_postgres 26 | DB_PORT=5432 27 | DB_DATABASE=your_project_local 28 | DB_DATABASE_TEST=${DB_DATABASE}_test 29 | DB_USERNAME=laradock 30 | DB_PASSWORD=secret 31 | 32 | SESSION_DRIVER=database 33 | SESSION_LIFETIME=120 34 | SESSION_ENCRYPT=false 35 | SESSION_PATH=/ 36 | SESSION_DOMAIN=null 37 | 38 | BROADCAST_CONNECTION=log 39 | FILESYSTEM_DISK=local 40 | QUEUE_CONNECTION=database 41 | 42 | CACHE_STORE=database 43 | CACHE_PREFIX= 44 | 45 | MEMCACHED_HOST=127.0.0.1 46 | 47 | REDIS_CLIENT=phpredis 48 | REDIS_HOST=your_project_redis 49 | REDIS_PASSWORD=null 50 | REDIS_PORT=6379 51 | 52 | MAIL_MAILER=log 53 | MAIL_SCHEME=null 54 | MAIL_HOST=127.0.0.1 55 | MAIL_PORT=2525 56 | MAIL_USERNAME=null 57 | MAIL_PASSWORD=null 58 | MAIL_FROM_ADDRESS="hello@example.com" 59 | MAIL_FROM_NAME="${APP_NAME}" 60 | 61 | AWS_ACCESS_KEY_ID= 62 | AWS_SECRET_ACCESS_KEY= 63 | AWS_DEFAULT_REGION=us-east-1 64 | AWS_BUCKET= 65 | AWS_USE_PATH_STYLE_ENDPOINT=false 66 | 67 | VITE_APP_NAME="${APP_NAME}" 68 | 69 | ########################################################## 70 | ################ Third Party Integrations ################# 71 | ########################################################### 72 | 73 | # Put third-party integration env vars here 74 | 75 | ########################################################### 76 | ###################### Docker Setup ####################### 77 | ########################################################### 78 | # To extend the composer process 79 | COMPOSER_PROCESS_TIMEOUT=-1 80 | 81 | # Choose storage path on your machine. For all storage systems 82 | DATA_PATH_HOST=./storage/laradock/ 83 | 84 | ### PHP ########################################### 85 | 86 | # Select a PHP version of the Workspace and PHP-FPM containers (Does not apply to HHVM). 87 | PHP_VERSION=8.4 88 | 89 | ### NGINX ################################################# 90 | 91 | NGINX_HOST_LOG_PATH=./storage/logs/nginx/ 92 | NGINX_VIRTUAL_HOST=localhost 93 | HTTPS_METHOD=noredirect 94 | 95 | ### POSTGRES ############################################## 96 | 97 | POSTGRES_DB=your_project_local 98 | POSTGRES_USER=laradock 99 | POSTGRES_PASSWORD=secret 100 | POSTGRES_PORT=5432 101 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.blade.php diff=html 4 | *.css diff=css 5 | *.html diff=html 6 | *.md diff=markdown 7 | *.php diff=php 8 | 9 | /.github export-ignore 10 | CHANGELOG.md export-ignore 11 | .styleci.yml export-ignore 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/hot 3 | /public/storage 4 | /storage/*.index 5 | /storage/*.key 6 | storage/laradock 7 | /vendor 8 | .env 9 | .env.backup 10 | .phpunit.result.cache 11 | docker-compose.override.yml 12 | 13 | Homestead.json 14 | Homestead.yaml 15 | npm-debug.log 16 | yarn-error.log 17 | 18 | /.idea 19 | /.vscode 20 | /.vagrant 21 | .phpstorm* 22 | _ide_helper.php 23 | .DS_Store 24 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | services: 4 | - postgresql 5 | 6 | matrix: 7 | fast_finish: true 8 | include: 9 | - php: 7.4 10 | env: LARAVEL_VERSION=8.* 11 | 12 | sudo: false 13 | 14 | dist: xenial 15 | 16 | env: 17 | global: 18 | - setup=basic 19 | - xdebug=false 20 | 21 | cache: 22 | directories: 23 | - $HOME/.composer/cache 24 | 25 | before_install: 26 | - if [[ $xdebug = 'true' ]] ; then phpenv config-rm xdebug.ini; fi 27 | - composer self-update --2 28 | 29 | install: 30 | - if [[ $setup = 'basic' ]]; then travis_retry composer install --prefer-dist --no-interaction --no-suggest; fi 31 | - if [[ $setup = 'stable' ]]; then travis_retry composer update --prefer-dist --no-interaction --no-suggest --prefer-stable; fi 32 | - if [[ $setup = 'lowest' ]]; then travis_retry composer update --prefer-dist --no-interaction --no-suggest --prefer-stable --prefer-lowest; fi 33 | 34 | before_script: 35 | - travis_retry composer install --prefer-source --no-interaction 36 | - if [ "$LARAVEL_VERSION" != "" ]; then composer require --dev "laravel/framework:${LARAVEL_VERSION}" --no-update; fi; 37 | - if [ "$LARAVEL_VERSION" != "" ]; then composer require --dev "illuminate/support:${LARAVEL_VERSION}" --no-update; fi; 38 | - composer update 39 | - cp -f phpunit.xml.travis phpunit.xml 40 | - psql -c 'create database travis_ci_test;' -U postgres 41 | 42 | 43 | script: 44 | - composer test 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Max 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. -------------------------------------------------------------------------------- /app/Exceptions/ApiExceptionHandler.php: -------------------------------------------------------------------------------- 1 | reportable(function (Throwable $e) { 43 | // 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/AuthController.php: -------------------------------------------------------------------------------- 1 | check()) { 26 | return redirect(RouteServiceProvider::HOME); 27 | } 28 | } 29 | 30 | return $next($request); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | allSubdomainsOfApplicationUrl(), 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustProxies.php: -------------------------------------------------------------------------------- 1 | isAdmin()) { 20 | return true; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Models/Role.php: -------------------------------------------------------------------------------- 1 | */ 26 | use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail, HasFactory, Notifiable; 27 | 28 | /** 29 | * @var int Auto increments integer key 30 | */ 31 | public $primaryKey = 'user_id'; 32 | 33 | /** 34 | * @var array Relations to load implicitly by Restful controllers 35 | */ 36 | public static ?array $itemWith = ['primaryRole', 'roles']; 37 | 38 | /** 39 | * The attributes that are mass assignable. 40 | * 41 | * @var list 42 | */ 43 | protected $fillable = [ 44 | 'name', 45 | 'email', 46 | 'password', 47 | 'primary_role', 48 | ]; 49 | 50 | /** 51 | * The attributes that should be hidden for serialization. 52 | * 53 | * @var list 54 | */ 55 | protected $hidden = [ 56 | 'password', 57 | 'remember_token', 58 | 'email_verified_at', 59 | ]; 60 | 61 | /** 62 | * Get the attributes that should be cast. 63 | * 64 | * @return array 65 | */ 66 | protected function casts(): array 67 | { 68 | return [ 69 | 'email_verified_at' => 'datetime', 70 | 'password' => 'hashed', 71 | ]; 72 | } 73 | 74 | /** 75 | * Return the validation rules for this model 76 | * 77 | * @return array Rules 78 | */ 79 | public function getValidationRules(): array 80 | { 81 | return [ 82 | 'email' => 'email|max:255|unique:users', 83 | 'name' => 'required|min:3', 84 | 'password' => 'required|min:6', 85 | ]; 86 | } 87 | 88 | public static function boot(): void 89 | { 90 | parent::boot(); 91 | } 92 | 93 | public function primaryRole(): BelongsTo 94 | { 95 | return $this->belongsTo(Role::class, 'primary_role'); 96 | } 97 | 98 | /** 99 | * User's secondary roles 100 | */ 101 | public function roles(): BelongsToMany 102 | { 103 | return $this->belongsToMany(Role::class, 'user_roles', 'user_id', 'role_id'); 104 | } 105 | 106 | /** 107 | * Get all user's roles 108 | */ 109 | public function getRoles(): array 110 | { 111 | $allRoles = array_merge( 112 | [ 113 | $this->primaryRole->name, 114 | ], 115 | $this->roles->pluck('name')->toArray() 116 | ); 117 | 118 | return $allRoles; 119 | } 120 | 121 | public function isAdmin(): bool 122 | { 123 | return $this->primaryRole->name == Role::ROLE_ADMIN; 124 | } 125 | 126 | /** 127 | * For Authentication 128 | * Get the identifier that will be stored in the subject claim of the JWT. 129 | * 130 | * @return mixed 131 | */ 132 | public function getJWTIdentifier(): string 133 | { 134 | return $this->getKey(); 135 | } 136 | 137 | /** 138 | * For Authentication 139 | * Return a key value array, containing any custom claims to be added to the JWT. 140 | * 141 | * @return array 142 | */ 143 | public function getJWTCustomClaims(): array 144 | { 145 | return [ 146 | 'user' => [ 147 | 'id' => $this->getKey(), 148 | 'name' => $this->name, 149 | 'primaryRole' => $this->primaryRole->name, 150 | ], 151 | ]; 152 | } 153 | 154 | /** 155 | * Get the name of the unique identifier for the user. 156 | * 157 | * @return string 158 | */ 159 | public function getAuthIdentifierName(): string 160 | { 161 | return $this->getKeyName(); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | registerExceptionHandler(); 18 | $this->registerTelescope(); 19 | } 20 | 21 | /** 22 | * Bootstrap any application services. 23 | * 24 | * @return void 25 | */ 26 | public function boot(): void 27 | { 28 | // 29 | } 30 | 31 | /** 32 | * Register the exception handler - extends the Dingo one 33 | * 34 | * @return void 35 | */ 36 | protected function registerExceptionHandler(): void 37 | { 38 | $this->app->singleton('api.exception', function ($app) { 39 | $config = $app->config->get('api'); 40 | return new ApiExceptionHandler($app['Illuminate\Contracts\Debug\ExceptionHandler'], $config['errorFormat'], $config['debug']); 41 | }); 42 | } 43 | 44 | /** 45 | * Conditionally register the telescope service provider 46 | */ 47 | protected function registerTelescope(): void 48 | { 49 | if ($this->app->environment('local', 'testing')) { 50 | $this->app->register(TelescopeServiceProvider::class); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | * 22 | * @return void 23 | */ 24 | public function boot(): void 25 | { 26 | $this->registerPolicies(); 27 | 28 | // 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 19 | // SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | * 26 | * @return void 27 | */ 28 | public function boot(): void 29 | { 30 | // 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | configureRateLimiting(); 39 | 40 | // UUID pattern Pattern 41 | Route::pattern('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); 42 | 43 | $this->routes(function () { 44 | Route::middleware('api') 45 | ->namespace($this->namespace) 46 | ->group(base_path('routes/api.php')); 47 | 48 | /* 49 | * Uncomment if you wish to enable web (it. non-api) routes. 50 | * 51 | * If you like, it is possible for both api and web routes to have no prefix (ie. share the same base / prefix) 52 | * 53 | Route::prefix('web') 54 | ->middleware('web') 55 | ->namespace($this->namespace) 56 | ->group(base_path('routes/web.php')); 57 | */ 58 | }); 59 | } 60 | 61 | /** 62 | * Configure the rate limiters for the application. 63 | * 64 | * @return void 65 | */ 66 | protected function configureRateLimiting(): void 67 | { 68 | RateLimiter::for('api', function (Request $request) { 69 | return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip()); 70 | }); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/Providers/TelescopeServiceProvider.php: -------------------------------------------------------------------------------- 1 | hideSensitiveRequestDetails(); 24 | 25 | Telescope::filter(function (IncomingEntry $entry) { 26 | if ($this->app->isLocal()) { 27 | return true; 28 | } 29 | 30 | return false; 31 | }); 32 | } 33 | 34 | /** 35 | * Prevent sensitive request details from being logged by Telescope. 36 | * 37 | * @return void 38 | */ 39 | protected function hideSensitiveRequestDetails(): void 40 | { 41 | if ($this->app->isLocal()) { 42 | return; 43 | } 44 | 45 | Telescope::hideRequestParameters(['_token']); 46 | 47 | Telescope::hideRequestHeaders([ 48 | 'cookie', 49 | 'x-csrf-token', 50 | 'x-xsrf-token', 51 | ]); 52 | } 53 | 54 | /** 55 | * Register the Telescope gate. 56 | * 57 | * This gate determines who can access Telescope in non-local environments. 58 | * 59 | * @return void 60 | */ 61 | protected function gate() 62 | { 63 | Gate::define('viewTelescope', function ($user) { 64 | // If needed, add your IP (or office IPs) to allow on non-local environments 65 | return false; 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/Services/RestfulService.php: -------------------------------------------------------------------------------- 1 | handleCommand(new ArgvInput); 14 | 15 | exit($status); 16 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | withRouting( 9 | web: __DIR__.'/../routes/web.php', 10 | api: __DIR__.'/../routes/api.php', 11 | commands: __DIR__.'/../routes/console.php', 12 | health: '/up', 13 | ) 14 | ->withMiddleware(function (Middleware $middleware) { 15 | // API middleware group 16 | $middleware->group('api', [ 17 | // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 18 | // \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', 19 | \Specialtactics\L5Api\Http\Middleware\SnakeCaseInputParameterKeys::class, 20 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 21 | ]); 22 | 23 | // Aliases 24 | $middleware->alias([ 25 | 'snake_case' => \Specialtactics\L5Api\Http\Middleware\SnakeCaseInputParameterKeys::class, 26 | 'check_role' => \Specialtactics\L5Api\Http\Middleware\CheckUserRole::class, 27 | ]); 28 | }) 29 | ->withExceptions(function (Exceptions $exceptions) { 30 | // 31 | })->create(); 32 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /bootstrap/providers.php: -------------------------------------------------------------------------------- 1 | env('API_STANDARDS_TREE', 'x'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | API Subtype 26 | |-------------------------------------------------------------------------- 27 | | 28 | | Your subtype will follow the standards tree you use when used in the 29 | | "Accept" header to negotiate the content type and version. 30 | | 31 | | For example: Accept: application/x.SUBTYPE.v1+json 32 | | 33 | */ 34 | 35 | 'subtype' => env('API_SUBTYPE', ''), 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Default API Version 40 | |-------------------------------------------------------------------------- 41 | | 42 | | This is the default version when strict mode is disabled and your API 43 | | is accessed via a web browser. It's also used as the default version 44 | | when generating your APIs documentation. 45 | | 46 | */ 47 | 48 | 'version' => env('API_VERSION', 'v1'), 49 | 50 | /* 51 | |-------------------------------------------------------------------------- 52 | | Default API Prefix 53 | |-------------------------------------------------------------------------- 54 | | 55 | | A default prefix to use for your API routes so you don't have to 56 | | specify it for each group. 57 | | 58 | */ 59 | 60 | 'prefix' => env('API_PREFIX', null), 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Default API Domain 65 | |-------------------------------------------------------------------------- 66 | | 67 | | A default domain to use for your API routes so you don't have to 68 | | specify it for each group. 69 | | 70 | */ 71 | 72 | 'domain' => env('API_DOMAIN', null), 73 | 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | Name 77 | |-------------------------------------------------------------------------- 78 | | 79 | | When documenting your API using the API Blueprint syntax you can 80 | | configure a default name to avoid having to manually specify 81 | | one when using the command. 82 | | 83 | */ 84 | 85 | 'name' => env('API_NAME', null), 86 | 87 | /* 88 | |-------------------------------------------------------------------------- 89 | | Conditional Requests 90 | |-------------------------------------------------------------------------- 91 | | 92 | | Globally enable conditional requests so that an ETag header is added to 93 | | any successful response. Subsequent requests will perform a check and 94 | | will return a 304 Not Modified. This can also be enabled or disabled 95 | | on certain groups or routes. 96 | | 97 | */ 98 | 99 | 'conditionalRequest' => env('API_CONDITIONAL_REQUEST', true), 100 | 101 | /* 102 | |-------------------------------------------------------------------------- 103 | | Strict Mode 104 | |-------------------------------------------------------------------------- 105 | | 106 | | Enabling strict mode will require clients to send a valid Accept header 107 | | with every request. This also voids the default API version, meaning 108 | | your API will not be browsable via a web browser. 109 | | 110 | */ 111 | 112 | 'strict' => env('API_STRICT', false), 113 | 114 | /* 115 | |-------------------------------------------------------------------------- 116 | | Debug Mode 117 | |-------------------------------------------------------------------------- 118 | | 119 | | Enabling debug mode will result in error responses caused by thrown 120 | | exceptions to have a "debug" key that will be populated with 121 | | more detailed information on the exception. 122 | | 123 | */ 124 | 125 | 'debug' => env('API_DEBUG', false), 126 | 127 | /* 128 | |-------------------------------------------------------------------------- 129 | | Generic Error Format 130 | |-------------------------------------------------------------------------- 131 | | 132 | | When some HTTP exceptions are not caught and dealt with the API will 133 | | generate a generic error response in the format provided. Any 134 | | keys that aren't replaced with corresponding values will be 135 | | removed from the final response. 136 | | 137 | */ 138 | 139 | 'errorFormat' => [ 140 | 'message' => ':message', 141 | 'errors' => ':errors', 142 | 'code' => ':code', 143 | 'statusCode' => ':status_code', 144 | 'debug' => ':debug', 145 | ], 146 | 147 | /* 148 | |-------------------------------------------------------------------------- 149 | | API Middleware 150 | |-------------------------------------------------------------------------- 151 | | 152 | | Middleware that will be applied globally to all API requests. 153 | | 154 | */ 155 | 156 | 'middleware' => [ 157 | 158 | ], 159 | 160 | /* 161 | |-------------------------------------------------------------------------- 162 | | Authentication Providers 163 | |-------------------------------------------------------------------------- 164 | | 165 | | The authentication providers that should be used when attempting to 166 | | authenticate an incoming API request. 167 | | 168 | */ 169 | 170 | 'auth' => [ 171 | 'jwt' => 'Dingo\Api\Auth\Provider\JWT', 172 | ], 173 | 174 | /* 175 | |-------------------------------------------------------------------------- 176 | | Throttling / Rate Limiting 177 | |-------------------------------------------------------------------------- 178 | | 179 | | Consumers of your API can be limited to the amount of requests they can 180 | | make. You can create your own throttles or simply change the default 181 | | throttles. 182 | | 183 | */ 184 | 185 | 'throttling' => [ 186 | 187 | ], 188 | 189 | /* 190 | |-------------------------------------------------------------------------- 191 | | Response Transformer 192 | |-------------------------------------------------------------------------- 193 | | 194 | | Responses can be transformed so that they are easier to format. By 195 | | default a Fractal transformer will be used to transform any 196 | | responses prior to formatting. You can easily replace 197 | | this with your own transformer. 198 | | 199 | */ 200 | 201 | 'transformer' => env('API_TRANSFORMER', Dingo\Api\Transformer\Adapter\Fractal::class), 202 | 203 | /* 204 | |-------------------------------------------------------------------------- 205 | | Response Formats 206 | |-------------------------------------------------------------------------- 207 | | 208 | | Responses can be returned in multiple formats by registering different 209 | | response formatters. You can also customize an existing response 210 | | formatter with a number of options to configure its output. 211 | | 212 | */ 213 | 214 | 'defaultFormat' => env('API_DEFAULT_FORMAT', 'json'), 215 | 216 | 'formats' => [ 217 | 218 | 'json' => Specialtactics\L5Api\Http\Response\Format\Json::class, 219 | 220 | ], 221 | 222 | 'formatsOptions' => [ 223 | 224 | 'json' => [ 225 | 'pretty_print' => env('API_JSON_FORMAT_PRETTY_PRINT_ENABLED', false), 226 | 'indent_style' => env('API_JSON_FORMAT_INDENT_STYLE', 'space'), 227 | 'indent_size' => env('API_JSON_FORMAT_INDENT_SIZE', 2), 228 | ], 229 | 'caseType' => env('API_CASE_TYPE', 'camel-case'), 230 | 'transform_keys_levels' => env('API_TRANSFORM_KEYS_LEVELS', null), 231 | ], 232 | 233 | ]; 234 | -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | env('APP_NAME', 'Laravel'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Application Environment 21 | |-------------------------------------------------------------------------- 22 | | 23 | | This value determines the "environment" your application is currently 24 | | running in. This may determine how you prefer to configure various 25 | | services the application utilizes. Set this in your ".env" file. 26 | | 27 | */ 28 | 29 | 'env' => env('APP_ENV', 'production'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Application Debug Mode 34 | |-------------------------------------------------------------------------- 35 | | 36 | | When your application is in debug mode, detailed error messages with 37 | | stack traces will be shown on every error that occurs within your 38 | | application. If disabled, a simple generic error page is shown. 39 | | 40 | */ 41 | 42 | 'debug' => (bool) env('APP_DEBUG', false), 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Application URL 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This URL is used by the console to properly generate URLs when using 50 | | the Artisan command line tool. You should set this to the root of 51 | | the application so that it's available within Artisan commands. 52 | | 53 | */ 54 | 55 | 'url' => env('APP_URL', 'http://localhost'), 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Application Timezone 60 | |-------------------------------------------------------------------------- 61 | | 62 | | Here you may specify the default timezone for your application, which 63 | | will be used by the PHP date and date-time functions. The timezone 64 | | is set to "UTC" by default as it is suitable for most use cases. 65 | | 66 | */ 67 | 68 | 'timezone' => env('APP_TIMEZONE', 'UTC'), 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Application Locale Configuration 73 | |-------------------------------------------------------------------------- 74 | | 75 | | The application locale determines the default locale that will be used 76 | | by Laravel's translation / localization methods. This option can be 77 | | set to any locale for which you plan to have translation strings. 78 | | 79 | */ 80 | 81 | 'locale' => env('APP_LOCALE', 'en'), 82 | 83 | 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), 84 | 85 | 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), 86 | 87 | /* 88 | |-------------------------------------------------------------------------- 89 | | Encryption Key 90 | |-------------------------------------------------------------------------- 91 | | 92 | | This key is utilized by Laravel's encryption services and should be set 93 | | to a random, 32 character string to ensure that all encrypted values 94 | | are secure. You should do this prior to deploying the application. 95 | | 96 | */ 97 | 98 | 'cipher' => 'AES-256-CBC', 99 | 100 | 'key' => env('APP_KEY'), 101 | 102 | 'previous_keys' => [ 103 | ...array_filter( 104 | explode(',', env('APP_PREVIOUS_KEYS', '')) 105 | ), 106 | ], 107 | 108 | /* 109 | |-------------------------------------------------------------------------- 110 | | Maintenance Mode Driver 111 | |-------------------------------------------------------------------------- 112 | | 113 | | These configuration options determine the driver used to determine and 114 | | manage Laravel's "maintenance mode" status. The "cache" driver will 115 | | allow maintenance mode to be controlled across multiple machines. 116 | | 117 | | Supported drivers: "file", "cache" 118 | | 119 | */ 120 | 121 | 'maintenance' => [ 122 | 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), 123 | 'store' => env('APP_MAINTENANCE_STORE', 'database'), 124 | ], 125 | 126 | ]; 127 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => env('AUTH_GUARD', 'api'), 18 | 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | which utilizes session storage plus the Eloquent user provider. 29 | | 30 | | All authentication guards have a user provider, which defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | system used by the application. Typically, Eloquent is utilized. 33 | | 34 | | Supported: "session" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'api' => [ 40 | 'driver' => 'jwt', 41 | 'provider' => 'users', 42 | 'hash' => false, 43 | ], 44 | 45 | 'web' => [ 46 | 'driver' => 'session', 47 | 'provider' => 'users', 48 | ], 49 | ], 50 | 51 | /* 52 | |-------------------------------------------------------------------------- 53 | | User Providers 54 | |-------------------------------------------------------------------------- 55 | | 56 | | All authentication guards have a user provider, which defines how the 57 | | users are actually retrieved out of your database or other storage 58 | | system used by the application. Typically, Eloquent is utilized. 59 | | 60 | | If you have multiple user tables or models you may configure multiple 61 | | providers to represent the model / table. These providers may then 62 | | be assigned to any extra authentication guards you have defined. 63 | | 64 | | Supported: "database", "eloquent" 65 | | 66 | */ 67 | 68 | 'providers' => [ 69 | 'users' => [ 70 | 'driver' => 'eloquent', 71 | 'model' => env('AUTH_MODEL', App\Models\User::class), 72 | ], 73 | 74 | // 'users' => [ 75 | // 'driver' => 'database', 76 | // 'table' => 'users', 77 | // ], 78 | ], 79 | 80 | /* 81 | |-------------------------------------------------------------------------- 82 | | Resetting Passwords 83 | |-------------------------------------------------------------------------- 84 | | 85 | | These configuration options specify the behavior of Laravel's password 86 | | reset functionality, including the table utilized for token storage 87 | | and the user provider that is invoked to actually retrieve users. 88 | | 89 | | The expiry time is the number of minutes that each reset token will be 90 | | considered valid. This security feature keeps tokens short-lived so 91 | | they have less time to be guessed. You may change this as needed. 92 | | 93 | | The throttle setting is the number of seconds a user must wait before 94 | | generating more password reset tokens. This prevents the user from 95 | | quickly generating a very large amount of password reset tokens. 96 | | 97 | */ 98 | 99 | 'passwords' => [ 100 | 'users' => [ 101 | 'provider' => 'users', 102 | 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), 103 | 'expire' => 60, 104 | 'throttle' => 60, 105 | ], 106 | ], 107 | 108 | /* 109 | |-------------------------------------------------------------------------- 110 | | Password Confirmation Timeout 111 | |-------------------------------------------------------------------------- 112 | | 113 | | Here you may define the amount of seconds before a password confirmation 114 | | window expires and users are asked to re-enter their password via the 115 | | confirmation screen. By default, the timeout lasts for three hours. 116 | | 117 | */ 118 | 119 | 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), 120 | 121 | ]; 122 | -------------------------------------------------------------------------------- /config/broadcasting.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'null'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Broadcast Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the broadcast connections that will be used 26 | | to broadcast events to other systems or over websockets. Samples of 27 | | each available type of connection are provided inside this array. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'pusher' => [ 34 | 'driver' => 'pusher', 35 | 'key' => env('PUSHER_APP_KEY'), 36 | 'secret' => env('PUSHER_APP_SECRET'), 37 | 'app_id' => env('PUSHER_APP_ID'), 38 | 'options' => [ 39 | 'cluster' => env('PUSHER_APP_CLUSTER'), 40 | 'useTLS' => true, 41 | ], 42 | ], 43 | 44 | 'ably' => [ 45 | 'driver' => 'ably', 46 | 'key' => env('ABLY_KEY'), 47 | ], 48 | 49 | 'redis' => [ 50 | 'driver' => 'redis', 51 | 'connection' => 'default', 52 | ], 53 | 54 | 'log' => [ 55 | 'driver' => 'log', 56 | ], 57 | 58 | 'null' => [ 59 | 'driver' => 'null', 60 | ], 61 | 62 | ], 63 | 64 | ]; 65 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_STORE', 'database'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Cache Stores 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the cache "stores" for your application as 26 | | well as their drivers. You may even define multiple stores for the 27 | | same cache driver to group types of items stored in your caches. 28 | | 29 | | Supported drivers: "array", "database", "file", "memcached", 30 | | "redis", "dynamodb", "octane", "null" 31 | | 32 | */ 33 | 34 | 'stores' => [ 35 | 36 | 'array' => [ 37 | 'driver' => 'array', 38 | 'serialize' => false, 39 | ], 40 | 41 | 'database' => [ 42 | 'driver' => 'database', 43 | 'connection' => env('DB_CACHE_CONNECTION'), 44 | 'table' => env('DB_CACHE_TABLE', 'cache'), 45 | 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), 46 | 'lock_table' => env('DB_CACHE_LOCK_TABLE'), 47 | ], 48 | 49 | 'file' => [ 50 | 'driver' => 'file', 51 | 'path' => storage_path('framework/cache/data'), 52 | 'lock_path' => storage_path('framework/cache/data'), 53 | ], 54 | 55 | 'memcached' => [ 56 | 'driver' => 'memcached', 57 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), 58 | 'sasl' => [ 59 | env('MEMCACHED_USERNAME'), 60 | env('MEMCACHED_PASSWORD'), 61 | ], 62 | 'options' => [ 63 | // Memcached::OPT_CONNECT_TIMEOUT => 2000, 64 | ], 65 | 'servers' => [ 66 | [ 67 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 68 | 'port' => env('MEMCACHED_PORT', 11211), 69 | 'weight' => 100, 70 | ], 71 | ], 72 | ], 73 | 74 | 'redis' => [ 75 | 'driver' => 'redis', 76 | 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), 77 | 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), 78 | ], 79 | 80 | 'dynamodb' => [ 81 | 'driver' => 'dynamodb', 82 | 'key' => env('AWS_ACCESS_KEY_ID'), 83 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 84 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 85 | 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), 86 | 'endpoint' => env('DYNAMODB_ENDPOINT'), 87 | ], 88 | 89 | 'octane' => [ 90 | 'driver' => 'octane', 91 | ], 92 | 93 | ], 94 | 95 | /* 96 | |-------------------------------------------------------------------------- 97 | | Cache Key Prefix 98 | |-------------------------------------------------------------------------- 99 | | 100 | | When utilizing the APC, database, memcached, Redis, and DynamoDB cache 101 | | stores, there might be other applications using the same cache. For 102 | | that reason, you may prefix every cache key to avoid collisions. 103 | | 104 | */ 105 | 106 | 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), 107 | 108 | ]; 109 | -------------------------------------------------------------------------------- /config/cors.php: -------------------------------------------------------------------------------- 1 | ['*', 'sanctum/csrf-cookie'], 19 | 20 | 'allowed_methods' => ['*'], 21 | 22 | 'allowed_origins' => ['*'], 23 | 24 | 'allowed_origins_patterns' => [], 25 | 26 | 'allowed_headers' => ['*'], 27 | 28 | 'exposed_headers' => [], 29 | 30 | 'max_age' => 0, 31 | 32 | 'supports_credentials' => false, 33 | 34 | ]; 35 | -------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | env('DB_CONNECTION', 'sqlite'), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Database Connections 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Below are all of the database connections defined for your application. 27 | | An example configuration is provided for each database system which 28 | | is supported by Laravel. You're free to add / remove connections. 29 | | 30 | */ 31 | 32 | 'connections' => [ 33 | 34 | 'sqlite' => [ 35 | 'driver' => 'sqlite', 36 | 'url' => env('DB_URL'), 37 | 'database' => env('DB_DATABASE', database_path('database.sqlite')), 38 | 'prefix' => '', 39 | 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), 40 | 'busy_timeout' => null, 41 | 'journal_mode' => null, 42 | 'synchronous' => null, 43 | ], 44 | 45 | 'mysql' => [ 46 | 'driver' => 'mysql', 47 | 'url' => env('DB_URL'), 48 | 'host' => env('DB_HOST', '127.0.0.1'), 49 | 'port' => env('DB_PORT', '3306'), 50 | 'database' => env('DB_DATABASE', 'laravel'), 51 | 'username' => env('DB_USERNAME', 'root'), 52 | 'password' => env('DB_PASSWORD', ''), 53 | 'unix_socket' => env('DB_SOCKET', ''), 54 | 'charset' => env('DB_CHARSET', 'utf8mb4'), 55 | 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), 56 | 'prefix' => '', 57 | 'prefix_indexes' => true, 58 | 'strict' => true, 59 | 'engine' => null, 60 | 'options' => extension_loaded('pdo_mysql') ? array_filter([ 61 | PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), 62 | ]) : [], 63 | ], 64 | 65 | 'mariadb' => [ 66 | 'driver' => 'mariadb', 67 | 'url' => env('DB_URL'), 68 | 'host' => env('DB_HOST', '127.0.0.1'), 69 | 'port' => env('DB_PORT', '3306'), 70 | 'database' => env('DB_DATABASE', 'laravel'), 71 | 'username' => env('DB_USERNAME', 'root'), 72 | 'password' => env('DB_PASSWORD', ''), 73 | 'unix_socket' => env('DB_SOCKET', ''), 74 | 'charset' => env('DB_CHARSET', 'utf8mb4'), 75 | 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), 76 | 'prefix' => '', 77 | 'prefix_indexes' => true, 78 | 'strict' => true, 79 | 'engine' => null, 80 | 'options' => extension_loaded('pdo_mysql') ? array_filter([ 81 | PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), 82 | ]) : [], 83 | ], 84 | 85 | 'pgsql' => [ 86 | 'driver' => 'pgsql', 87 | 'url' => env('DB_URL'), 88 | 'host' => env('DB_HOST', '127.0.0.1'), 89 | 'port' => env('DB_PORT', '5432'), 90 | 'database' => env('DB_DATABASE', 'laravel'), 91 | 'username' => env('DB_USERNAME', 'root'), 92 | 'password' => env('DB_PASSWORD', ''), 93 | 'charset' => env('DB_CHARSET', 'utf8'), 94 | 'prefix' => '', 95 | 'prefix_indexes' => true, 96 | 'search_path' => 'public', 97 | 'sslmode' => 'prefer', 98 | ], 99 | 100 | 'sqlsrv' => [ 101 | 'driver' => 'sqlsrv', 102 | 'url' => env('DB_URL'), 103 | 'host' => env('DB_HOST', 'localhost'), 104 | 'port' => env('DB_PORT', '1433'), 105 | 'database' => env('DB_DATABASE', 'laravel'), 106 | 'username' => env('DB_USERNAME', 'root'), 107 | 'password' => env('DB_PASSWORD', ''), 108 | 'charset' => env('DB_CHARSET', 'utf8'), 109 | 'prefix' => '', 110 | 'prefix_indexes' => true, 111 | // 'encrypt' => env('DB_ENCRYPT', 'yes'), 112 | // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), 113 | ], 114 | 115 | ], 116 | 117 | /* 118 | |-------------------------------------------------------------------------- 119 | | Migration Repository Table 120 | |-------------------------------------------------------------------------- 121 | | 122 | | This table keeps track of all the migrations that have already run for 123 | | your application. Using this information, we can determine which of 124 | | the migrations on disk haven't actually been run on the database. 125 | | 126 | */ 127 | 128 | 'migrations' => [ 129 | 'table' => 'migrations', 130 | 'update_date_on_publish' => true, 131 | ], 132 | 133 | /* 134 | |-------------------------------------------------------------------------- 135 | | Redis Databases 136 | |-------------------------------------------------------------------------- 137 | | 138 | | Redis is an open source, fast, and advanced key-value store that also 139 | | provides a richer body of commands than a typical key-value system 140 | | such as Memcached. You may define your connection settings here. 141 | | 142 | */ 143 | 144 | 'redis' => [ 145 | 146 | 'client' => env('REDIS_CLIENT', 'phpredis'), 147 | 148 | 'options' => [ 149 | 'cluster' => env('REDIS_CLUSTER', 'redis'), 150 | 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), 151 | ], 152 | 153 | 'default' => [ 154 | 'url' => env('REDIS_URL'), 155 | 'host' => env('REDIS_HOST', '127.0.0.1'), 156 | 'username' => env('REDIS_USERNAME'), 157 | 'password' => env('REDIS_PASSWORD'), 158 | 'port' => env('REDIS_PORT', '6379'), 159 | 'database' => env('REDIS_DB', '0'), 160 | ], 161 | 162 | 'cache' => [ 163 | 'url' => env('REDIS_URL'), 164 | 'host' => env('REDIS_HOST', '127.0.0.1'), 165 | 'username' => env('REDIS_USERNAME'), 166 | 'password' => env('REDIS_PASSWORD'), 167 | 'port' => env('REDIS_PORT', '6379'), 168 | 'database' => env('REDIS_CACHE_DB', '1'), 169 | ], 170 | 171 | ], 172 | 173 | ]; 174 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DISK', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Filesystem Disks 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Below you may configure as many filesystem disks as necessary, and you 24 | | may even configure multiple disks for the same driver. Examples for 25 | | most supported storage drivers are configured here for reference. 26 | | 27 | | Supported drivers: "local", "ftp", "sftp", "s3" 28 | | 29 | */ 30 | 31 | 'disks' => [ 32 | 33 | 'local' => [ 34 | 'driver' => 'local', 35 | 'root' => storage_path('app/private'), 36 | 'serve' => true, 37 | 'throw' => false, 38 | ], 39 | 40 | 'public' => [ 41 | 'driver' => 'local', 42 | 'root' => storage_path('app/public'), 43 | 'url' => env('APP_URL').'/storage', 44 | 'visibility' => 'public', 45 | 'throw' => false, 46 | ], 47 | 48 | 's3' => [ 49 | 'driver' => 's3', 50 | 'key' => env('AWS_ACCESS_KEY_ID'), 51 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 52 | 'region' => env('AWS_DEFAULT_REGION'), 53 | 'bucket' => env('AWS_BUCKET'), 54 | 'url' => env('AWS_URL'), 55 | 'endpoint' => env('AWS_ENDPOINT'), 56 | 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 57 | 'throw' => false, 58 | ], 59 | 60 | ], 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Symbolic Links 65 | |-------------------------------------------------------------------------- 66 | | 67 | | Here you may configure the symbolic links that will be created when the 68 | | `storage:link` Artisan command is executed. The array keys should be 69 | | the locations of the links and the values should be their targets. 70 | | 71 | */ 72 | 73 | 'links' => [ 74 | public_path('storage') => storage_path('app/public'), 75 | ], 76 | 77 | ]; 78 | -------------------------------------------------------------------------------- /config/hashing.php: -------------------------------------------------------------------------------- 1 | 'bcrypt', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Bcrypt Options 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may specify the configuration options that should be used when 26 | | passwords are hashed using the Bcrypt algorithm. This will allow you 27 | | to control the amount of time it takes to hash the given password. 28 | | 29 | */ 30 | 31 | 'bcrypt' => [ 32 | 'rounds' => env('BCRYPT_ROUNDS', 10), 33 | ], 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Argon Options 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Here you may specify the configuration options that should be used when 41 | | passwords are hashed using the Argon algorithm. These will allow you 42 | | to control the amount of time it takes to hash the given password. 43 | | 44 | */ 45 | 46 | 'argon' => [ 47 | 'memory' => 1024, 48 | 'threads' => 2, 49 | 'time' => 2, 50 | ], 51 | 52 | ]; 53 | -------------------------------------------------------------------------------- /config/jwt.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | return [ 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | JWT Authentication Secret 17 | |-------------------------------------------------------------------------- 18 | | 19 | | Don't forget to set this in your .env file, as it will be used to sign 20 | | your tokens. A helper command is provided for this: 21 | | `php artisan jwt:secret` 22 | | 23 | | Note: This will be used for Symmetric algorithms only (HMAC), 24 | | since RSA and ECDSA use a private/public key combo (See below). 25 | | 26 | */ 27 | 28 | 'secret' => env('JWT_SECRET'), 29 | 30 | /* 31 | |-------------------------------------------------------------------------- 32 | | JWT Authentication Keys 33 | |-------------------------------------------------------------------------- 34 | | 35 | | The algorithm you are using, will determine whether your tokens are 36 | | signed with a random string (defined in `JWT_SECRET`) or using the 37 | | following public & private keys. 38 | | 39 | | Symmetric Algorithms: 40 | | HS256, HS384 & HS512 will use `JWT_SECRET`. 41 | | 42 | | Asymmetric Algorithms: 43 | | RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below. 44 | | 45 | */ 46 | 47 | 'keys' => [ 48 | 49 | /* 50 | |-------------------------------------------------------------------------- 51 | | Public Key 52 | |-------------------------------------------------------------------------- 53 | | 54 | | A path or resource to your public key. 55 | | 56 | | E.g. 'file://path/to/public/key' 57 | | 58 | */ 59 | 60 | 'public' => env('JWT_PUBLIC_KEY'), 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Private Key 65 | |-------------------------------------------------------------------------- 66 | | 67 | | A path or resource to your private key. 68 | | 69 | | E.g. 'file://path/to/private/key' 70 | | 71 | */ 72 | 73 | 'private' => env('JWT_PRIVATE_KEY'), 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Passphrase 78 | |-------------------------------------------------------------------------- 79 | | 80 | | The passphrase for your private key. Can be null if none set. 81 | | 82 | */ 83 | 84 | 'passphrase' => env('JWT_PASSPHRASE'), 85 | 86 | ], 87 | 88 | /* 89 | |-------------------------------------------------------------------------- 90 | | JWT time to live 91 | |-------------------------------------------------------------------------- 92 | | 93 | | Specify the length of time (in minutes) that the token will be valid for. 94 | | Defaults to 1 hour. 95 | | 96 | | You can also set this to null, to yield a never expiring token. 97 | | Some people may want this behaviour for e.g. a mobile app. 98 | | This is not particularly recommended, so make sure you have appropriate 99 | | systems in place to revoke the token if necessary. 100 | | 101 | */ 102 | 103 | 'ttl' => env('JWT_TTL', 60), 104 | 105 | /* 106 | |-------------------------------------------------------------------------- 107 | | Refresh time to live 108 | |-------------------------------------------------------------------------- 109 | | 110 | | Specify the length of time (in minutes) that the token can be refreshed 111 | | within. I.E. The user can refresh their token within a 2 week window of 112 | | the original token being created until they must re-authenticate. 113 | | Defaults to 2 weeks. 114 | | 115 | | You can also set this to null, to yield an infinite refresh time. 116 | | Some may want this instead of never expiring tokens for e.g. a mobile app. 117 | | This is not particularly recommended, so make sure you have appropriate 118 | | systems in place to revoke the token if necessary. 119 | | 120 | */ 121 | 122 | 'refresh_ttl' => env('JWT_REFRESH_TTL', 20160), 123 | 124 | /* 125 | |-------------------------------------------------------------------------- 126 | | JWT hashing algorithm 127 | |-------------------------------------------------------------------------- 128 | | 129 | | Specify the hashing algorithm that will be used to sign the token. 130 | | 131 | | See here: https://github.com/namshi/jose/tree/master/src/Namshi/JOSE/Signer/OpenSSL 132 | | for possible values. 133 | | 134 | */ 135 | 136 | 'algo' => env('JWT_ALGO', 'HS512'), 137 | 138 | /* 139 | |-------------------------------------------------------------------------- 140 | | Required Claims 141 | |-------------------------------------------------------------------------- 142 | | 143 | | Specify the required claims that must exist in any token. 144 | | A TokenInvalidException will be thrown if any of these claims are not 145 | | present in the payload. 146 | | 147 | */ 148 | 149 | 'required_claims' => [ 150 | 'iss', 151 | 'iat', 152 | 'exp', 153 | 'nbf', 154 | 'sub', 155 | 'jti', 156 | ], 157 | 158 | /* 159 | |-------------------------------------------------------------------------- 160 | | Persistent Claims 161 | |-------------------------------------------------------------------------- 162 | | 163 | | Specify the claim keys to be persisted when refreshing a token. 164 | | `sub` and `iat` will automatically be persisted, in 165 | | addition to the these claims. 166 | | 167 | | Note: If a claim does not exist then it will be ignored. 168 | | 169 | */ 170 | 171 | 'persistent_claims' => [ 172 | // 'foo', 173 | // 'bar', 174 | ], 175 | 176 | /* 177 | |-------------------------------------------------------------------------- 178 | | Lock Subject 179 | |-------------------------------------------------------------------------- 180 | | 181 | | This will determine whether a `prv` claim is automatically added to 182 | | the token. The purpose of this is to ensure that if you have multiple 183 | | authentication models e.g. `App\User` & `App\OtherPerson`, then we 184 | | should prevent one authentication request from impersonating another, 185 | | if 2 tokens happen to have the same id across the 2 different models. 186 | | 187 | | Under specific circumstances, you may want to disable this behaviour 188 | | e.g. if you only have one authentication model, then you would save 189 | | a little on token size. 190 | | 191 | */ 192 | 193 | 'lock_subject' => true, 194 | 195 | /* 196 | |-------------------------------------------------------------------------- 197 | | Leeway 198 | |-------------------------------------------------------------------------- 199 | | 200 | | This property gives the jwt timestamp claims some "leeway". 201 | | Meaning that if you have any unavoidable slight clock skew on 202 | | any of your servers then this will afford you some level of cushioning. 203 | | 204 | | This applies to the claims `iat`, `nbf` and `exp`. 205 | | 206 | | Specify in seconds - only if you know you need it. 207 | | 208 | */ 209 | 210 | 'leeway' => env('JWT_LEEWAY', 0), 211 | 212 | /* 213 | |-------------------------------------------------------------------------- 214 | | Blacklist Enabled 215 | |-------------------------------------------------------------------------- 216 | | 217 | | In order to invalidate tokens, you must have the blacklist enabled. 218 | | If you do not want or need this functionality, then set this to false. 219 | | 220 | */ 221 | 222 | 'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true), 223 | 224 | /* 225 | | ------------------------------------------------------------------------- 226 | | Blacklist Grace Period 227 | | ------------------------------------------------------------------------- 228 | | 229 | | When multiple concurrent requests are made with the same JWT, 230 | | it is possible that some of them fail, due to token regeneration 231 | | on every request. 232 | | 233 | | Set grace period in seconds to prevent parallel request failure. 234 | | 235 | */ 236 | 237 | 'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0), 238 | 239 | /* 240 | |-------------------------------------------------------------------------- 241 | | Cookies encryption 242 | |-------------------------------------------------------------------------- 243 | | 244 | | By default Laravel encrypt cookies for security reason. 245 | | If you decide to not decrypt cookies, you will have to configure Laravel 246 | | to not encrypt your cookie token by adding its name into the $except 247 | | array available in the middleware "EncryptCookies" provided by Laravel. 248 | | see https://laravel.com/docs/master/responses#cookies-and-encryption 249 | | for details. 250 | | 251 | | Set it to true if you want to decrypt cookies. 252 | | 253 | */ 254 | 255 | 'decrypt_cookies' => false, 256 | 257 | /* 258 | |-------------------------------------------------------------------------- 259 | | Providers 260 | |-------------------------------------------------------------------------- 261 | | 262 | | Specify the various providers used throughout the package. 263 | | 264 | */ 265 | 266 | 'providers' => [ 267 | 268 | /* 269 | |-------------------------------------------------------------------------- 270 | | JWT Provider 271 | |-------------------------------------------------------------------------- 272 | | 273 | | Specify the provider that is used to create and decode the tokens. 274 | | 275 | */ 276 | 277 | 'jwt' => PHPOpenSourceSaver\JWTAuth\Providers\JWT\Lcobucci::class, 278 | 279 | /* 280 | |-------------------------------------------------------------------------- 281 | | Authentication Provider 282 | |-------------------------------------------------------------------------- 283 | | 284 | | Specify the provider that is used to authenticate users. 285 | | 286 | */ 287 | 288 | 'auth' => PHPOpenSourceSaver\JWTAuth\Providers\Auth\Illuminate::class, 289 | 290 | /* 291 | |-------------------------------------------------------------------------- 292 | | Storage Provider 293 | |-------------------------------------------------------------------------- 294 | | 295 | | Specify the provider that is used to store tokens in the blacklist. 296 | | 297 | */ 298 | 299 | 'storage' => PHPOpenSourceSaver\JWTAuth\Providers\Storage\Illuminate::class, 300 | 301 | ], 302 | 303 | ]; 304 | -------------------------------------------------------------------------------- /config/logging.php: -------------------------------------------------------------------------------- 1 | env('LOG_CHANNEL', 'stack'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Deprecations Log Channel 26 | |-------------------------------------------------------------------------- 27 | | 28 | | This option controls the log channel that should be used to log warnings 29 | | regarding deprecated PHP and library features. This allows you to get 30 | | your application ready for upcoming major versions of dependencies. 31 | | 32 | */ 33 | 34 | 'deprecations' => [ 35 | 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), 36 | 'trace' => env('LOG_DEPRECATIONS_TRACE', false), 37 | ], 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Log Channels 42 | |-------------------------------------------------------------------------- 43 | | 44 | | Here you may configure the log channels for your application. Laravel 45 | | utilizes the Monolog PHP logging library, which includes a variety 46 | | of powerful log handlers and formatters that you're free to use. 47 | | 48 | | Available drivers: "single", "daily", "slack", "syslog", 49 | | "errorlog", "monolog", "custom", "stack" 50 | | 51 | */ 52 | 53 | 'channels' => [ 54 | 55 | 'stack' => [ 56 | 'driver' => 'stack', 57 | 'channels' => explode(',', env('LOG_STACK', 'single')), 58 | 'ignore_exceptions' => false, 59 | ], 60 | 61 | 'single' => [ 62 | 'driver' => 'single', 63 | 'path' => storage_path('logs/laravel.log'), 64 | 'level' => env('LOG_LEVEL', 'debug'), 65 | 'replace_placeholders' => true, 66 | ], 67 | 68 | 'daily' => [ 69 | 'driver' => 'daily', 70 | 'path' => storage_path('logs/laravel.log'), 71 | 'level' => env('LOG_LEVEL', 'debug'), 72 | 'days' => env('LOG_DAILY_DAYS', 14), 73 | 'replace_placeholders' => true, 74 | ], 75 | 76 | 'slack' => [ 77 | 'driver' => 'slack', 78 | 'url' => env('LOG_SLACK_WEBHOOK_URL'), 79 | 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), 80 | 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), 81 | 'level' => env('LOG_LEVEL', 'critical'), 82 | 'replace_placeholders' => true, 83 | ], 84 | 85 | 'papertrail' => [ 86 | 'driver' => 'monolog', 87 | 'level' => env('LOG_LEVEL', 'debug'), 88 | 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), 89 | 'handler_with' => [ 90 | 'host' => env('PAPERTRAIL_URL'), 91 | 'port' => env('PAPERTRAIL_PORT'), 92 | 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), 93 | ], 94 | 'processors' => [PsrLogMessageProcessor::class], 95 | ], 96 | 97 | 'stderr' => [ 98 | 'driver' => 'monolog', 99 | 'level' => env('LOG_LEVEL', 'debug'), 100 | 'handler' => StreamHandler::class, 101 | 'formatter' => env('LOG_STDERR_FORMATTER'), 102 | 'with' => [ 103 | 'stream' => 'php://stderr', 104 | ], 105 | 'processors' => [PsrLogMessageProcessor::class], 106 | ], 107 | 108 | 'syslog' => [ 109 | 'driver' => 'syslog', 110 | 'level' => env('LOG_LEVEL', 'debug'), 111 | 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), 112 | 'replace_placeholders' => true, 113 | ], 114 | 115 | 'errorlog' => [ 116 | 'driver' => 'errorlog', 117 | 'level' => env('LOG_LEVEL', 'debug'), 118 | 'replace_placeholders' => true, 119 | ], 120 | 121 | 'null' => [ 122 | 'driver' => 'monolog', 123 | 'handler' => NullHandler::class, 124 | ], 125 | 126 | 'emergency' => [ 127 | 'path' => storage_path('logs/laravel.log'), 128 | ], 129 | 130 | ], 131 | 132 | ]; 133 | -------------------------------------------------------------------------------- /config/mail.php: -------------------------------------------------------------------------------- 1 | env('MAIL_MAILER', 'log'), 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Mailer Configurations 22 | |-------------------------------------------------------------------------- 23 | | 24 | | Here you may configure all of the mailers used by your application plus 25 | | their respective settings. Several examples have been configured for 26 | | you and you are free to add your own as your application requires. 27 | | 28 | | Laravel supports a variety of mail "transport" drivers that can be used 29 | | when delivering an email. You may specify which one you're using for 30 | | your mailers below. You may also add additional mailers if needed. 31 | | 32 | | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", 33 | | "postmark", "resend", "log", "array", 34 | | "failover", "roundrobin" 35 | | 36 | */ 37 | 38 | 'mailers' => [ 39 | 40 | 'smtp' => [ 41 | 'transport' => 'smtp', 42 | 'scheme' => env('MAIL_SCHEME'), 43 | 'url' => env('MAIL_URL'), 44 | 'host' => env('MAIL_HOST', '127.0.0.1'), 45 | 'port' => env('MAIL_PORT', 2525), 46 | 'username' => env('MAIL_USERNAME'), 47 | 'password' => env('MAIL_PASSWORD'), 48 | 'timeout' => null, 49 | 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), 50 | ], 51 | 52 | 'ses' => [ 53 | 'transport' => 'ses', 54 | ], 55 | 56 | 'postmark' => [ 57 | 'transport' => 'postmark', 58 | // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), 59 | // 'client' => [ 60 | // 'timeout' => 5, 61 | // ], 62 | ], 63 | 64 | 'resend' => [ 65 | 'transport' => 'resend', 66 | ], 67 | 68 | 'sendmail' => [ 69 | 'transport' => 'sendmail', 70 | 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), 71 | ], 72 | 73 | 'log' => [ 74 | 'transport' => 'log', 75 | 'channel' => env('MAIL_LOG_CHANNEL'), 76 | ], 77 | 78 | 'array' => [ 79 | 'transport' => 'array', 80 | ], 81 | 82 | 'failover' => [ 83 | 'transport' => 'failover', 84 | 'mailers' => [ 85 | 'smtp', 86 | 'log', 87 | ], 88 | ], 89 | 90 | 'roundrobin' => [ 91 | 'transport' => 'roundrobin', 92 | 'mailers' => [ 93 | 'ses', 94 | 'postmark', 95 | ], 96 | ], 97 | 98 | ], 99 | 100 | /* 101 | |-------------------------------------------------------------------------- 102 | | Global "From" Address 103 | |-------------------------------------------------------------------------- 104 | | 105 | | You may wish for all emails sent by your application to be sent from 106 | | the same address. Here you may specify a name and address that is 107 | | used globally for all emails that are sent by your application. 108 | | 109 | */ 110 | 111 | 'from' => [ 112 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), 113 | 'name' => env('MAIL_FROM_NAME', 'Example'), 114 | ], 115 | 116 | ]; 117 | -------------------------------------------------------------------------------- /config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_CONNECTION', 'database'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Queue Connections 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may configure the connection options for every queue backend 24 | | used by your application. An example configuration is provided for 25 | | each backend supported by Laravel. You're also free to add more. 26 | | 27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'connection' => env('DB_QUEUE_CONNECTION'), 40 | 'table' => env('DB_QUEUE_TABLE', 'jobs'), 41 | 'queue' => env('DB_QUEUE', 'default'), 42 | 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), 43 | 'after_commit' => false, 44 | ], 45 | 46 | 'beanstalkd' => [ 47 | 'driver' => 'beanstalkd', 48 | 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), 49 | 'queue' => env('BEANSTALKD_QUEUE', 'default'), 50 | 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), 51 | 'block_for' => 0, 52 | 'after_commit' => false, 53 | ], 54 | 55 | 'sqs' => [ 56 | 'driver' => 'sqs', 57 | 'key' => env('AWS_ACCESS_KEY_ID'), 58 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 59 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), 60 | 'queue' => env('SQS_QUEUE', 'default'), 61 | 'suffix' => env('SQS_SUFFIX'), 62 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 63 | 'after_commit' => false, 64 | ], 65 | 66 | 'redis' => [ 67 | 'driver' => 'redis', 68 | 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), 69 | 'queue' => env('REDIS_QUEUE', 'default'), 70 | 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), 71 | 'block_for' => null, 72 | 'after_commit' => false, 73 | ], 74 | 75 | ], 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Job Batching 80 | |-------------------------------------------------------------------------- 81 | | 82 | | The following options configure the database and table that store job 83 | | batching information. These options can be updated to any database 84 | | connection and table which has been defined by your application. 85 | | 86 | */ 87 | 88 | 'batching' => [ 89 | 'database' => env('DB_CONNECTION', 'sqlite'), 90 | 'table' => 'job_batches', 91 | ], 92 | 93 | /* 94 | |-------------------------------------------------------------------------- 95 | | Failed Queue Jobs 96 | |-------------------------------------------------------------------------- 97 | | 98 | | These options configure the behavior of failed queue job logging so you 99 | | can control how and where failed jobs are stored. Laravel ships with 100 | | support for storing failed jobs in a simple file or in a database. 101 | | 102 | | Supported drivers: "database-uuids", "dynamodb", "file", "null" 103 | | 104 | */ 105 | 106 | 'failed' => [ 107 | 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), 108 | 'database' => env('DB_CONNECTION', 'sqlite'), 109 | 'table' => 'failed_jobs', 110 | ], 111 | 112 | ]; 113 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'token' => env('POSTMARK_TOKEN'), 19 | ], 20 | 21 | 'ses' => [ 22 | 'key' => env('AWS_ACCESS_KEY_ID'), 23 | 'secret' => env('AWS_SECRET_ACCESS_KEY'), 24 | 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 25 | ], 26 | 27 | 'resend' => [ 28 | 'key' => env('RESEND_KEY'), 29 | ], 30 | 31 | 'slack' => [ 32 | 'notifications' => [ 33 | 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), 34 | 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), 35 | ], 36 | ], 37 | 38 | ]; 39 | -------------------------------------------------------------------------------- /config/session.php: -------------------------------------------------------------------------------- 1 | env('SESSION_DRIVER', 'database'), 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Session Lifetime 26 | |-------------------------------------------------------------------------- 27 | | 28 | | Here you may specify the number of minutes that you wish the session 29 | | to be allowed to remain idle before it expires. If you want them 30 | | to expire immediately when the browser is closed then you may 31 | | indicate that via the expire_on_close configuration option. 32 | | 33 | */ 34 | 35 | 'lifetime' => env('SESSION_LIFETIME', 120), 36 | 37 | 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Session Encryption 42 | |-------------------------------------------------------------------------- 43 | | 44 | | This option allows you to easily specify that all of your session data 45 | | should be encrypted before it's stored. All encryption is performed 46 | | automatically by Laravel and you may use the session like normal. 47 | | 48 | */ 49 | 50 | 'encrypt' => env('SESSION_ENCRYPT', false), 51 | 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | Session File Location 55 | |-------------------------------------------------------------------------- 56 | | 57 | | When utilizing the "file" session driver, the session files are placed 58 | | on disk. The default storage location is defined here; however, you 59 | | are free to provide another location where they should be stored. 60 | | 61 | */ 62 | 63 | 'files' => storage_path('framework/sessions'), 64 | 65 | /* 66 | |-------------------------------------------------------------------------- 67 | | Session Database Connection 68 | |-------------------------------------------------------------------------- 69 | | 70 | | When using the "database" or "redis" session drivers, you may specify a 71 | | connection that should be used to manage these sessions. This should 72 | | correspond to a connection in your database configuration options. 73 | | 74 | */ 75 | 76 | 'connection' => env('SESSION_CONNECTION'), 77 | 78 | /* 79 | |-------------------------------------------------------------------------- 80 | | Session Database Table 81 | |-------------------------------------------------------------------------- 82 | | 83 | | When using the "database" session driver, you may specify the table to 84 | | be used to store sessions. Of course, a sensible default is defined 85 | | for you; however, you're welcome to change this to another table. 86 | | 87 | */ 88 | 89 | 'table' => env('SESSION_TABLE', 'sessions'), 90 | 91 | /* 92 | |-------------------------------------------------------------------------- 93 | | Session Cache Store 94 | |-------------------------------------------------------------------------- 95 | | 96 | | When using one of the framework's cache driven session backends, you may 97 | | define the cache store which should be used to store the session data 98 | | between requests. This must match one of your defined cache stores. 99 | | 100 | | Affects: "apc", "dynamodb", "memcached", "redis" 101 | | 102 | */ 103 | 104 | 'store' => env('SESSION_STORE'), 105 | 106 | /* 107 | |-------------------------------------------------------------------------- 108 | | Session Sweeping Lottery 109 | |-------------------------------------------------------------------------- 110 | | 111 | | Some session drivers must manually sweep their storage location to get 112 | | rid of old sessions from storage. Here are the chances that it will 113 | | happen on a given request. By default, the odds are 2 out of 100. 114 | | 115 | */ 116 | 117 | 'lottery' => [2, 100], 118 | 119 | /* 120 | |-------------------------------------------------------------------------- 121 | | Session Cookie Name 122 | |-------------------------------------------------------------------------- 123 | | 124 | | Here you may change the name of the session cookie that is created by 125 | | the framework. Typically, you should not need to change this value 126 | | since doing so does not grant a meaningful security improvement. 127 | | 128 | */ 129 | 130 | 'cookie' => env( 131 | 'SESSION_COOKIE', 132 | Str::slug(env('APP_NAME', 'laravel'), '_').'_session' 133 | ), 134 | 135 | /* 136 | |-------------------------------------------------------------------------- 137 | | Session Cookie Path 138 | |-------------------------------------------------------------------------- 139 | | 140 | | The session cookie path determines the path for which the cookie will 141 | | be regarded as available. Typically, this will be the root path of 142 | | your application, but you're free to change this when necessary. 143 | | 144 | */ 145 | 146 | 'path' => env('SESSION_PATH', '/'), 147 | 148 | /* 149 | |-------------------------------------------------------------------------- 150 | | Session Cookie Domain 151 | |-------------------------------------------------------------------------- 152 | | 153 | | This value determines the domain and subdomains the session cookie is 154 | | available to. By default, the cookie will be available to the root 155 | | domain and all subdomains. Typically, this shouldn't be changed. 156 | | 157 | */ 158 | 159 | 'domain' => env('SESSION_DOMAIN'), 160 | 161 | /* 162 | |-------------------------------------------------------------------------- 163 | | HTTPS Only Cookies 164 | |-------------------------------------------------------------------------- 165 | | 166 | | By setting this option to true, session cookies will only be sent back 167 | | to the server if the browser has a HTTPS connection. This will keep 168 | | the cookie from being sent to you when it can't be done securely. 169 | | 170 | */ 171 | 172 | 'secure' => env('SESSION_SECURE_COOKIE'), 173 | 174 | /* 175 | |-------------------------------------------------------------------------- 176 | | HTTP Access Only 177 | |-------------------------------------------------------------------------- 178 | | 179 | | Setting this value to true will prevent JavaScript from accessing the 180 | | value of the cookie and the cookie will only be accessible through 181 | | the HTTP protocol. It's unlikely you should disable this option. 182 | | 183 | */ 184 | 185 | 'http_only' => env('SESSION_HTTP_ONLY', true), 186 | 187 | /* 188 | |-------------------------------------------------------------------------- 189 | | Same-Site Cookies 190 | |-------------------------------------------------------------------------- 191 | | 192 | | This option determines how your cookies behave when cross-site requests 193 | | take place, and can be used to mitigate CSRF attacks. By default, we 194 | | will set this value to "lax" to permit secure cross-site requests. 195 | | 196 | | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value 197 | | 198 | | Supported: "lax", "strict", "none", null 199 | | 200 | */ 201 | 202 | 'same_site' => env('SESSION_SAME_SITE', 'lax'), 203 | 204 | /* 205 | |-------------------------------------------------------------------------- 206 | | Partitioned Cookies 207 | |-------------------------------------------------------------------------- 208 | | 209 | | Setting this value to true will tie the cookie to the top-level site for 210 | | a cross-site context. Partitioned cookies are accepted by the browser 211 | | when flagged "secure" and the Same-Site attribute is set to "none". 212 | | 213 | */ 214 | 215 | 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), 216 | 217 | ]; 218 | -------------------------------------------------------------------------------- /config/stubs.php: -------------------------------------------------------------------------------- 1 | base_path('vendor/specialtactics/l5-api/resources/stubs'), 11 | 12 | /* 13 | |-------------------------------------------------------------------------- 14 | | Default namespaces for the classes 15 | |-------------------------------------------------------------------------- 16 | | Warning! Root application namespaсe (like "App") should be skipped. 17 | */ 18 | 'namespaces' => [ 19 | 'channel' => '\Broadcasting', 20 | 'command' => '\Console\Commands', 21 | 'controller' => '\Http\Controllers', 22 | 'event' => '\Events', 23 | 'exception' => '\Exceptions', 24 | 'job' => '\Jobs', 25 | 'listener' => '\Listeners', 26 | 'mail' => '\Mail', 27 | 'middleware' => '\Http\Middleware', 28 | 'model' => '\Models', 29 | 'notification' => '\Notifications', 30 | 'policy' => '\Policies', 31 | 'provider' => '\Providers', 32 | 'request' => '\Http\Requests', 33 | 'resource' => '\Http\Resources', 34 | 'rule' => '\Rules', 35 | ], 36 | 37 | ]; 38 | -------------------------------------------------------------------------------- /config/telescope.php: -------------------------------------------------------------------------------- 1 | 'telescope', 9 | 10 | /* 11 | |-------------------------------------------------------------------------- 12 | | Telescope UI light mode 13 | |-------------------------------------------------------------------------- 14 | | 15 | | Change to 'dark' for dark mode 16 | */ 17 | 'ui-mode' => env('TELESCOPE_UI_MODE', 'light'), 18 | 19 | /* 20 | |-------------------------------------------------------------------------- 21 | | Telescope Storage Driver 22 | |-------------------------------------------------------------------------- 23 | | 24 | | This configuration options determines the storage driver that will 25 | | be used to store Telescope's data. In addition, you may set any 26 | | custom options as needed by the particular driver you choose. 27 | | 28 | */ 29 | 30 | 'driver' => env('TELESCOPE_DRIVER', 'database'), 31 | 32 | 'storage' => [ 33 | 'database' => [ 34 | 'connection' => env('DB_CONNECTION', 'mysql'), 35 | ], 36 | ], 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Telescope Master Switch 41 | |-------------------------------------------------------------------------- 42 | | 43 | | This option may be used to disable all Telescope watchers regardless 44 | | of their individual configuration, which simply provides a single 45 | | and convenient way to enable or disable Telescope data storage. 46 | | 47 | */ 48 | 49 | 'enabled' => env('TELESCOPE_ENABLED', true), 50 | 51 | /* 52 | |-------------------------------------------------------------------------- 53 | | Telescope Route Middleware 54 | |-------------------------------------------------------------------------- 55 | | 56 | | These middleware will be assigned to every Telescope route, giving you 57 | | the chance to add your own middleware to this list or change any of 58 | | the existing middleware. Or, you can simply stick with this list. 59 | | 60 | */ 61 | 62 | 'middleware' => [ 63 | 'web', 64 | Authorize::class, 65 | ], 66 | 67 | /* 68 | |-------------------------------------------------------------------------- 69 | | Ignored Paths & Commands 70 | |-------------------------------------------------------------------------- 71 | | 72 | | The following array lists the URI paths and Artisan commands that will 73 | | not be watched by Telescope. In addition to this list, some Laravel 74 | | commands, like migrations and queue commands, are always ignored. 75 | | 76 | */ 77 | 78 | 'ignore_paths' => [ 79 | // 80 | ], 81 | 82 | 'ignore_commands' => [ 83 | // 84 | ], 85 | 86 | /* 87 | |-------------------------------------------------------------------------- 88 | | Telescope Watchers 89 | |-------------------------------------------------------------------------- 90 | | 91 | | The following array lists the "watchers" that will be registered with 92 | | Telescope. The watchers gather the application's profile data when 93 | | a request or task is executed. Feel free to customize this list. 94 | | 95 | */ 96 | 97 | 'watchers' => [ 98 | Watchers\CacheWatcher::class => env('TELESCOPE_CACHE_WATCHER', true), 99 | Watchers\CommandWatcher::class => env('TELESCOPE_COMMAND_WATCHER', true), 100 | Watchers\DumpWatcher::class => env('TELESCOPE_DUMP_WATCHER', true), 101 | Watchers\EventWatcher::class => env('TELESCOPE_EVENT_WATCHER', true), 102 | Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true), 103 | Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true), 104 | Watchers\LogWatcher::class => env('TELESCOPE_LOG_WATCHER', true), 105 | Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true), 106 | Watchers\ModelWatcher::class => env('TELESCOPE_MODEL_WATCHER', true), 107 | Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true), 108 | 109 | Watchers\QueryWatcher::class => [ 110 | 'enabled' => env('TELESCOPE_QUERY_WATCHER', true), 111 | 'slow' => env('TELESCOPE_QUERY_SLOW', 100), 112 | ], 113 | 114 | Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true), 115 | 116 | Watchers\RequestWatcher::class => [ 117 | 'enabled' => env('TELESCOPE_REQUEST_WATCHER', true), 118 | 'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64), 119 | ], 120 | 121 | Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true), 122 | ], 123 | ]; 124 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => env( 32 | 'VIEW_COMPILED_PATH', 33 | realpath(storage_path('framework/views')) 34 | ), 35 | 36 | ]; 37 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class UserFactory extends Factory 13 | { 14 | /** 15 | * The current password being used by the factory. 16 | */ 17 | protected static ?string $password; 18 | 19 | /** 20 | * Define the model's default state. 21 | * 22 | * @return array 23 | */ 24 | public function definition(): array 25 | { 26 | return [ 27 | 'name' => fake()->name(), 28 | 'email' => fake()->unique()->safeEmail(), 29 | 'email_verified_at' => now(), 30 | 'password' => static::$password ??= Hash::make('password'), 31 | 'remember_token' => Str::random(10), 32 | ]; 33 | } 34 | 35 | /** 36 | * Indicate that the model's email address should be unverified. 37 | */ 38 | public function unverified(): static 39 | { 40 | return $this->state(fn (array $attributes) => [ 41 | 'email_verified_at' => null, 42 | ]); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /database/migrations/0001_01_01_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | uuid('role_id')->primary(); 21 | $table->string('name')->unique(); 22 | $table->string('description'); 23 | $table->timestamps(); 24 | $table->softDeletes(); 25 | }); 26 | 27 | Schema::create(static::TABLE_NAME_USERS, function (Blueprint $table) { 28 | $table->uuid('user_id')->primary(); 29 | $table->string('name'); 30 | $table->string('email')->unique(); 31 | $table->timestamp('email_verified_at')->nullable(); 32 | $table->string('password'); 33 | $table->uuid('primary_role')->nullable(); 34 | $table->foreign('primary_role')->references('role_id')->on(static::TABLE_NAME_ROLES)->onDelete('set null'); 35 | $table->rememberToken(); 36 | $table->timestamps(); 37 | }); 38 | 39 | Schema::create(static::TABLE_NAME_USER_ROLES, function (Blueprint $table) { 40 | $table->uuid('user_id'); 41 | $table->uuid('role_id'); 42 | $table->foreign('user_id')->references('user_id')->on(static::TABLE_NAME_USERS)->onDelete('cascade'); 43 | $table->foreign('role_id')->references('role_id')->on(static::TABLE_NAME_ROLES)->onDelete('cascade'); 44 | 45 | $table->primary(['user_id', 'role_id']); 46 | 47 | $table->timestamps(); 48 | $table->softDeletes(); 49 | }); 50 | 51 | Schema::create(static::TABLE_NAME_PASSWORD_RESET_TOKENS, function (Blueprint $table) { 52 | $table->string('email')->primary(); 53 | $table->string('token'); 54 | $table->timestamp('created_at')->nullable(); 55 | }); 56 | 57 | Schema::create(static::TABLE_NAME_SESSIONS, function (Blueprint $table) { 58 | $table->string('id')->primary(); 59 | $table->uuid('user_id')->nullable()->index(); 60 | $table->foreign('user_id')->references('user_id')->on(static::TABLE_NAME_USERS)->onDelete('cascade'); 61 | $table->string('ip_address', 45)->nullable(); 62 | $table->text('user_agent')->nullable(); 63 | $table->longText('payload'); 64 | $table->integer('last_activity')->index(); 65 | }); 66 | } 67 | 68 | /** 69 | * Reverse the migrations. 70 | */ 71 | public function down(): void 72 | { 73 | Schema::dropIfExists(static::TABLE_NAME_SESSIONS); 74 | Schema::dropIfExists(static::TABLE_NAME_PASSWORD_RESET_TOKENS); 75 | Schema::dropIfExists(static::TABLE_NAME_USER_ROLES); 76 | Schema::dropIfExists(static::TABLE_NAME_USERS); 77 | Schema::dropIfExists(static::TABLE_NAME_ROLES); 78 | 79 | } 80 | }; 81 | -------------------------------------------------------------------------------- /database/migrations/0001_01_01_000001_create_cache_table.php: -------------------------------------------------------------------------------- 1 | string('key')->primary(); 16 | $table->mediumText('value'); 17 | $table->integer('expiration'); 18 | }); 19 | 20 | Schema::create('cache_locks', function (Blueprint $table) { 21 | $table->string('key')->primary(); 22 | $table->string('owner'); 23 | $table->integer('expiration'); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | */ 30 | public function down(): void 31 | { 32 | Schema::dropIfExists('cache'); 33 | Schema::dropIfExists('cache_locks'); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /database/migrations/0001_01_01_000002_create_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('queue')->index(); 17 | $table->longText('payload'); 18 | $table->unsignedTinyInteger('attempts'); 19 | $table->unsignedInteger('reserved_at')->nullable(); 20 | $table->unsignedInteger('available_at'); 21 | $table->unsignedInteger('created_at'); 22 | }); 23 | 24 | Schema::create('job_batches', function (Blueprint $table) { 25 | $table->string('id')->primary(); 26 | $table->string('name'); 27 | $table->integer('total_jobs'); 28 | $table->integer('pending_jobs'); 29 | $table->integer('failed_jobs'); 30 | $table->longText('failed_job_ids'); 31 | $table->mediumText('options')->nullable(); 32 | $table->integer('cancelled_at')->nullable(); 33 | $table->integer('created_at'); 34 | $table->integer('finished_at')->nullable(); 35 | }); 36 | 37 | Schema::create('failed_jobs', function (Blueprint $table) { 38 | $table->id(); 39 | $table->string('uuid')->unique(); 40 | $table->text('connection'); 41 | $table->text('queue'); 42 | $table->longText('payload'); 43 | $table->longText('exception'); 44 | $table->timestamp('failed_at')->useCurrent(); 45 | }); 46 | } 47 | 48 | /** 49 | * Reverse the migrations. 50 | */ 51 | public function down(): void 52 | { 53 | Schema::dropIfExists('jobs'); 54 | Schema::dropIfExists('job_batches'); 55 | Schema::dropIfExists('failed_jobs'); 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /database/seeders/BaseSeeder.php: -------------------------------------------------------------------------------- 1 | faker = \Faker\Factory::create(); 24 | 25 | $this->before(); 26 | 27 | // Run in any environment 28 | $this->runAlways(); 29 | 30 | // Production Only 31 | if (app()->environment() === 'production') { 32 | $this->runProduction(); 33 | } 34 | // Fake environments 35 | else { 36 | $this->runFake(); 37 | } 38 | 39 | $this->after(); 40 | } 41 | 42 | /** 43 | * Run fake seeds - for non production environments 44 | * 45 | * @return void 46 | */ 47 | public function runFake() 48 | { 49 | } 50 | 51 | /** 52 | * Run seeds to be ran only on production environments 53 | * 54 | * @return void 55 | */ 56 | public function runProduction() 57 | { 58 | } 59 | 60 | /** 61 | * Run seeds to be ran on every environment (including production) 62 | * 63 | * @return void 64 | */ 65 | public function runAlways() 66 | { 67 | } 68 | 69 | /** 70 | * Run before all any seeding 71 | * 72 | * @return void 73 | */ 74 | public function before() 75 | { 76 | } 77 | 78 | /** 79 | * Run after all seeding 80 | * 81 | * @return void 82 | */ 83 | public function after() 84 | { 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(RoleTableSeeder::class); 17 | $this->call(UserStorySeeder::class); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /database/seeders/RoleTableSeeder.php: -------------------------------------------------------------------------------- 1 | 'admin', 13 | 'description' => 'Administrator Users', 14 | ]); 15 | 16 | Role::firstOrCreate([ 17 | 'name' => 'regular', 18 | 'description' => 'Regular Users', 19 | ]); 20 | } 21 | 22 | public function runFake() 23 | { 24 | for ($i = 0; $i < 10; ++$i) { 25 | Role::firstOrCreate([ 26 | 'name' => $this->faker->unique()->word(), 27 | 'description' => $this->faker->sentence(), 28 | ]); 29 | } 30 | } 31 | 32 | /** 33 | * Get a collection of random roles 34 | * Remove duplicates to prevent SQL errors, also prevent infinite loop in case of not enough roles 35 | * 36 | * @param $count int How many roles to get 37 | * @return \Illuminate\Support\Collection 38 | */ 39 | public static function getRandomRoles($count) 40 | { 41 | $roles = Role::all(); 42 | 43 | $fakeRoles = []; 44 | $i = 0; 45 | 46 | do { 47 | ++$i; 48 | $fakeRoles[] = $roles->whereNotIn('name', ['admin'])->random(); 49 | $fakeRoles = array_unique($fakeRoles); 50 | } while (count($fakeRoles) < $count && $i < 50); // Iteration limit 51 | 52 | return collect($fakeRoles); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /database/seeders/UserStorySeeder.php: -------------------------------------------------------------------------------- 1 | 'admin@admin.com', 15 | ]; 16 | 17 | public function runFake() 18 | { 19 | // Grab all roles for reference 20 | $roles = Role::all(); 21 | 22 | // Create an admin user 23 | \App\Models\User::factory()->create([ 24 | 'name' => 'Admin', 25 | 'email' => static::ADMIN_CREDENTIALS['email'], 26 | 'primary_role' => $roles->where('name', 'admin')->first()->role_id, 27 | ]); 28 | 29 | // Create regular user 30 | \App\Models\User::factory()->create([ 31 | 'name' => 'Bob', 32 | 'email' => 'bob@bob.com', 33 | 'primary_role' => $roles->where('name', 'regular')->first()->role_id, 34 | ]); 35 | 36 | // Get some random roles to assign to users 37 | $fakeRolesToAssignCount = 3; 38 | $fakeRolesToAssign = RoleTableSeeder::getRandomRoles($fakeRolesToAssignCount); 39 | 40 | // Assign fake roles to users 41 | for ($i = 0; $i < 5; ++$i) { 42 | $user = \App\Models\User::factory()->create([ 43 | 'primary_role' => $roles->random()->role_id, 44 | ]); 45 | 46 | for ($j = 0; $j < count($fakeRolesToAssign); ++$j) { 47 | $user->roles()->save($fakeRolesToAssign->shift()); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | 5 | # Workspace Container 6 | workspace: 7 | container_name: your_project_workspace 8 | build: 9 | context: ./env/docker/workspace 10 | args: 11 | - PHP_VERSION=${PHP_VERSION} 12 | - PHP_XDEBUG_ENABLE=${PHP_XDEBUG_ENABLE} 13 | - PHP_XDEBUG_VERSION=${PHP_XDEBUG_VERSION} 14 | - PHP_XDEBUG_REMOTE_CONNECT_BACK=${PHP_XDEBUG_REMOTE_CONNECT_BACK} 15 | - COMPOSER_PROCESS_TIMEOUT=${COMPOSER_PROCESS_TIMEOUT} 16 | volumes: 17 | - ./:/var/www:cached 18 | - ~/.ssh:/home/laradock/.ssh 19 | - ~/.gitconfig:/home/laradock/.gitconfig 20 | - ~/.config/composer:/home/laradock/.config/composer 21 | - ~/.aws:/home/laradock/.aws 22 | tty: true 23 | networks: 24 | - your_project_network 25 | dns: 26 | - 8.8.8.8 27 | - 1.1.1.1 28 | 29 | # PHP-FPM 30 | php-fpm: 31 | container_name: your_project_php_fpm 32 | build: 33 | context: ./env/docker/php-fpm 34 | args: 35 | - PHP_VERSION=${PHP_VERSION} 36 | - PHP_XDEBUG_ENABLE=${PHP_XDEBUG_ENABLE} 37 | - PHP_XDEBUG_VERSION=${PHP_XDEBUG_VERSION} 38 | - PHP_XDEBUG_REMOTE_CONNECT_BACK=${PHP_XDEBUG_REMOTE_CONNECT_BACK} 39 | volumes: 40 | - ./:/var/www:cached 41 | depends_on: 42 | - workspace 43 | networks: 44 | - your_project_network 45 | 46 | # NGINX 47 | nginx: 48 | container_name: your_project_nginx 49 | build: 50 | context: ./env/docker/nginx 51 | volumes: 52 | - ./:/var/www:cached 53 | - ${NGINX_HOST_LOG_PATH}:/var/log/nginx 54 | depends_on: 55 | - php-fpm 56 | - postgres 57 | environment: 58 | - HTTPS_METHOD=${HTTPS_METHOD} 59 | ports: 60 | - 80:80 61 | networks: 62 | - your_project_network 63 | 64 | # PostgreSQL 65 | postgres: 66 | container_name: your_project_postgres 67 | build: 68 | context: ./env/docker/postgres 69 | volumes: 70 | - ${DATA_PATH_HOST}postgres:/var/lib/postgresql/data 71 | environment: 72 | - POSTGRES_DB=${POSTGRES_DB} 73 | - POSTGRES_USER=${POSTGRES_USER} 74 | - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} 75 | networks: 76 | - your_project_network 77 | 78 | # Redis 79 | redis: 80 | container_name: your_project_redis 81 | image: "redis" 82 | hostname: your_project_redis 83 | networks: 84 | - your_project_network 85 | 86 | # Volumes configuration 87 | volumes: 88 | postgres: 89 | driver: "local" 90 | 91 | # Network configuration 92 | networks: 93 | your_project_network: 94 | name: your_project_network 95 | -------------------------------------------------------------------------------- /docs/example-apache-vhost: -------------------------------------------------------------------------------- 1 | 2 | ServerAdmin webmaster@localhost 3 | ServerName 4 | 5 | RequestHeader append Accept "application/vnd..v1+json" 6 | 7 | DocumentRoot 8 | 9 | > 10 | Options Indexes FollowSymLinks MultiViews 11 | AllowOverride All 12 | Require all granted 13 | 14 | DirectoryIndex index.php 15 | FallbackResource /index.php 16 | 17 | 18 | # Pass through auth header 19 | SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0 20 | 21 | # Set CORS headers 22 | Header set Access-Control-Allow-Origin "*" 23 | 24 | ## ProxyPass to php-fpm 25 | ## Use your own config, this is just an example 26 | ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/path/to/$1 27 | 28 | #LogLevel warn 29 | #ErrorLog /path/to/api.log 30 | #CustomLog /path/to/api-access.log combined 31 | 32 | -------------------------------------------------------------------------------- /docs/example-nginx-vhost: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | listen [::]:80; 4 | 5 | server_name ; 6 | root ; 7 | index index.php; 8 | 9 | location / { 10 | try_files $uri $uri/ /index.php$is_args$args; 11 | } 12 | 13 | location ~ \.php$ { 14 | try_files $uri /index.php =404; 15 | fastcgi_pass php-upstream; 16 | fastcgi_index index.php; 17 | fastcgi_buffers 16 16k; 18 | fastcgi_buffer_size 32k; 19 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 20 | #fixes timeouts 21 | fastcgi_read_timeout 600; 22 | include fastcgi_params; 23 | 24 | add_header 'Access-Control-Allow-Origin' "$http_origin" always; 25 | add_header 'Access-Control-Allow-Credentials' 'true' always; 26 | add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always; 27 | add_header 'Access-Control-Allow-Headers' 'Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With' always; 28 | add_header 'Access-Control-Expose-Headers' 'Authorization, Content-Length, Content-Range' always; 29 | } 30 | 31 | location ~ /\.ht { 32 | deny all; 33 | } 34 | 35 | error_log /var/log/nginx/laravel_error.log; 36 | access_log /var/log/nginx/laravel_access.log; 37 | } 38 | -------------------------------------------------------------------------------- /docs/postman/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "ea7b4604-3bd1-473f-b0ab-137417c6c18d", 4 | "name": "L5 API Boilerplate", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "Auth", 10 | "item": [ 11 | { 12 | "name": "Login as Admin", 13 | "event": [ 14 | { 15 | "listen": "test", 16 | "script": { 17 | "id": "6d953560-1388-416e-8a7b-6445e9e8b1a8", 18 | "exec": [ 19 | "const res = pm.response.json();", 20 | "", 21 | "pm.environment.set(\"adminJWT\", res.data.jwt);", 22 | "" 23 | ], 24 | "type": "text/javascript" 25 | } 26 | }, 27 | { 28 | "listen": "prerequest", 29 | "script": { 30 | "id": "9b4e7b33-5409-42ff-9db2-f4f2825e913a", 31 | "exec": [ 32 | "pm.variables.set('authHeader', btoa(pm.environment.get('adminEmail') + ':' + pm.environment.get('adminPassword')));" 33 | ], 34 | "type": "text/javascript" 35 | } 36 | } 37 | ], 38 | "request": { 39 | "method": "GET", 40 | "header": [ 41 | { 42 | "key": "Content-Type", 43 | "value": "application/json" 44 | }, 45 | { 46 | "key": "Authorization", 47 | "value": "Basic {{authHeader}}" 48 | } 49 | ], 50 | "body": { 51 | "mode": "raw", 52 | "raw": "" 53 | }, 54 | "url": { 55 | "raw": "{{HOST}}/auth/jwt/token", 56 | "host": [ 57 | "{{HOST}}" 58 | ], 59 | "path": [ 60 | "auth", 61 | "jwt", 62 | "token" 63 | ] 64 | } 65 | }, 66 | "response": [] 67 | }, 68 | { 69 | "name": "Get Current User", 70 | "event": [ 71 | { 72 | "listen": "test", 73 | "script": { 74 | "id": "6d953560-1388-416e-8a7b-6445e9e8b1a8", 75 | "exec": [ 76 | "const res = pm.response.json();", 77 | "", 78 | "pm.globals.set(\"adminJWT\", res.data.jwt);", 79 | "" 80 | ], 81 | "type": "text/javascript" 82 | } 83 | } 84 | ], 85 | "request": { 86 | "method": "GET", 87 | "header": [ 88 | { 89 | "key": "Content-Type", 90 | "value": "application/json" 91 | }, 92 | { 93 | "key": "Authorization", 94 | "value": "Bearer {{adminJWT}}" 95 | } 96 | ], 97 | "body": { 98 | "mode": "raw", 99 | "raw": "" 100 | }, 101 | "url": { 102 | "raw": "{{HOST}}/auth/me", 103 | "host": [ 104 | "{{HOST}}" 105 | ], 106 | "path": [ 107 | "auth", 108 | "me" 109 | ] 110 | } 111 | }, 112 | "response": [] 113 | } 114 | ] 115 | }, 116 | { 117 | "name": "Users", 118 | "item": [ 119 | { 120 | "name": "Get All Users", 121 | "event": [ 122 | { 123 | "listen": "test", 124 | "script": { 125 | "id": "36d37aa3-b575-48c3-9e32-f762600cdbba", 126 | "exec": [ 127 | "const response = pm.response.json();", 128 | "", 129 | "pm.environment.set(\"userUuid\", response.data[0].userUuid);", 130 | "" 131 | ], 132 | "type": "text/javascript" 133 | } 134 | } 135 | ], 136 | "request": { 137 | "method": "GET", 138 | "header": [ 139 | { 140 | "key": "Authorization", 141 | "value": "Bearer {{adminJWT}}" 142 | } 143 | ], 144 | "body": { 145 | "mode": "raw", 146 | "raw": "" 147 | }, 148 | "url": { 149 | "raw": "{{HOST}}/users", 150 | "host": [ 151 | "{{HOST}}" 152 | ], 153 | "path": [ 154 | "users" 155 | ] 156 | } 157 | }, 158 | "response": [] 159 | }, 160 | { 161 | "name": "Create a user", 162 | "event": [ 163 | { 164 | "listen": "test", 165 | "script": { 166 | "id": "6eec5df1-fd09-4424-b691-3971490462d5", 167 | "exec": [ 168 | "const response = pm.response.json();", 169 | "", 170 | "pm.environment.set(\"userUuid\", response.data.id);", 171 | "" 172 | ], 173 | "type": "text/javascript" 174 | } 175 | }, 176 | { 177 | "listen": "prerequest", 178 | "script": { 179 | "id": "222749dc-e2b6-4b62-bea8-281d12ad5960", 180 | "exec": [ 181 | "var ranstr = (len) => {", 182 | " const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"; let str = '';", 183 | " for (let i = 0; i < len; ++i) { str += chars.charAt(Math.floor(Math.random() * chars.length)); }", 184 | " return str;", 185 | "}", 186 | "", 187 | "pm.globals.set(\"randomString\", ranstr(10));" 188 | ], 189 | "type": "text/javascript" 190 | } 191 | } 192 | ], 193 | "request": { 194 | "method": "POST", 195 | "header": [ 196 | { 197 | "key": "Content-Type", 198 | "value": "application/json" 199 | }, 200 | { 201 | "key": "Authorization", 202 | "value": "Bearer {{adminJWT}}" 203 | } 204 | ], 205 | "body": { 206 | "mode": "raw", 207 | "raw": "{\n \"name\": \"Test User\",\n \"email\": \"{{randomString}}@test.com\",\n \"password\": \"password\"\n}" 208 | }, 209 | "url": { 210 | "raw": "{{HOST}}/users", 211 | "host": [ 212 | "{{HOST}}" 213 | ], 214 | "path": [ 215 | "users" 216 | ] 217 | } 218 | }, 219 | "response": [] 220 | }, 221 | { 222 | "name": "Get A User", 223 | "request": { 224 | "method": "GET", 225 | "header": [ 226 | { 227 | "key": "Authorization", 228 | "value": "Bearer {{adminJWT}}" 229 | } 230 | ], 231 | "body": { 232 | "mode": "raw", 233 | "raw": "" 234 | }, 235 | "url": { 236 | "raw": "{{HOST}}/users/{{userUuid}}", 237 | "host": [ 238 | "{{HOST}}" 239 | ], 240 | "path": [ 241 | "users", 242 | "{{userUuid}}" 243 | ] 244 | } 245 | }, 246 | "response": [] 247 | }, 248 | { 249 | "name": "Update A User", 250 | "request": { 251 | "method": "PATCH", 252 | "header": [ 253 | { 254 | "key": "Content-Type", 255 | "value": "application/json" 256 | }, 257 | { 258 | "key": "Authorization", 259 | "value": "Bearer {{adminJWT}}" 260 | } 261 | ], 262 | "body": { 263 | "mode": "raw", 264 | "raw": "{\n \"name\": \"Updated user name\"\n}" 265 | }, 266 | "url": { 267 | "raw": "{{HOST}}/users/{{userUuid}}", 268 | "host": [ 269 | "{{HOST}}" 270 | ], 271 | "path": [ 272 | "users", 273 | "{{userUuid}}" 274 | ] 275 | } 276 | }, 277 | "response": [] 278 | }, 279 | { 280 | "name": "Delete User", 281 | "request": { 282 | "method": "DELETE", 283 | "header": [ 284 | { 285 | "key": "Authorization", 286 | "value": "Bearer {{adminJWT}}" 287 | }, 288 | { 289 | "key": "Content-Type", 290 | "name": "Content-Type", 291 | "value": "application/json", 292 | "type": "text" 293 | } 294 | ], 295 | "body": { 296 | "mode": "raw", 297 | "raw": "" 298 | }, 299 | "url": { 300 | "raw": "{{HOST}}/users/{{userUuid}}", 301 | "host": [ 302 | "{{HOST}}" 303 | ], 304 | "path": [ 305 | "users", 306 | "{{userUuid}}" 307 | ] 308 | } 309 | }, 310 | "response": [] 311 | } 312 | ] 313 | } 314 | ] 315 | } -------------------------------------------------------------------------------- /docs/postman/environment.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2f15b865-6e39-440a-ab63-b53417bd1bb2", 3 | "name": "API Boilerplate", 4 | "values": [ 5 | { 6 | "key": "HOST", 7 | "value": "http://local.api.l5api", 8 | "enabled": true 9 | }, 10 | { 11 | "key": "adminEmail", 12 | "value": "admin@admin.com", 13 | "description": "", 14 | "enabled": true 15 | }, 16 | { 17 | "key": "adminPassword", 18 | "value": "password", 19 | "description": "", 20 | "enabled": true 21 | } 22 | ], 23 | "_postman_variable_scope": "environment", 24 | "_postman_exported_at": "2019-03-21T13:58:28.136Z", 25 | "_postman_exported_using": "Postman/7.0.6" 26 | } -------------------------------------------------------------------------------- /env/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | composer install 4 | composer dump-autoload --optimize 5 | php artisan ide-helper:generate 6 | php artisan ide-helper:meta 7 | -------------------------------------------------------------------------------- /env/docker/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /logs 3 | /data 4 | .env 5 | /.project 6 | .docker-sync 7 | /jenkins/jenkins_home 8 | -------------------------------------------------------------------------------- /env/docker/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:alpine 2 | 3 | COPY nginx.conf /etc/nginx/ 4 | COPY sites/laravel.conf /etc/nginx/conf.d/ 5 | COPY upstream.conf /etc/nginx/conf.d/ 6 | RUN rm -f /etc/nginx/conf.d/default.conf 7 | 8 | RUN set -x ; \ 9 | addgroup -g 82 -S www-data ; \ 10 | adduser -u 1000 -D -S -G www-data www-data && exit 0 ; exit 1 11 | 12 | EXPOSE 80 443 -------------------------------------------------------------------------------- /env/docker/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | user www-data; 2 | worker_processes 4; 3 | pid /run/nginx.pid; 4 | # daemon off; 5 | 6 | events { 7 | worker_connections 2048; 8 | multi_accept on; 9 | use epoll; 10 | } 11 | 12 | http { 13 | server_tokens off; 14 | sendfile on; 15 | tcp_nopush on; 16 | tcp_nodelay on; 17 | keepalive_timeout 15; 18 | types_hash_max_size 2048; 19 | client_max_body_size 20M; 20 | include /etc/nginx/mime.types; 21 | default_type application/octet-stream; 22 | access_log /dev/stdout; 23 | error_log /dev/stderr; 24 | gzip on; 25 | gzip_disable "msie6"; 26 | 27 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 28 | ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; 29 | 30 | include /etc/nginx/conf.d/*.conf; 31 | include /etc/nginx/sites-available/*.conf; 32 | open_file_cache off; # Disabled for issue 619 33 | charset UTF-8; 34 | } 35 | -------------------------------------------------------------------------------- /env/docker/nginx/sites/laravel.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 80; 4 | listen [::]:80; 5 | 6 | server_name localhost; 7 | root /var/www/public; 8 | index index.php index.html index.htm; 9 | 10 | location / { 11 | try_files $uri $uri/ /index.php$is_args$args; 12 | } 13 | 14 | location ~ \.php$ { 15 | try_files $uri /index.php =404; 16 | fastcgi_pass php-upstream; 17 | fastcgi_index index.php; 18 | fastcgi_buffers 16 16k; 19 | fastcgi_buffer_size 32k; 20 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 21 | #fixes timeouts 22 | fastcgi_read_timeout 600; 23 | include fastcgi_params; 24 | } 25 | 26 | location ~ /\.ht { 27 | deny all; 28 | } 29 | 30 | location /.well-known/acme-challenge/ { 31 | root /var/www/letsencrypt/; 32 | log_not_found off; 33 | } 34 | 35 | error_log /var/log/nginx/laravel_error.log; 36 | access_log /var/log/nginx/laravel_access.log; 37 | } 38 | -------------------------------------------------------------------------------- /env/docker/nginx/upstream.conf: -------------------------------------------------------------------------------- 1 | upstream php-upstream { 2 | server php-fpm:9000; 3 | } -------------------------------------------------------------------------------- /env/docker/php-fpm/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG PHP_VERSION=${PHP_VERSION} 2 | 3 | FROM php:${PHP_VERSION}-fpm 4 | 5 | # Install packages for required extensions 6 | RUN apt-get update \ 7 | && apt-get install -y --no-install-recommends \ 8 | libzip-dev \ 9 | libz-dev \ 10 | libpq-dev \ 11 | libssl-dev \ 12 | libmcrypt-dev \ 13 | libicu-dev \ 14 | libxml2-dev \ 15 | curl \ 16 | iputils-ping \ 17 | vim \ 18 | libonig-dev \ 19 | && rm -rf /var/lib/apt/lists/* 20 | 21 | # Install Laravel required extensions 22 | RUN docker-php-ext-install \ 23 | mbstring \ 24 | pdo_pgsql \ 25 | opcache \ 26 | zip \ 27 | bcmath \ 28 | sockets \ 29 | intl \ 30 | pcntl 31 | 32 | # Install required PECL extensions 33 | RUN pecl install \ 34 | redis 35 | 36 | # Enable above 37 | RUN docker-php-ext-enable \ 38 | redis 39 | 40 | ########################################################################### 41 | # xDebug: 42 | ########################################################################### 43 | 44 | ARG PHP_XDEBUG_ENABLE=false 45 | ARG PHP_XDEBUG_VERSION= 46 | RUN if [ ${PHP_XDEBUG_ENABLE} = true ]; then \ 47 | # Install the xdebug extension 48 | # when php is 7.3, xdebug version has to be xdebug-2.7.0 49 | pecl install "xdebug${PHP_XDEBUG_VERSION}" && \ 50 | docker-php-ext-enable xdebug \ 51 | ;fi 52 | 53 | # Copy xdebug configuration for remote debugging 54 | COPY ./xdebug.ini /usr/local/etc/php/conf.d/ 55 | 56 | ARG PHP_XDEBUG_REMOTE_CONNECT_BACK=false 57 | RUN if [ ${PHP_XDEBUG_REMOTE_CONNECT_BACK} = true ]; then \ 58 | echo "xdebug.remote_connect_back=1" >> /usr/local/etc/php/conf.d/xdebug.ini \ 59 | ;fi 60 | 61 | ########################################################################### 62 | # Check PHP version: 63 | ########################################################################### 64 | 65 | ARG PHP_VERSION=${PHP_VERSION} 66 | 67 | RUN php -v | head -n 1 | grep -q "PHP ${PHP_VERSION}." 68 | 69 | ########################################################################### 70 | # Copy PHP configuration files 71 | ########################################################################### 72 | 73 | COPY ./php.ini /usr/local/etc/php/ 74 | COPY ./opcache.ini /usr/local/etc/php/conf.d/ 75 | COPY ./laravel.ini /usr/local/etc/php/conf.d/ 76 | COPY ./xlaravel.pool.conf /usr/local/etc/php-fpm.d/ 77 | 78 | USER root 79 | 80 | ########################################################################### 81 | # Clean up 82 | ########################################################################### 83 | 84 | RUN apt-get clean && \ 85 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ 86 | rm /var/log/lastlog /var/log/faillog 87 | 88 | RUN usermod -u 1000 www-data 89 | 90 | WORKDIR /var/www 91 | -------------------------------------------------------------------------------- /env/docker/php-fpm/laravel.ini: -------------------------------------------------------------------------------- 1 | date.timezone=UTC 2 | display_errors=Off 3 | log_errors=On 4 | 5 | ; Maximum amount of memory a script may consume (128MB) 6 | ; http://php.net/memory-limit 7 | memory_limit = 256M 8 | ; Maximum allowed size for uploaded files. 9 | ; http://php.net/upload-max-filesize 10 | upload_max_filesize = 20M 11 | ; Sets max size of post data allowed. 12 | ; http://php.net/post-max-size 13 | post_max_size = 20M 14 | max_execution_time=600 15 | default_socket_timeout=3600 16 | request_terminate_timeout=600 17 | -------------------------------------------------------------------------------- /env/docker/php-fpm/opcache.ini: -------------------------------------------------------------------------------- 1 | ; NOTE: The actual opcache.so extention is NOT SET HERE but rather (/usr/local/etc/php/conf.d/docker-php-ext-opcache.ini) 2 | 3 | opcache.enable="1" 4 | opcache.memory_consumption="128" 5 | opcache.use_cwd="0" 6 | opcache.max_file_size="0" 7 | opcache.max_accelerated_files = 30000 8 | opcache.validate_timestamps="1" 9 | opcache.revalidate_freq="0" 10 | -------------------------------------------------------------------------------- /env/docker/php-fpm/xdebug.ini: -------------------------------------------------------------------------------- 1 | ; NOTE: The actual debug.so extention is NOT SET HERE but rather (/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini) 2 | 3 | xdebug.remote_host=host.docker.internal 4 | ; xdebug.remote_connect_back=1 5 | xdebug.remote_port=9000 6 | xdebug.idekey=PHPSTORM 7 | 8 | xdebug.remote_autostart=0 9 | xdebug.remote_enable=1 10 | xdebug.cli_color=0 11 | xdebug.profiler_enable=0 12 | xdebug.profiler_output_dir="~/xdebug/phpstorm/tmp/profiling" 13 | 14 | xdebug.remote_handler=dbgp 15 | xdebug.remote_mode=req 16 | xdebug.remote_log="/var/www/storage/logs/xdebug.log" 17 | 18 | xdebug.var_display_max_children=-1 19 | xdebug.var_display_max_data=-1 20 | xdebug.var_display_max_depth=-1 21 | -------------------------------------------------------------------------------- /env/docker/php-fpm/xlaravel.pool.conf: -------------------------------------------------------------------------------- 1 | ; Unix user/group of processes 2 | ; Note: The user is mandatory. If the group is not set, the default user's group 3 | ; will be used. 4 | user = www-data 5 | group = www-data 6 | 7 | ; The address on which to accept FastCGI requests. 8 | ; Valid syntaxes are: 9 | ; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific address on 10 | ; a specific port; 11 | ; 'port' - to listen on a TCP socket to all addresses on a 12 | ; specific port; 13 | ; '/path/to/unix/socket' - to listen on a unix socket. 14 | ; Note: This value is mandatory. 15 | listen = 0.0.0.0:9000 16 | 17 | ; Choose how the process manager will control the number of child processes. 18 | ; Possible Values: 19 | ; static - a fixed number (pm.max_children) of child processes; 20 | ; dynamic - the number of child processes are set dynamically based on the 21 | ; following directives. With this process management, there will be 22 | ; always at least 1 children. 23 | ; pm.max_children - the maximum number of children that can 24 | ; be alive at the same time. 25 | ; pm.start_servers - the number of children created on startup. 26 | ; pm.min_spare_servers - the minimum number of children in 'idle' 27 | ; state (waiting to process). If the number 28 | ; of 'idle' processes is less than this 29 | ; number then some children will be created. 30 | ; pm.max_spare_servers - the maximum number of children in 'idle' 31 | ; state (waiting to process). If the number 32 | ; of 'idle' processes is greater than this 33 | ; number then some children will be killed. 34 | ; ondemand - no children are created at startup. Children will be forked when 35 | ; new requests will connect. The following parameter are used: 36 | ; pm.max_children - the maximum number of children that 37 | ; can be alive at the same time. 38 | ; pm.process_idle_timeout - The number of seconds after which 39 | ; an idle process will be killed. 40 | ; Note: This value is mandatory. 41 | pm = dynamic 42 | 43 | ; The number of child processes to be created when pm is set to 'static' and the 44 | ; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. 45 | ; This value sets the limit on the number of simultaneous requests that will be 46 | ; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. 47 | ; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP 48 | ; CGI. The below defaults are based on a server without much resources. Don't 49 | ; forget to tweak pm.* to fit your needs. 50 | ; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' 51 | ; Note: This value is mandatory. 52 | pm.max_children = 20 53 | 54 | ; The number of child processes created on startup. 55 | ; Note: Used only when pm is set to 'dynamic' 56 | ; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 57 | pm.start_servers = 2 58 | 59 | ; The desired minimum number of idle server processes. 60 | ; Note: Used only when pm is set to 'dynamic' 61 | ; Note: Mandatory when pm is set to 'dynamic' 62 | pm.min_spare_servers = 1 63 | 64 | ; The desired maximum number of idle server processes. 65 | ; Note: Used only when pm is set to 'dynamic' 66 | ; Note: Mandatory when pm is set to 'dynamic' 67 | pm.max_spare_servers = 3 68 | 69 | ;--------------------- 70 | 71 | ; Make specific Docker environment variables available to PHP 72 | env[DB_1_ENV_MYSQL_DATABASE] = $DB_1_ENV_MYSQL_DATABASE 73 | env[DB_1_ENV_MYSQL_USER] = $DB_1_ENV_MYSQL_USER 74 | env[DB_1_ENV_MYSQL_PASSWORD] = $DB_1_ENV_MYSQL_PASSWORD 75 | 76 | catch_workers_output = yes 77 | -------------------------------------------------------------------------------- /env/docker/postgres/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:alpine 2 | 3 | COPY ./create_test_db.sh /docker-entrypoint-initdb.d/10-create_test_db.sh -------------------------------------------------------------------------------- /env/docker/postgres/create_test_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | psql --username ${POSTGRES_USER} ${POSTGRES_DB} -c "CREATE DATABASE ${POSTGRES_DB}_test;" 3 | -------------------------------------------------------------------------------- /env/docker/workspace/.zshrc: -------------------------------------------------------------------------------- 1 | # If you come from bash you might have to change your $PATH. 2 | # export PATH=$HOME/bin:/usr/local/bin:$PATH 3 | 4 | # Path to your oh-my-zsh installation. 5 | export ZSH=/home/laradock/.oh-my-zsh 6 | 7 | # Set name of the theme to load. Optionally, if you set this to "random" 8 | # it'll load a random theme each time that oh-my-zsh is loaded. 9 | # See https://github.com/robbyrussell/oh-my-zsh/wiki/Themes 10 | ZSH_THEME="robbyrussell" 11 | 12 | # Set list of themes to load 13 | # Setting this variable when ZSH_THEME=random 14 | # cause zsh load theme from this variable instead of 15 | # looking in ~/.oh-my-zsh/themes/ 16 | # An empty array have no effect 17 | # ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" ) 18 | 19 | # Uncomment the following line to use case-sensitive completion. 20 | # CASE_SENSITIVE="true" 21 | 22 | # Uncomment the following line to use hyphen-insensitive completion. Case 23 | # sensitive completion must be off. _ and - will be interchangeable. 24 | # HYPHEN_INSENSITIVE="true" 25 | 26 | # Uncomment the following line to disable bi-weekly auto-update checks. 27 | # DISABLE_AUTO_UPDATE="true" 28 | 29 | # Uncomment the following line to change how often to auto-update (in days). 30 | # export UPDATE_ZSH_DAYS=13 31 | 32 | # Uncomment the following line to disable colors in ls. 33 | # DISABLE_LS_COLORS="true" 34 | 35 | # Uncomment the following line to disable auto-setting terminal title. 36 | # DISABLE_AUTO_TITLE="true" 37 | 38 | # Uncomment the following line to enable command auto-correction. 39 | # ENABLE_CORRECTION="true" 40 | 41 | # Uncomment the following line to display red dots whilst waiting for completion. 42 | # COMPLETION_WAITING_DOTS="true" 43 | 44 | # Uncomment the following line if you want to disable marking untracked files 45 | # under VCS as dirty. This makes repository status check for large repositories 46 | # much, much faster. 47 | # DISABLE_UNTRACKED_FILES_DIRTY="true" 48 | 49 | # Uncomment the following line if you want to change the command execution time 50 | # stamp shown in the history command output. 51 | # The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" 52 | # HIST_STAMPS="mm/dd/yyyy" 53 | 54 | # Would you like to use another custom folder than $ZSH/custom? 55 | # ZSH_CUSTOM=/path/to/new-custom-folder 56 | 57 | # Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*) 58 | # Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ 59 | # Example format: plugins=(rails git textmate ruby lighthouse) 60 | # Add wisely, as too many plugins slow down shell startup. 61 | plugins=( 62 | git, 63 | man, 64 | dotenv 65 | ) 66 | 67 | source $ZSH/oh-my-zsh.sh 68 | 69 | # User configuration 70 | 71 | # export MANPATH="/usr/local/man:$MANPATH" 72 | 73 | # You may need to manually set your language environment 74 | # export LANG=en_US.UTF-8 75 | 76 | # Preferred editor for local and remote sessions 77 | # if [[ -n $SSH_CONNECTION ]]; then 78 | # export EDITOR='vim' 79 | # else 80 | # export EDITOR='mvim' 81 | # fi 82 | 83 | # Compilation flags 84 | # export ARCHFLAGS="-arch x86_64" 85 | 86 | # ssh 87 | # export SSH_KEY_PATH="~/.ssh/rsa_id" 88 | 89 | # Set personal aliases, overriding those provided by oh-my-zsh libs, 90 | # plugins, and themes. Aliases can be placed here, though oh-my-zsh 91 | # users are encouraged to define aliases within the ZSH_CUSTOM folder. 92 | # For a full list of active aliases, run `alias`. 93 | # 94 | # Example aliases 95 | # alias zshconfig="mate ~/.zshrc" 96 | # alias ohmyzsh="mate ~/.oh-my-zsh" 97 | -------------------------------------------------------------------------------- /env/docker/workspace/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG PHP_VERSION=${PHP_VERSION} 2 | 3 | FROM php:${PHP_VERSION}-cli 4 | 5 | # Install packages for required extensions 6 | RUN apt-get update \ 7 | && apt-get install -y --no-install-recommends \ 8 | libz-dev \ 9 | libpq-dev \ 10 | libssl-dev \ 11 | libmcrypt-dev \ 12 | libicu-dev \ 13 | libxml2-dev \ 14 | curl \ 15 | git \ 16 | zip \ 17 | unzip \ 18 | libzip-dev \ 19 | vim \ 20 | wget \ 21 | zsh \ 22 | gpg \ 23 | lsb-release \ 24 | ssh-client \ 25 | iputils-ping \ 26 | libonig-dev \ 27 | libpng-dev \ 28 | && rm -rf /var/lib/apt/lists/* 29 | 30 | # Install Laravel required extensions 31 | RUN docker-php-ext-install \ 32 | mbstring \ 33 | pdo_pgsql \ 34 | opcache \ 35 | zip \ 36 | bcmath \ 37 | sockets \ 38 | intl \ 39 | pcntl 40 | 41 | # Install required PECL extensions 42 | RUN pecl install \ 43 | redis 44 | 45 | # Enable above 46 | RUN docker-php-ext-enable \ 47 | redis 48 | 49 | ########################################################################### 50 | # Laradock non-root user: 51 | ########################################################################### 52 | 53 | # Start as root 54 | USER root 55 | 56 | # Add a non-root user to prevent files being created with root permissions on host machine. 57 | ARG PUID=1000 58 | ENV PUID ${PUID} 59 | ARG PGID=1000 60 | ENV PGID ${PGID} 61 | 62 | RUN groupadd -g ${PGID} laradock && \ 63 | useradd -u ${PUID} -g laradock -m laradock && \ 64 | usermod -p "*" laradock 65 | 66 | ########################################################################### 67 | # Set Timezone 68 | ########################################################################### 69 | 70 | ARG TZ=UTC 71 | ENV TZ ${TZ} 72 | 73 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 74 | 75 | ########################################################################### 76 | # User Aliases 77 | ########################################################################### 78 | 79 | USER root 80 | 81 | COPY ./aliases.sh /root/aliases.sh 82 | COPY ./aliases.sh /home/laradock/aliases.sh 83 | 84 | RUN sed -i 's/\r//' /root/aliases.sh && \ 85 | sed -i 's/\r//' /home/laradock/aliases.sh && \ 86 | chown laradock:laradock /home/laradock/aliases.sh && \ 87 | echo "" >> ~/.bashrc && \ 88 | echo "# Load Custom Aliases" >> ~/.bashrc && \ 89 | echo "source ~/aliases.sh" >> ~/.bashrc && \ 90 | echo "" >> ~/.bashrc 91 | 92 | USER laradock 93 | 94 | RUN echo "" >> ~/.bashrc && \ 95 | echo "# Load Custom Aliases" >> ~/.bashrc && \ 96 | echo "source ~/aliases.sh" >> ~/.bashrc && \ 97 | echo "" >> ~/.bashrc 98 | 99 | ########################################################################### 100 | # Composer: 101 | ########################################################################### 102 | 103 | USER root 104 | 105 | ARG COMPOSER_PROCESS_TIMEOUT=300 106 | ENV COMPOSER_PROCESS_TIMEOUT ${COMPOSER_PROCESS_TIMEOUT} 107 | 108 | # Install composer and add its bin to the PATH. 109 | RUN curl -s http://getcomposer.org/installer | php && \ 110 | echo "export PATH=${PATH}:/var/www/vendor/bin" >> ~/.bashrc && \ 111 | mv composer.phar /usr/local/bin/composer 112 | 113 | USER laradock 114 | 115 | # Export composer vendor path 116 | RUN echo "" >> ~/.bashrc && \ 117 | echo 'export PATH="~/.composer/vendor/bin:$PATH"' >> ~/.bashrc 118 | 119 | ########################################################################### 120 | # Non-root user : PHPUnit path 121 | ########################################################################### 122 | 123 | # add ./vendor/bin to non-root user's bashrc (needed for phpunit) 124 | USER laradock 125 | RUN echo "" >> ~/.bashrc && \ 126 | echo 'export PATH="/var/www/vendor/bin:$PATH"' >> ~/.bashrc 127 | 128 | ########################################################################### 129 | # Crontab 130 | ########################################################################### 131 | 132 | USER root 133 | COPY ./crontab /etc/cron.d 134 | RUN chmod -R 644 /etc/cron.d 135 | 136 | ##################################### 137 | # Oh My ZSH 138 | ##################################### 139 | 140 | USER root 141 | RUN wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | zsh || true \ 142 | && chsh -s $(which zsh) $(whoami) \ 143 | && chsh -s $(which zsh) laradock 144 | COPY ./.zshrc /home/laradock/zshrc 145 | 146 | USER laradock 147 | RUN wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | zsh || true \ 148 | mv ~/zshrc ~/.zshrc 149 | 150 | ########################################################################### 151 | # xDebug: 152 | ########################################################################### 153 | 154 | USER root 155 | ARG PHP_XDEBUG_ENABLE=false 156 | ARG PHP_XDEBUG_VERSION= 157 | RUN if [ ${PHP_XDEBUG_ENABLE} = true ]; then \ 158 | # Install the xdebug extension 159 | # when php is 7.3, xdebug version has to be xdebug-2.7.0 160 | pecl install xdebug${PHP_XDEBUG_VERSION} && \ 161 | docker-php-ext-enable xdebug \ 162 | ;fi 163 | 164 | # Copy xdebug configuration for remote debugging 165 | COPY ./xdebug.ini /usr/local/etc/php/conf.d/ 166 | 167 | ARG PHP_XDEBUG_REMOTE_CONNECT_BACK=false 168 | RUN if [ ${PHP_XDEBUG_REMOTE_CONNECT_BACK} = true ]; then \ 169 | echo "xdebug.remote_connect_back=1" >> /usr/local/etc/php/conf.d/xdebug.ini \ 170 | ;fi 171 | 172 | 173 | ########################################################################### 174 | # Check PHP version: 175 | ########################################################################### 176 | 177 | ARG PHP_VERSION=${PHP_VERSION} 178 | RUN php -v | head -n 1 | grep -q "PHP ${PHP_VERSION}." 179 | 180 | # 181 | #-------------------------------------------------------------------------- 182 | # Final Touch 183 | #-------------------------------------------------------------------------- 184 | # 185 | 186 | USER root 187 | 188 | RUN mkdir /home/laradock/.config && chown laradock:laradock /home/laradock/.config 189 | 190 | # Clean up 191 | RUN apt-get clean && \ 192 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ 193 | rm /var/log/lastlog /var/log/faillog 194 | 195 | # Set default work directory 196 | WORKDIR /var/www 197 | -------------------------------------------------------------------------------- /env/docker/workspace/aliases.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Colors used for status updates 4 | ESC_SEQ="\x1b[" 5 | COL_RESET=$ESC_SEQ"39;49;00m" 6 | COL_RED=$ESC_SEQ"31;01m" 7 | COL_GREEN=$ESC_SEQ"32;01m" 8 | COL_YELLOW=$ESC_SEQ"33;01m" 9 | COL_BLUE=$ESC_SEQ"34;01m" 10 | COL_MAGENTA=$ESC_SEQ"35;01m" 11 | COL_CYAN=$ESC_SEQ"36;01m" 12 | 13 | # Detect which `ls` flavor is in use 14 | if ls --color > /dev/null 2>&1; then # GNU `ls` 15 | colorflag="--color" 16 | export LS_COLORS='no=00:fi=00:di=01;31:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.ogg=01;35:*.mp3=01;35:*.wav=01;35:' 17 | else # macOS `ls` 18 | colorflag="-G" 19 | export LSCOLORS='BxBxhxDxfxhxhxhxhxcxcx' 20 | fi 21 | 22 | # List all files colorized in long format 23 | #alias l="ls -lF ${colorflag}" 24 | ### MEGA: I want l and la ti return hisdden files 25 | alias l="ls -laF ${colorflag}" 26 | 27 | # List all files colorized in long format, including dot files 28 | alias la="ls -laF ${colorflag}" 29 | 30 | # List only directories 31 | alias lsd="ls -lF ${colorflag} | grep --color=never '^d'" 32 | 33 | # Always use color output for `ls` 34 | alias ls="command ls ${colorflag}" 35 | 36 | # Commonly Used Aliases 37 | alias ..="cd .." 38 | alias ...="cd ../.." 39 | alias ....="cd ../../.." 40 | alias .....="cd ../../../.." 41 | alias ~="cd ~" # `cd` is probably faster to type though 42 | alias -- -="cd -" 43 | alias home="cd ~" 44 | 45 | alias h="history" 46 | alias j="jobs" 47 | alias e='exit' 48 | alias c="clear" 49 | alias cla="clear && ls -l" 50 | alias cll="clear && ls -la" 51 | alias cls="clear && ls" 52 | alias code="cd /var/www" 53 | alias ea="vi ~/aliases" 54 | 55 | # Always enable colored `grep` output 56 | # Note: `GREP_OPTIONS="--color=auto"` is deprecated, hence the alias usage. 57 | alias grep='grep --color=auto' 58 | alias fgrep='fgrep --color=auto' 59 | alias egrep='egrep --color=auto' 60 | 61 | alias art="php artisan" 62 | alias artisan="php artisan" 63 | alias cdump="composer dump-autoload -o" 64 | alias composer:dump="composer dump-autoload -o" 65 | alias db:reset="php artisan migrate:reset && php artisan migrate --seed" 66 | alias dusk="php artisan dusk" 67 | alias fresh="php artisan migrate:fresh" 68 | alias migrate="php artisan migrate" 69 | alias refresh="php artisan migrate:refresh" 70 | alias rollback="php artisan migrate:rollback" 71 | alias seed="php artisan:seed" 72 | alias serve="php artisan serve --quiet &" 73 | 74 | alias phpunit="./vendor/bin/phpunit" 75 | alias pu="phpunit" 76 | alias puf="phpunit --filter" 77 | alias pud='phpunit --debug' 78 | 79 | alias cc='codecept' 80 | alias ccb='codecept build' 81 | alias ccr='codecept run' 82 | alias ccu='codecept run unit' 83 | alias ccf='codecept run functional' 84 | 85 | alias g="gulp" 86 | alias npm-global="npm list -g --depth 0" 87 | alias ra="reload" 88 | alias reload="source ~/.aliases && echo \"$COL_GREEN ==> Aliases Reloaded... $COL_RESET \n \"" 89 | alias run="npm run" 90 | alias tree="xtree" 91 | 92 | # Xvfb 93 | alias xvfb="Xvfb -ac :0 -screen 0 1024x768x16 &" 94 | 95 | # requires installation of 'https://www.npmjs.com/package/npms-cli' 96 | alias npms="npms search" 97 | # requires installation of 'https://www.npmjs.com/package/package-menu-cli' 98 | alias pm="package-menu" 99 | # requires installation of 'https://www.npmjs.com/package/pkg-version-cli' 100 | alias pv="package-version" 101 | # requires installation of 'https://github.com/sindresorhus/latest-version-cli' 102 | alias lv="latest-version" 103 | 104 | # git aliases 105 | alias gaa="git add ." 106 | alias gd="git --no-pager diff" 107 | alias git-revert="git reset --hard && git clean -df" 108 | alias gs="git status" 109 | alias whoops="git reset --hard && git clean -df" 110 | 111 | # Create a new directory and enter it 112 | function mkd() { 113 | mkdir -p "$@" && cd "$@" 114 | } 115 | 116 | function md() { 117 | mkdir -p "$@" && cd "$@" 118 | } 119 | 120 | function xtree { 121 | find ${1:-.} -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g' 122 | } 123 | 124 | # `tre` is a shorthand for `tree` with hidden files and color enabled, ignoring 125 | # the `.git` directory, listing directories first. The output gets piped into 126 | # `less` with options to preserve color and line numbers, unless the output is 127 | # small enough for one screen. 128 | function tre() { 129 | tree -aC -I '.git|node_modules|bower_components' --dirsfirst "$@" | less -FRNX; 130 | } 131 | 132 | # Determine size of a file or total size of a directory 133 | function fs() { 134 | if du -b /dev/null > /dev/null 2>&1; then 135 | local arg=-sbh; 136 | else 137 | local arg=-sh; 138 | fi 139 | if [[ -n "$@" ]]; then 140 | du $arg -- "$@"; 141 | else 142 | du $arg .[^.]* ./*; 143 | fi; 144 | } 145 | -------------------------------------------------------------------------------- /env/docker/workspace/crontab/laradock: -------------------------------------------------------------------------------- 1 | * * * * * laradock php /var/www/artisan schedule:run >> /dev/null 2>&1 2 | -------------------------------------------------------------------------------- /env/docker/workspace/xdebug.ini: -------------------------------------------------------------------------------- 1 | ; NOTE: The actual debug.so extention is NOT SET HERE but rather (/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini) 2 | 3 | xdebug.remote_host=host.docker.internal 4 | ; xdebug.remote_connect_back=1 5 | xdebug.remote_port=9000 6 | xdebug.idekey=PHPSTORM 7 | 8 | xdebug.remote_autostart=0 9 | xdebug.remote_enable=1 10 | xdebug.cli_color=0 11 | xdebug.profiler_enable=0 12 | xdebug.profiler_output_dir="~/xdebug/phpstorm/tmp/profiling" 13 | 14 | xdebug.remote_handler=dbgp 15 | xdebug.remote_mode=req 16 | xdebug.remote_log="/var/www/storage/logs/xdebug.log" 17 | 18 | xdebug.var_display_max_children=-1 19 | xdebug.var_display_max_data=-1 20 | xdebug.var_display_max_depth=-1 21 | -------------------------------------------------------------------------------- /env/workspace.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-compose exec --user laradock workspace zsh 4 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | This is the PHP coding standard used for the Laravel API boilerplate 7 | 8 | 9 | app 10 | config 11 | resources/views 12 | 13 | 14 | */storage/* 15 | */cache/* 16 | */*.js 17 | */*.css 18 | */*.xml 19 | */*.blade.php 20 | */autoload.php 21 | */vendor/* 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | warning 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | */routes/* 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/Unit 16 | 17 | 18 | 19 | ./tests/Api 20 | 21 | 22 | 27 | 28 | 29 | 30 | ./app 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /phpunit.xml.travis: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/Unit 16 | 17 | 18 | 19 | ./tests/Api 20 | 21 | 22 | 27 | 28 | 29 | 30 | ./app 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specialtactics/laravel-api-boilerplate/7e64c5697881b594adad2f2bf62048b50026cffa/public/favicon.ico -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | handleRequest(Request::capture()); 18 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /public/vendor/telescope/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specialtactics/laravel-api-boilerplate/7e64c5697881b594adad2f2bf62048b50026cffa/public/vendor/telescope/favicon.ico -------------------------------------------------------------------------------- /public/vendor/telescope/mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/app.js": "/app.js?id=cbaa84f183262df2778e", 3 | "/app.css": "/app.css?id=c097a04c12c993b0b389", 4 | "/app-dark.css": "/app-dark.css?id=1afefefbd103a662cdcf" 5 | } -------------------------------------------------------------------------------- /public/web.config: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![CI Tests](https://github.com/specialtactics/laravel-api-boilerplate/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/specialtactics/laravel-api-boilerplate/actions) 2 | [![License](https://img.shields.io/packagist/l/specialtactics/laravel-api-boilerplate.svg?style=flat-square)](LICENSE) 3 | [![Development Version](https://img.shields.io/packagist/vpre/specialtactics/laravel-api-boilerplate.svg?style=flat-square)](https://packagist.org/packages/specialtactics/laravel-api-boilerplate) 4 | 5 | 6 |

7 | 8 | ## About Laravel API Boilerplate 9 | This is a boilerplate for writing RESTful API projects using Laravel. The aim of this boilerplate is to provide developers with scaffolding and common functionality which will make writing APIs exceedingly quick, efficient and convenient. 10 | 11 | It is intended for this repository to be used when starting a new API project. Therefore, instead of cloning the laravel repository, you should clone this one. 12 | 13 | The principles of this boilerplate are to; 14 | 15 | - Save developers considerable effort by using reasonable conventions 16 | - Allow for everything the boilerplate provides to be easily extended and entirely customised to suit developer needs, through normal PHP inheritance 17 | - As well as allow developers to easily use the boilerplate functionality and mix it in with their own implementation 18 | - Follow REST standards very closely 19 | - Use existing Laravel features and existing Laravel add-on packages where possible 20 | - Add many convenient features useful for writing APIs 21 | - Maintain a high level of performance 22 | 23 | ## Documentation 24 | For setup, usage guidance, and all other docs - please consult the [Project Wiki](https://github.com/specialtactics/l5-api-boilerplate/wiki). 25 | 26 | ## Contributing 27 | 28 | If you would like to contribute to this project, please feel free to submit a pull request. If you plan to do any major work - it may be worthwhile messaging the author beforehand to explain your plans and get them approved. 29 | 30 | Please keep in mind, this package is only the template portion of the boilerplate, the main portion is [l5-api](https://github.com/specialtactics/l5-api). 31 | Before adding any new functionality, you should consider whether it's possible at all to keep it out of this project and rather put it into l5-api, as that is preferred. 32 | 33 | ## Check out the documentation of supporting projects 34 | 35 | Every great project stands on the shoulders of giants. Check out the documentation of these key supporting packages to learn more; 36 | 37 | - [Laravel](https://laravel.com/docs/) 38 | - [Dingo API](https://github.com/dingo/api/wiki) 39 | - [Tymon JWT Auth](https://github.com/tymondesigns/jwt-auth) 40 | - [League Fractal](https://fractal.thephpleague.com/) 41 | - [Laravel UUID](https://github.com/webpatser/laravel-uuid/tree/2.1.1) 42 | 43 | ## Recommended Packages 44 | 45 | I have tried to include only the packages thought absolutely necessary, so here is a list of packages I recommend checking out: 46 | 47 | #### General 48 | - [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 49 | - [PHP-VCR](https://github.com/php-vcr/php-vcr) 50 | 51 | #### For Debugging 52 | - [Bugsnag for Laravel](https://github.com/bugsnag/bugsnag-laravel) 53 | - [Sentry](https://github.com/getsentry/sentry-laravel) 54 | 55 | ## License 56 | 57 | This boilerplate, much like the Laravel framework is open-source software licensed under the [MIT license](https://opensource.org/licenses/MIT). 58 | -------------------------------------------------------------------------------- /resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'password' => 'The provided password is incorrect.', 18 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 19 | 20 | ]; 21 | -------------------------------------------------------------------------------- /resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Your password has been reset!', 17 | 'sent' => 'We have emailed your password reset link!', 18 | 'throttled' => 'Please wait before retrying.', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that email address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /resources/lang/en/validation.php: -------------------------------------------------------------------------------- 1 | 'The :attribute must be accepted.', 17 | 'active_url' => 'The :attribute is not a valid URL.', 18 | 'after' => 'The :attribute must be a date after :date.', 19 | 'after_or_equal' => 'The :attribute must be a date after or equal to :date.', 20 | 'alpha' => 'The :attribute must only contain letters.', 21 | 'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.', 22 | 'alpha_num' => 'The :attribute must only contain letters and numbers.', 23 | 'array' => 'The :attribute must be an array.', 24 | 'before' => 'The :attribute must be a date before :date.', 25 | 'before_or_equal' => 'The :attribute must be a date before or equal to :date.', 26 | 'between' => [ 27 | 'numeric' => 'The :attribute must be between :min and :max.', 28 | 'file' => 'The :attribute must be between :min and :max kilobytes.', 29 | 'string' => 'The :attribute must be between :min and :max characters.', 30 | 'array' => 'The :attribute must have between :min and :max items.', 31 | ], 32 | 'boolean' => 'The :attribute field must be true or false.', 33 | 'confirmed' => 'The :attribute confirmation does not match.', 34 | 'date' => 'The :attribute is not a valid date.', 35 | 'date_equals' => 'The :attribute must be a date equal to :date.', 36 | 'date_format' => 'The :attribute does not match the format :format.', 37 | 'different' => 'The :attribute and :other must be different.', 38 | 'digits' => 'The :attribute must be :digits digits.', 39 | 'digits_between' => 'The :attribute must be between :min and :max digits.', 40 | 'dimensions' => 'The :attribute has invalid image dimensions.', 41 | 'distinct' => 'The :attribute field has a duplicate value.', 42 | 'email' => 'The :attribute must be a valid email address.', 43 | 'ends_with' => 'The :attribute must end with one of the following: :values.', 44 | 'exists' => 'The selected :attribute is invalid.', 45 | 'file' => 'The :attribute must be a file.', 46 | 'filled' => 'The :attribute field must have a value.', 47 | 'gt' => [ 48 | 'numeric' => 'The :attribute must be greater than :value.', 49 | 'file' => 'The :attribute must be greater than :value kilobytes.', 50 | 'string' => 'The :attribute must be greater than :value characters.', 51 | 'array' => 'The :attribute must have more than :value items.', 52 | ], 53 | 'gte' => [ 54 | 'numeric' => 'The :attribute must be greater than or equal :value.', 55 | 'file' => 'The :attribute must be greater than or equal :value kilobytes.', 56 | 'string' => 'The :attribute must be greater than or equal :value characters.', 57 | 'array' => 'The :attribute must have :value items or more.', 58 | ], 59 | 'image' => 'The :attribute must be an image.', 60 | 'in' => 'The selected :attribute is invalid.', 61 | 'in_array' => 'The :attribute field does not exist in :other.', 62 | 'integer' => 'The :attribute must be an integer.', 63 | 'ip' => 'The :attribute must be a valid IP address.', 64 | 'ipv4' => 'The :attribute must be a valid IPv4 address.', 65 | 'ipv6' => 'The :attribute must be a valid IPv6 address.', 66 | 'json' => 'The :attribute must be a valid JSON string.', 67 | 'lt' => [ 68 | 'numeric' => 'The :attribute must be less than :value.', 69 | 'file' => 'The :attribute must be less than :value kilobytes.', 70 | 'string' => 'The :attribute must be less than :value characters.', 71 | 'array' => 'The :attribute must have less than :value items.', 72 | ], 73 | 'lte' => [ 74 | 'numeric' => 'The :attribute must be less than or equal :value.', 75 | 'file' => 'The :attribute must be less than or equal :value kilobytes.', 76 | 'string' => 'The :attribute must be less than or equal :value characters.', 77 | 'array' => 'The :attribute must not have more than :value items.', 78 | ], 79 | 'max' => [ 80 | 'numeric' => 'The :attribute must not be greater than :max.', 81 | 'file' => 'The :attribute must not be greater than :max kilobytes.', 82 | 'string' => 'The :attribute must not be greater than :max characters.', 83 | 'array' => 'The :attribute must not have more than :max items.', 84 | ], 85 | 'mimes' => 'The :attribute must be a file of type: :values.', 86 | 'mimetypes' => 'The :attribute must be a file of type: :values.', 87 | 'min' => [ 88 | 'numeric' => 'The :attribute must be at least :min.', 89 | 'file' => 'The :attribute must be at least :min kilobytes.', 90 | 'string' => 'The :attribute must be at least :min characters.', 91 | 'array' => 'The :attribute must have at least :min items.', 92 | ], 93 | 'multiple_of' => 'The :attribute must be a multiple of :value.', 94 | 'not_in' => 'The selected :attribute is invalid.', 95 | 'not_regex' => 'The :attribute format is invalid.', 96 | 'numeric' => 'The :attribute must be a number.', 97 | 'password' => 'The password is incorrect.', 98 | 'present' => 'The :attribute field must be present.', 99 | 'regex' => 'The :attribute format is invalid.', 100 | 'required' => 'The :attribute field is required.', 101 | 'required_if' => 'The :attribute field is required when :other is :value.', 102 | 'required_unless' => 'The :attribute field is required unless :other is in :values.', 103 | 'required_with' => 'The :attribute field is required when :values is present.', 104 | 'required_with_all' => 'The :attribute field is required when :values are present.', 105 | 'required_without' => 'The :attribute field is required when :values is not present.', 106 | 'required_without_all' => 'The :attribute field is required when none of :values are present.', 107 | 'prohibited' => 'The :attribute field is prohibited.', 108 | 'prohibited_if' => 'The :attribute field is prohibited when :other is :value.', 109 | 'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.', 110 | 'same' => 'The :attribute and :other must match.', 111 | 'size' => [ 112 | 'numeric' => 'The :attribute must be :size.', 113 | 'file' => 'The :attribute must be :size kilobytes.', 114 | 'string' => 'The :attribute must be :size characters.', 115 | 'array' => 'The :attribute must contain :size items.', 116 | ], 117 | 'starts_with' => 'The :attribute must start with one of the following: :values.', 118 | 'string' => 'The :attribute must be a string.', 119 | 'timezone' => 'The :attribute must be a valid zone.', 120 | 'unique' => 'The :attribute has already been taken.', 121 | 'uploaded' => 'The :attribute failed to upload.', 122 | 'url' => 'The :attribute format is invalid.', 123 | 'uuid' => 'The :attribute must be a valid UUID.', 124 | 125 | /* 126 | |-------------------------------------------------------------------------- 127 | | Custom Validation Language Lines 128 | |-------------------------------------------------------------------------- 129 | | 130 | | Here you may specify custom validation messages for attributes using the 131 | | convention "attribute.rule" to name the lines. This makes it quick to 132 | | specify a specific custom language line for a given attribute rule. 133 | | 134 | */ 135 | 136 | 'custom' => [ 137 | 'attribute-name' => [ 138 | 'rule-name' => 'custom-message', 139 | ], 140 | ], 141 | 142 | /* 143 | |-------------------------------------------------------------------------- 144 | | Custom Validation Attributes 145 | |-------------------------------------------------------------------------- 146 | | 147 | | The following language lines are used to swap our attribute placeholder 148 | | with something more reader friendly such as "E-Mail Address" instead 149 | | of "email". This simply helps us make our message more expressive. 150 | | 151 | */ 152 | 153 | 'attributes' => [], 154 | 155 | ]; 156 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | version('v1', ['middleware' => ['api']], function (Router $api) { 28 | /* 29 | * Authentication 30 | */ 31 | $api->group(['prefix' => 'auth'], function (Router $api) { 32 | $api->group(['prefix' => 'jwt'], function (Router $api) { 33 | $api->get('/token', 'App\Http\Controllers\Auth\AuthController@token'); 34 | }); 35 | }); 36 | 37 | /* 38 | * Authenticated routes 39 | */ 40 | $api->group(['middleware' => ['api.auth']], function (Router $api) { 41 | /* 42 | * Authentication 43 | */ 44 | $api->group(['prefix' => 'auth'], function (Router $api) { 45 | $api->group(['prefix' => 'jwt'], function (Router $api) { 46 | $api->get('/refresh', 'App\Http\Controllers\Auth\AuthController@refresh'); 47 | $api->delete('/token', 'App\Http\Controllers\Auth\AuthController@logout'); 48 | }); 49 | 50 | $api->get('/me', 'App\Http\Controllers\Auth\AuthController@getUser'); 51 | }); 52 | 53 | /* 54 | * Users 55 | */ 56 | $api->group(['prefix' => 'users', 'middleware' => 'check_role:admin'], function (Router $api) { 57 | $api->get('/', 'App\Http\Controllers\UserController@getAll'); 58 | $api->get('/{uuid}', 'App\Http\Controllers\UserController@get'); 59 | $api->post('/', 'App\Http\Controllers\UserController@post'); 60 | $api->put('/{uuid}', 'App\Http\Controllers\UserController@put'); 61 | $api->patch('/{uuid}', 'App\Http\Controllers\UserController@patch'); 62 | $api->delete('/{uuid}', 'App\Http\Controllers\UserController@delete'); 63 | }); 64 | 65 | /* 66 | * Roles 67 | */ 68 | $api->group(['prefix' => 'roles'], function (Router $api) { 69 | $api->get('/', 'App\Http\Controllers\RoleController@getAll'); 70 | }); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 18 | }); 19 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 9 | })->purpose('Display an inspiring quote')->hourly(); 10 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | $uri = urldecode( 11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 12 | ); 13 | 14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 15 | // built-in PHP web server. This provides a convenient way to test a Laravel 16 | // application without having installed a "real" web server software here. 17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !private/ 3 | !public/ 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /storage/app/private/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | compiled.php 2 | config.php 3 | down 4 | events.scanned.php 5 | maintenance.php 6 | routes.php 7 | routes.scanned.php 8 | schedule-* 9 | services.json 10 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/Api/UserControllerTest.php: -------------------------------------------------------------------------------- 1 | actingAsAdmin()->json('GET', '/users'); 12 | 13 | // Check status and structure 14 | $jsonResponse 15 | ->assertStatus(200) 16 | ->assertJsonStructure( 17 | [ 18 | 'data' => [ 19 | [ 20 | 'id', 21 | 'name', 22 | 'email', 23 | ], 24 | ], 25 | ] 26 | ); 27 | } 28 | 29 | public function testPost() { 30 | $testUser = User::factory()->make()->getAttributes(); 31 | 32 | $jsonResponse = $this->actingAsAdmin()->json('POST', '/users', $testUser); 33 | 34 | unset($testUser['password']); 35 | 36 | // Check status, structure and data 37 | $jsonResponse 38 | ->assertStatus(201) 39 | ->assertJsonStructure( 40 | [ 41 | 'data' => 42 | [ 43 | 'name', 44 | 'email', 45 | 'id', 46 | ] 47 | ] 48 | ); 49 | 50 | // Check password is hidden 51 | $response = $jsonResponse->decodeResponseJson(); 52 | $this->assertNotContains('password', $response['data']); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/ApiTestCase.php: -------------------------------------------------------------------------------- 1 | withHeader('Authorization', 'Bearer ' . JWTAuth::fromUser($user)); 25 | } 26 | 27 | /** 28 | * API Test case helper function for setting up 29 | * the request auth header as supplied user 30 | * 31 | * @param array $credentials 32 | * @return $this 33 | */ 34 | public function actingAsUser($credentials) 35 | { 36 | if (!$token = JWTAuth::attempt($credentials)) { 37 | return $this; 38 | } 39 | 40 | $user = ($apiKey = Arr::get($credentials, 'api_key')) 41 | ? User::whereApiKey($apiKey)->firstOrFail() 42 | : User::whereEmail(Arr::get($credentials, 'email'))->firstOrFail(); 43 | 44 | return $this->actingAs($user); 45 | } 46 | 47 | /** 48 | * API Test case helper function for setting up the request as a logged in admin user 49 | * 50 | * @return $this 51 | */ 52 | public function actingAsAdmin() 53 | { 54 | $user = User::where('email', UserStorySeeder::ADMIN_CREDENTIALS['email'])->firstOrFail(); 55 | 56 | return $this->actingAs($user); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 17 | 18 | $response->assertStatus(200); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | make(Illuminate\Contracts\Console\Kernel::class); 8 | $console->bootstrap(); 9 | 10 | // Migrate and seed test DB 11 | $console->call('migrate:fresh', ['--seed' => true]); 12 | 13 | // Clear all app cache 14 | $app->cache->clear(); 15 | --------------------------------------------------------------------------------