├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── composer.json ├── config ├── .gitkeep └── config.php ├── phpunit.xml.dist.bak ├── src ├── Checks │ ├── AppKeyIsSet.php │ ├── Check.php │ ├── ComposerWithDevDependenciesIsUpToDate.php │ ├── ComposerWithoutDevDependenciesIsUpToDate.php │ ├── ConfigurationIsCached.php │ ├── ConfigurationIsNotCached.php │ ├── CorrectPhpVersionIsInstalled.php │ ├── DatabaseCanBeAccessed.php │ ├── DebugModeIsNotEnabled.php │ ├── DirectoriesHaveCorrectPermissions.php │ ├── EnvFileExists.php │ ├── ExampleEnvironmentVariablesAreSet.php │ ├── ExampleEnvironmentVariablesAreUpToDate.php │ ├── HorizonIsRunning.php │ ├── LocalesAreInstalled.php │ ├── MaintenanceModeNotEnabled.php │ ├── MigrationsAreUpToDate.php │ ├── PhpExtensionsAreDisabled.php │ ├── PhpExtensionsAreInstalled.php │ ├── RedisCanBeAccessed.php │ ├── RoutesAreCached.php │ ├── RoutesAreNotCached.php │ ├── ServersArePingable.php │ ├── StorageDirectoryIsLinked.php │ ├── SupervisorProgramsAreRunning.php │ └── UsedEnvironmentVariablesAreDefined.php ├── Composer.php ├── Exceptions │ └── InvalidConfigurationException.php ├── SelfDiagnosisCommand.php ├── SelfDiagnosisServiceProvider.php ├── Server.php └── SystemFunctions.php └── translations ├── de ├── checks.php └── commands.php ├── en ├── checks.php └── commands.php └── id ├── checks.php └── commands.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-self-diagnosis` will be documented in this file 4 | 5 | ## 1.0.0 - 201X-XX-XX 6 | 7 | - initial release 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | Please read and understand the contribution guide before creating an issue or pull request. 6 | 7 | ## Etiquette 8 | 9 | This project is open source, and as such, the maintainers give their free time to build and maintain the source code 10 | held within. They make the code freely available in the hope that it will be of use to other developers. It would be 11 | extremely unfair for them to suffer abuse or anger for their hard work. 12 | 13 | Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the 14 | world that developers are civilized and selfless people. 15 | 16 | It's the duty of the maintainer to ensure that all submissions to the project are of sufficient 17 | quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. 18 | 19 | ## Viability 20 | 21 | When requesting or submitting new features, first consider whether it might be useful to others. Open 22 | source projects are used by many developers, who may have entirely different needs to your own. Think about 23 | whether or not your feature is likely to be used by other users of the project. 24 | 25 | ## Procedure 26 | 27 | Before filing an issue: 28 | 29 | - Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. 30 | - Check to make sure your feature suggestion isn't already present within the project. 31 | - Check the pull requests tab to ensure that the bug doesn't have a fix in progress. 32 | - Check the pull requests tab to ensure that the feature isn't already in progress. 33 | 34 | Before submitting a pull request: 35 | 36 | - Check the codebase to ensure that your feature doesn't already exist. 37 | - Check the pull requests to ensure that another person hasn't already submitted the feature or fix. 38 | 39 | ## Requirements 40 | 41 | If the project maintainer has any additional requirements, you will find them listed here. 42 | 43 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). 44 | 45 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 46 | 47 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 48 | 49 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. 50 | 51 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 52 | 53 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 54 | 55 | **Happy coding**! 56 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Beyond Code GmbH 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Perform Self-Diagnosis Tests On Your Laravel Application 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/beyondcode/laravel-self-diagnosis.svg?style=flat-square)](https://packagist.org/packages/beyondcode/laravel-self-diagnosis) 4 | [![Total Downloads](https://img.shields.io/packagist/dt/beyondcode/laravel-self-diagnosis.svg?style=flat-square)](https://packagist.org/packages/beyondcode/laravel-self-diagnosis) 5 | 6 | This package allows you to run self-diagnosis tests on your Laravel application. It comes with multiple checks out of the box and allows you to add custom checks yourself. 7 | 8 | Here is an example output of the command: 9 | 10 | ![All Checks passed](https://beyondco.de/github/self-diagnosis/checks_green.png) 11 | 12 | ## Included checks 13 | 14 | - Is the `APP_KEY` set? 15 | - Are your composer dependencies up to date with the `composer.lock` file? 16 | - Do you have the correct PHP version installed? 17 | - Do you have the correct PHP extensions installed? 18 | - Can a connection to the database be established? 19 | - Do the `storage` and `bootstrap/cache` directories have the correct permissions? 20 | - Does the `.env` file exist? 21 | - Is the maintenance mode disabled? 22 | - Are the required locales installed on the system? 23 | - Are there environment variables that exist in `.env.example` but not in `.env`? 24 | - Are there any migrations that need to be run? 25 | - Is the storage directory linked? 26 | - Can Redis be accessed? 27 | 28 | ### Development environment checks 29 | 30 | - Is the configuration not cached? 31 | - Are the routes not cached? 32 | - Are there environment variables that exist in `.env` but not in `.env.example`? 33 | 34 | ### Production environment checks 35 | 36 | - Is the configuration cached? 37 | - Are the routes cached? 38 | - Is the xdebug PHP extension disabled? 39 | - Is APP_DEBUG set to false? 40 | - Are certain servers reachable? 41 | - Are certain supervisor programs running? 42 | 43 | ## Installation 44 | 45 | You can install the package via composer: 46 | 47 | ```bash 48 | composer require beyondcode/laravel-self-diagnosis 49 | ``` 50 | 51 | ## Usage 52 | 53 | Just call the artisan command to start the checks: 54 | 55 | ```bash 56 | php artisan self-diagnosis 57 | ``` 58 | 59 | ### Customization 60 | 61 | You can publish the configuration file, that contains all available checks using: 62 | 63 | ```bash 64 | php artisan vendor:publish --provider=BeyondCode\\SelfDiagnosis\\SelfDiagnosisServiceProvider 65 | ``` 66 | 67 | This will publish a `self-diagnosis.php` file in your `config` folder. This file contains all the checks that will be performed on your application. 68 | 69 | ```php 70 | [ 78 | 'prod' => 'production', 79 | 'live' => 'production', 80 | 'local' => 'development', 81 | ], 82 | 83 | /* 84 | * Common checks that will be performed on all environments. 85 | */ 86 | 'checks' => [ 87 | \BeyondCode\SelfDiagnosis\Checks\AppKeyIsSet::class, 88 | \BeyondCode\SelfDiagnosis\Checks\CorrectPhpVersionIsInstalled::class, 89 | \BeyondCode\SelfDiagnosis\Checks\DatabaseCanBeAccessed::class => [ 90 | 'default_connection' => true, 91 | 'connections' => [], 92 | ], 93 | \BeyondCode\SelfDiagnosis\Checks\DirectoriesHaveCorrectPermissions::class => [ 94 | 'directories' => [ 95 | storage_path(), 96 | base_path('bootstrap/cache'), 97 | ], 98 | ], 99 | \BeyondCode\SelfDiagnosis\Checks\EnvFileExists::class, 100 | \BeyondCode\SelfDiagnosis\Checks\ExampleEnvironmentVariablesAreSet::class, 101 | \BeyondCode\SelfDiagnosis\Checks\LocalesAreInstalled::class => [ 102 | 'required_locales' => [ 103 | 'en_US', 104 | 'en_US.utf8', 105 | ], 106 | ], 107 | \BeyondCode\SelfDiagnosis\Checks\MaintenanceModeNotEnabled::class, 108 | \BeyondCode\SelfDiagnosis\Checks\MigrationsAreUpToDate::class, 109 | \BeyondCode\SelfDiagnosis\Checks\PhpExtensionsAreInstalled::class => [ 110 | 'extensions' => [ 111 | 'openssl', 112 | 'PDO', 113 | 'mbstring', 114 | 'tokenizer', 115 | 'xml', 116 | 'ctype', 117 | 'json', 118 | ], 119 | 'include_composer_extensions' => true, 120 | ], 121 | \BeyondCode\SelfDiagnosis\Checks\StorageDirectoryIsLinked::class, 122 | ], 123 | 124 | /* 125 | * Environment specific checks that will only be performed for the corresponding environment. 126 | */ 127 | 'environment_checks' => [ 128 | 'development' => [ 129 | \BeyondCode\SelfDiagnosis\Checks\ComposerWithDevDependenciesIsUpToDate::class => [ 130 | 'additional_options' => '--ignore-platform-reqs', 131 | ], 132 | \BeyondCode\SelfDiagnosis\Checks\ConfigurationIsNotCached::class, 133 | \BeyondCode\SelfDiagnosis\Checks\RoutesAreNotCached::class, 134 | ], 135 | 'production' => [ 136 | \BeyondCode\SelfDiagnosis\Checks\ComposerWithoutDevDependenciesIsUpToDate::class => [ 137 | 'additional_options' => '--ignore-platform-reqs', 138 | ], 139 | \BeyondCode\SelfDiagnosis\Checks\ConfigurationIsCached::class, 140 | \BeyondCode\SelfDiagnosis\Checks\DebugModeIsNotEnabled::class, 141 | \BeyondCode\SelfDiagnosis\Checks\PhpExtensionsAreDisabled::class => [ 142 | 'extensions' => [ 143 | 'xdebug', 144 | ], 145 | ], 146 | \BeyondCode\SelfDiagnosis\Checks\RedisCanBeAccessed::class => [ 147 | 'default_connection' => true, 148 | 'connections' => [], 149 | ], 150 | \BeyondCode\SelfDiagnosis\Checks\RoutesAreCached::class, 151 | \BeyondCode\SelfDiagnosis\Checks\ServersArePingable::class => [ 152 | 'servers' => [ 153 | 'www.google.com', 154 | ['host' => 'www.google.com', 'port' => 8080], 155 | '8.8.8.8', 156 | ['host' => '8.8.8.8', 'port' => 8080, 'timeout' => 5], 157 | ], 158 | ], 159 | \BeyondCode\SelfDiagnosis\Checks\SupervisorProgramsAreRunning::class => [ 160 | 'programs' => [ 161 | 'horizon', 162 | ], 163 | 'restarted_within' => 300, // max seconds since last restart, 0 to disable check 164 | ], 165 | ], 166 | ], 167 | 168 | ]; 169 | ``` 170 | 171 | #### Available Configuration Options 172 | 173 | The following options are available for the individual checks: 174 | 175 | - [`BeyondCode\SelfDiagnosis\Checks\ComposerWithDevDependenciesIsUpToDate`](src/Checks/ComposerWithDevDependenciesIsUpToDate.php) 176 | - **additional_options** *(string, optional parameters like `'--ignore-platform-reqs'`)*: optional arguments for composer 177 | - [`BeyondCode\SelfDiagnosis\Checks\ComposerWithoutDevDependenciesIsUpToDate`](src/Checks/ComposerWithoutDevDependenciesIsUpToDate.php) 178 | - **additional_options** *(string, optional parameters like `'--ignore-platform-reqs'`)*: optional arguments for composer 179 | - [`BeyondCode\SelfDiagnosis\Checks\DatabaseCanBeAccessed`](src/Checks/DatabaseCanBeAccessed.php) 180 | - **default_connection** *(boolean, default: `true`)*: if the default connection should be checked 181 | - **connections** *(array, list of connection names like `['mysql', 'sqlsrv']`, default: `[]`)*: additional connections to check 182 | - [`BeyondCode\SelfDiagnosis\Checks\DirectoriesHaveCorrectPermissions`](src/Checks/DirectoriesHaveCorrectPermissions.php) 183 | - **directories** *(array, list of directory paths like `[storage_path(), base_path('bootstrap/cache')]`, default: `[]`)*: directories to check 184 | - [`BeyondCode\SelfDiagnosis\Checks\LocalesAreInstalled`](src/Checks/LocalesAreInstalled.php) 185 | - **required_locales** *(array, list of locales like `['en_US', 'en_US.utf8']`, default: `[]`)*: locales to check 186 | - [`BeyondCode\SelfDiagnosis\Checks\PhpExtensionsAreDisabled`](src/Checks/PhpExtensionsAreDisabled.php) 187 | - **extensions** *(array, list of extension names like `['xdebug', 'zlib']`, default: `[]`)*: extensions to check 188 | - [`BeyondCode\SelfDiagnosis\Checks\PhpExtensionsAreInstalled`](src/Checks/PhpExtensionsAreInstalled.php) 189 | - **extensions** *(array, list of extension names like `['openssl', 'PDO']`, default: `[]`)*: extensions to check 190 | - **include_composer_extensions** *(boolean, default: `false`)*: if required extensions defined in `composer.json` should be checked 191 | - [`BeyondCode\SelfDiagnosis\Checks\RedisCanBeAccessed`](src/Checks/RedisCanBeAccessed.php) 192 | - **default_connection** *(boolean, default: `true`)*: if the default connection should be checked 193 | - **connections** *(array, list of connection names like `['cache_1', 'cache_2']`, default: `[]`)*: additional connections to check 194 | - [`BeyondCode\SelfDiagnosis\Checks\SupervisorProgramsAreRunning`](src/Checks/SupervisorProgramsAreRunning.php) 195 | - **programs** *(array, list of programs like `['horizon', 'another-program']`, default: `[]`)*: programs that are required to be running 196 | - **restarted_within** *(integer, max allowed seconds since last restart of programs (`0` = disabled), default: `0`)*: verifies that programs have been restarted recently to grab code updates 197 | - [`BeyondCode\SelfDiagnosis\Checks\ServersArePingable`](src/Checks/ServersArePingable.php) 198 | - **servers** *(array, list of servers and parameters like `['google.com', ['host' => 'google.com', 'port' => 8080]]`)*: servers to ping 199 | 200 | ### Custom Checks 201 | 202 | You can create custom checks, by implementing the [`BeyondCode\SelfDiagnosis\Checks\Check`](src/Checks/Check.php) interface and adding the class to the config file. 203 | Like this: 204 | 205 | ```php 206 | [ 9 | 'prod' => 'production', 10 | 'live' => 'production', 11 | 'local' => 'development', 12 | ], 13 | 14 | /* 15 | * Common checks that will be performed on all environments. 16 | */ 17 | 'checks' => [ 18 | \BeyondCode\SelfDiagnosis\Checks\AppKeyIsSet::class, 19 | \BeyondCode\SelfDiagnosis\Checks\CorrectPhpVersionIsInstalled::class, 20 | \BeyondCode\SelfDiagnosis\Checks\DatabaseCanBeAccessed::class => [ 21 | 'default_connection' => true, 22 | 'connections' => [], 23 | ], 24 | \BeyondCode\SelfDiagnosis\Checks\DirectoriesHaveCorrectPermissions::class => [ 25 | 'directories' => [ 26 | storage_path(), 27 | base_path('bootstrap/cache'), 28 | ], 29 | ], 30 | \BeyondCode\SelfDiagnosis\Checks\EnvFileExists::class, 31 | \BeyondCode\SelfDiagnosis\Checks\ExampleEnvironmentVariablesAreSet::class, 32 | \BeyondCode\SelfDiagnosis\Checks\UsedEnvironmentVariablesAreDefined::class => [ 33 | 'directories' => [ 34 | config_path(), 35 | app_path(), 36 | ], 37 | ], 38 | \BeyondCode\SelfDiagnosis\Checks\LocalesAreInstalled::class => [ 39 | 'required_locales' => [ 40 | 'en_US', 41 | PHP_OS === 'Darwin' ? 'en_US.UTF-8' : 'en_US.utf8', 42 | ], 43 | ], 44 | \BeyondCode\SelfDiagnosis\Checks\MaintenanceModeNotEnabled::class, 45 | \BeyondCode\SelfDiagnosis\Checks\MigrationsAreUpToDate::class, 46 | \BeyondCode\SelfDiagnosis\Checks\PhpExtensionsAreInstalled::class => [ 47 | 'extensions' => [ 48 | 'openssl', 49 | 'PDO', 50 | 'mbstring', 51 | 'tokenizer', 52 | 'xml', 53 | 'ctype', 54 | 'json', 55 | ], 56 | 'include_composer_extensions' => true, 57 | ], 58 | //\BeyondCode\SelfDiagnosis\Checks\RedisCanBeAccessed::class => [ 59 | // 'default_connection' => true, 60 | // 'connections' => [], 61 | //], 62 | \BeyondCode\SelfDiagnosis\Checks\StorageDirectoryIsLinked::class, 63 | ], 64 | 65 | /* 66 | * Environment specific checks that will only be performed for the corresponding environment. 67 | */ 68 | 'environment_checks' => [ 69 | 'development' => [ 70 | \BeyondCode\SelfDiagnosis\Checks\ComposerWithDevDependenciesIsUpToDate::class, 71 | \BeyondCode\SelfDiagnosis\Checks\ConfigurationIsNotCached::class, 72 | \BeyondCode\SelfDiagnosis\Checks\RoutesAreNotCached::class, 73 | \BeyondCode\SelfDiagnosis\Checks\ExampleEnvironmentVariablesAreUpToDate::class, 74 | \BeyondCode\SelfDiagnosis\Checks\UsedEnvironmentVariablesAreDefined::class, 75 | ], 76 | 'production' => [ 77 | \BeyondCode\SelfDiagnosis\Checks\ComposerWithoutDevDependenciesIsUpToDate::class, 78 | \BeyondCode\SelfDiagnosis\Checks\ConfigurationIsCached::class, 79 | \BeyondCode\SelfDiagnosis\Checks\DebugModeIsNotEnabled::class, 80 | \BeyondCode\SelfDiagnosis\Checks\PhpExtensionsAreDisabled::class => [ 81 | 'extensions' => [ 82 | 'xdebug', 83 | ], 84 | ], 85 | \BeyondCode\SelfDiagnosis\Checks\RoutesAreCached::class, 86 | //\BeyondCode\SelfDiagnosis\Checks\ServersArePingable::class => [ 87 | // 'servers' => [ 88 | // 'www.google.com', 89 | // ['host' => 'www.google.com', 'port' => 8080], 90 | // '8.8.8.8', 91 | // ['host' => '8.8.8.8', 'port' => 8080, 'timeout' => 5], 92 | // ], 93 | //], 94 | //\BeyondCode\SelfDiagnosis\Checks\SupervisorProgramsAreRunning::class => [ 95 | // 'programs' => [ 96 | // 'horizon', 97 | // ], 98 | // 'restarted_within' => 300, 99 | //], 100 | //\BeyondCode\SelfDiagnosis\Checks\HorizonIsRunning::class, 101 | ], 102 | ], 103 | 104 | ]; 105 | -------------------------------------------------------------------------------- /phpunit.xml.dist.bak: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | tests 15 | 16 | 17 | 18 | 19 | src/ 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Checks/AppKeyIsSet.php: -------------------------------------------------------------------------------- 1 | composer = $composer; 20 | $this->composer->setWorkingPath(base_path()); 21 | } 22 | 23 | /** 24 | * The name of the check. 25 | * 26 | * @param array $config 27 | * @return string 28 | */ 29 | public function name(array $config): string 30 | { 31 | return trans('self-diagnosis::checks.composer_with_dev_dependencies_is_up_to_date.name'); 32 | } 33 | 34 | /** 35 | * Perform the actual verification of this check. 36 | * 37 | * @param array $config 38 | * @return bool 39 | */ 40 | public function check(array $config): bool 41 | { 42 | $additionalOptions = Arr::get($config, 'additional_options', ''); 43 | 44 | $this->output = $this->composer->installDryRun($additionalOptions); 45 | 46 | return Str::contains($this->output, [ 47 | 'Nothing to install or update', 48 | 'Nothing to install, update or remove', 49 | 'Package operations: 0 installs, 0 updates, 0 removals' 50 | ]); 51 | } 52 | 53 | /** 54 | * The error message to display in case the check does not pass. 55 | * 56 | * @param array $config 57 | * @return string 58 | */ 59 | public function message(array $config): string 60 | { 61 | return trans('self-diagnosis::checks.composer_with_dev_dependencies_is_up_to_date.message', [ 62 | 'more' => $this->output, 63 | ]); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Checks/ComposerWithoutDevDependenciesIsUpToDate.php: -------------------------------------------------------------------------------- 1 | composer = $composer; 20 | $this->composer->setWorkingPath(base_path()); 21 | } 22 | 23 | /** 24 | * The name of the check. 25 | * 26 | * @param array $config 27 | * @return string 28 | */ 29 | public function name(array $config): string 30 | { 31 | return trans('self-diagnosis::checks.composer_without_dev_dependencies_is_up_to_date.name'); 32 | } 33 | 34 | /** 35 | * Perform the actual verification of this check. 36 | * 37 | * @param array $config 38 | * @return bool 39 | */ 40 | public function check(array $config): bool 41 | { 42 | $additionalOptions = Arr::get($config, 'additional_options', ''); 43 | 44 | $this->output = $this->composer->installDryRun('--no-dev ' . $additionalOptions); 45 | 46 | return Str::contains($this->output, [ 47 | 'Nothing to install or update', 48 | 'Nothing to install, update or remove', 49 | 'Package operations: 0 installs, 0 updates, 0 removals' 50 | ]); 51 | } 52 | 53 | /** 54 | * The error message to display in case the check does not pass. 55 | * 56 | * @param array $config 57 | * @return string 58 | */ 59 | public function message(array $config): string 60 | { 61 | return trans('self-diagnosis::checks.composer_without_dev_dependencies_is_up_to_date.message', [ 62 | 'more' => $this->output, 63 | ]); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Checks/ConfigurationIsCached.php: -------------------------------------------------------------------------------- 1 | configurationIsCached() === true; 28 | } 29 | 30 | /** 31 | * The error message to display in case the check does not pass. 32 | * 33 | * @param array $config 34 | * @return string 35 | */ 36 | public function message(array $config): string 37 | { 38 | return trans('self-diagnosis::checks.configuration_is_cached.message'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Checks/ConfigurationIsNotCached.php: -------------------------------------------------------------------------------- 1 | configurationIsCached() === false; 28 | } 29 | 30 | /** 31 | * The error message to display in case the check does not pass. 32 | * 33 | * @param array $config 34 | * @return string 35 | */ 36 | public function message(array $config): string 37 | { 38 | return trans('self-diagnosis::checks.configuration_is_not_cached.message'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Checks/CorrectPhpVersionIsInstalled.php: -------------------------------------------------------------------------------- 1 | filesystem = $filesystem; 17 | } 18 | 19 | /** 20 | * The name of the check. 21 | * 22 | * @param array $config 23 | * @return string 24 | */ 25 | public function name(array $config): string 26 | { 27 | return trans('self-diagnosis::checks.correct_php_version_is_installed.name'); 28 | } 29 | 30 | /** 31 | * Perform the actual verification of this check. 32 | * 33 | * @param array $config 34 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 35 | * @return bool 36 | */ 37 | public function check(array $config): bool 38 | { 39 | // we dont use the phpversion function because that adds more data to the number (Like: -1+ubuntu16.04) 40 | // that conflicts with the semver check 41 | return Semver::satisfies( 42 | PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION, 43 | $this->getRequiredPhpConstraint() 44 | ); 45 | } 46 | 47 | /** 48 | * The error message to display in case the check does not pass. 49 | * 50 | * @param array $config 51 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 52 | * @return string 53 | */ 54 | public function message(array $config): string 55 | { 56 | return trans('self-diagnosis::checks.correct_php_version_is_installed.message', [ 57 | 'required' => $this->getRequiredPhpConstraint(), 58 | 'used' => phpversion(), 59 | ]); 60 | } 61 | 62 | /** 63 | * @return mixed 64 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 65 | */ 66 | public function getRequiredPhpConstraint() 67 | { 68 | $composer = json_decode($this->filesystem->get(base_path('composer.json')), true); 69 | return Arr::get($composer, 'require.php'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Checks/DatabaseCanBeAccessed.php: -------------------------------------------------------------------------------- 1 | getPdo(); 34 | } 35 | 36 | foreach (Arr::get($config, 'connections', []) as $connection) { 37 | DB::connection($connection)->getPdo(); 38 | } 39 | 40 | return true; 41 | } catch (\Exception $e) { 42 | $this->message = $e->getMessage(); 43 | } 44 | return false; 45 | } 46 | 47 | /** 48 | * The error message to display in case the check does not pass. 49 | * 50 | * @param array $config 51 | * @return string 52 | */ 53 | public function message(array $config): string 54 | { 55 | return trans('self-diagnosis::checks.database_can_be_accessed.message', [ 56 | 'error' => $this->message, 57 | ]); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Checks/DebugModeIsNotEnabled.php: -------------------------------------------------------------------------------- 1 | filesystem = $filesystem; 24 | } 25 | 26 | /** 27 | * The name of the check. 28 | * 29 | * @param array $config 30 | * @return string 31 | */ 32 | public function name(array $config): string 33 | { 34 | return trans('self-diagnosis::checks.directories_have_correct_permissions.name'); 35 | } 36 | 37 | /** 38 | * The error message to display in case the check does not pass. 39 | * 40 | * @param array $config 41 | * @return string 42 | */ 43 | public function message(array $config): string 44 | { 45 | return trans('self-diagnosis::checks.directories_have_correct_permissions.message', [ 46 | 'directories' => $this->paths->implode(PHP_EOL), 47 | ]); 48 | } 49 | 50 | /** 51 | * Perform the actual verification of this check. 52 | * 53 | * @param array $config 54 | * @return bool 55 | */ 56 | public function check(array $config): bool 57 | { 58 | $this->paths = Collection::make(Arr::get($config, 'directories', [])); 59 | 60 | $this->paths = $this->paths->reject(function ($path) { 61 | return $this->filesystem->isWritable($path); 62 | }); 63 | 64 | return $this->paths->isEmpty(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Checks/EnvFileExists.php: -------------------------------------------------------------------------------- 1 | filesystem = $filesystem; 16 | } 17 | 18 | /** 19 | * The name of the check. 20 | * 21 | * @param array $config 22 | * @return string 23 | */ 24 | public function name(array $config): string 25 | { 26 | return trans('self-diagnosis::checks.env_file_exists.name'); 27 | } 28 | 29 | /** 30 | * Perform the actual verification of this check. 31 | * 32 | * @param array $config 33 | * @return bool 34 | */ 35 | public function check(array $config): bool 36 | { 37 | return $this->filesystem->exists(base_path('.env')); 38 | } 39 | 40 | /** 41 | * The error message to display in case the check does not pass. 42 | * 43 | * @param array $config 44 | * @return string 45 | */ 46 | public function message(array $config): string 47 | { 48 | return trans('self-diagnosis::checks.env_file_exists.message'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Checks/ExampleEnvironmentVariablesAreSet.php: -------------------------------------------------------------------------------- 1 | checkForDotEnvV5(); 34 | } 35 | if (method_exists(Dotenv::class, 'createImmutable')) { 36 | return $this->checkForDotEnvV4(); 37 | } 38 | 39 | if (interface_exists(\Dotenv\Environment\FactoryInterface::class)) { 40 | $examples = Dotenv::create(base_path(), '.env.example'); 41 | $actual = Dotenv::create(base_path(), '.env'); 42 | } else { 43 | $examples = new Dotenv(base_path(), '.env.example'); 44 | $actual = new Dotenv(base_path(), '.env'); 45 | } 46 | 47 | $examples->safeLoad(); 48 | $actual->safeLoad(); 49 | 50 | $this->envVariables = Collection::make($examples->getEnvironmentVariableNames()) 51 | ->diff($actual->getEnvironmentVariableNames()); 52 | 53 | return $this->envVariables->isEmpty(); 54 | } 55 | 56 | /** 57 | * Perform the verification of this check for DotEnv v4. 58 | * 59 | * @return bool 60 | */ 61 | private function checkForDotEnvV4(): bool 62 | { 63 | $examples = Dotenv::createImmutable(base_path(), '.env.example'); 64 | $actual = Dotenv::createImmutable(base_path(), '.env'); 65 | 66 | $this->envVariables = Collection::make($examples->safeLoad()) 67 | ->diffKeys($actual->safeLoad()) 68 | ->keys(); 69 | 70 | return $this->envVariables->isEmpty(); 71 | } 72 | 73 | /** 74 | * Perform the verification of this check for DotEnv v5. 75 | * 76 | * @return bool 77 | */ 78 | private function checkForDotEnvV5(): bool 79 | { 80 | $examples = Dotenv::createMutable(base_path(), '.env.example'); 81 | $actual = Dotenv::createMutable(base_path(), '.env'); 82 | 83 | $this->envVariables = Collection::make($examples->safeLoad()) 84 | ->diffKeys($actual->safeLoad()) 85 | ->keys(); 86 | 87 | return $this->envVariables->isEmpty(); 88 | } 89 | 90 | /** 91 | * The error message to display in case the check does not pass. 92 | * 93 | * @param array $config 94 | * @return string 95 | */ 96 | public function message(array $config): string 97 | { 98 | return trans('self-diagnosis::checks.example_environment_variables_are_set.message', [ 99 | 'variables' => $this->envVariables->implode(PHP_EOL), 100 | ]); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Checks/ExampleEnvironmentVariablesAreUpToDate.php: -------------------------------------------------------------------------------- 1 | safeLoad(); 34 | 35 | $actual = Dotenv::createMutable(base_path(), '.env'); 36 | $actual = $actual->safeLoad(); 37 | 38 | $this->envVariables = Collection::make($actual) 39 | ->diffKeys($examples) 40 | ->keys(); 41 | 42 | return $this->envVariables->isEmpty(); 43 | } 44 | 45 | /** 46 | * The error message to display in case the check does not pass. 47 | * 48 | * @param array $config 49 | * @return string 50 | */ 51 | public function message(array $config): string 52 | { 53 | return trans('self-diagnosis::checks.example_environment_variables_are_up_to_date.message', [ 54 | 'variables' => $this->envVariables->implode(PHP_EOL), 55 | ]); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Checks/HorizonIsRunning.php: -------------------------------------------------------------------------------- 1 | error = $e->getMessage(); 38 | } 39 | 40 | return false; 41 | } 42 | 43 | /** 44 | * The error message to display in case the check does not pass. 45 | * 46 | * @param array $config 47 | * @return string 48 | */ 49 | public function message(array $config): string 50 | { 51 | if ($this->error !== null) { 52 | return trans('self-diagnosis::checks.horizon_is_running.message.unable_to_check', [ 53 | 'reason' => $this->error, 54 | ]); 55 | } 56 | 57 | return trans('self-diagnosis::checks.horizon_is_running.message.not_running'); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Checks/LocalesAreInstalled.php: -------------------------------------------------------------------------------- 1 | systemFunctions = $systemFunctions; 28 | } 29 | 30 | /** 31 | * The name of the check. 32 | * 33 | * @param array $config 34 | * @return string 35 | */ 36 | public function name(array $config): string 37 | { 38 | return trans('self-diagnosis::checks.locales_are_installed.name'); 39 | } 40 | 41 | /** 42 | * Perform the actual verification of this check. 43 | * 44 | * @param array $config 45 | * @return bool 46 | */ 47 | public function check(array $config): bool 48 | { 49 | $this->missingLocales = new Collection(Arr::get($config, 'required_locales', [])); 50 | if ($this->missingLocales->isEmpty()) { 51 | return true; 52 | } 53 | 54 | if (!$this->systemFunctions->isFunctionAvailable('shell_exec')) { 55 | $this->message = trans('self-diagnosis::checks.locales_are_installed.message.shell_exec_not_available'); 56 | return false; 57 | } 58 | 59 | if ($this->systemFunctions->isWindowsOperatingSystem()) { 60 | $this->message = trans('self-diagnosis::checks.locales_are_installed.message.cannot_run_on_windows'); 61 | return false; 62 | } 63 | 64 | $locales = $this->systemFunctions->callShellExec('locale -a'); 65 | if ($locales === null || $locales === '') { 66 | $this->message = trans('self-diagnosis::checks.locales_are_installed.message.locale_command_not_available'); 67 | return false; 68 | } 69 | 70 | $locales = explode("\n" , $locales); 71 | 72 | $this->missingLocales = $this->missingLocales->reject(function ($loc) use ($locales) { 73 | return in_array($loc, $locales); 74 | }); 75 | 76 | return $this->missingLocales->isEmpty(); 77 | } 78 | 79 | /** 80 | * The error message to display in case the check does not pass. 81 | * 82 | * @param array $config 83 | * @return string 84 | */ 85 | public function message(array $config): string 86 | { 87 | if ($this->message) { 88 | return $this->message; 89 | } 90 | 91 | return trans('self-diagnosis::checks.locales_are_installed.message.missing_locales', [ 92 | 'locales' => $this->missingLocales->implode(PHP_EOL), 93 | ]); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Checks/MaintenanceModeNotEnabled.php: -------------------------------------------------------------------------------- 1 | isDownForMaintenance() === false; 27 | } 28 | 29 | /** 30 | * The error message to display in case the check does not pass. 31 | * 32 | * @param array $config 33 | * @return string 34 | */ 35 | public function message(array $config): string 36 | { 37 | return trans('self-diagnosis::checks.maintenance_mode_not_enabled.message'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Checks/MigrationsAreUpToDate.php: -------------------------------------------------------------------------------- 1 | 'true', '--force' => 'true']); 32 | $output = Artisan::output(); 33 | return strstr($output, 'Nothing to migrate.'); 34 | } catch (\PDOException $e) { 35 | $this->databaseError = $e->getMessage(); 36 | } 37 | return false; 38 | } 39 | 40 | /** 41 | * The error message to display in case the check does not pass. 42 | * 43 | * @param array $config 44 | * @return string 45 | */ 46 | public function message(array $config): string 47 | { 48 | if ($this->databaseError !== null) { 49 | return trans('self-diagnosis::checks.migrations_are_up_to_date.message.unable_to_check', [ 50 | 'reason' => $this->databaseError, 51 | ]); 52 | } 53 | return trans('self-diagnosis::checks.migrations_are_up_to_date.message.need_to_migrate'); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Checks/PhpExtensionsAreDisabled.php: -------------------------------------------------------------------------------- 1 | extensions = Collection::make(Arr::get($config, 'extensions', [])); 34 | $this->extensions = $this->extensions->reject(function ($ext) { 35 | return extension_loaded($ext) === false; 36 | }); 37 | 38 | return $this->extensions->isEmpty(); 39 | } 40 | 41 | /** 42 | * The error message to display in case the check does not pass. 43 | * 44 | * @param array $config 45 | * @return string 46 | */ 47 | public function message(array $config): string 48 | { 49 | return trans('self-diagnosis::checks.php_extensions_are_disabled.message', [ 50 | 'extensions' => $this->extensions->implode(PHP_EOL), 51 | ]); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Checks/PhpExtensionsAreInstalled.php: -------------------------------------------------------------------------------- 1 | filesystem = $filesystem; 21 | } 22 | 23 | /** @var Collection */ 24 | private $extensions; 25 | 26 | /** 27 | * The name of the check. 28 | * 29 | * @param array $config 30 | * @return string 31 | */ 32 | public function name(array $config): string 33 | { 34 | return trans('self-diagnosis::checks.php_extensions_are_installed.name'); 35 | } 36 | 37 | /** 38 | * The error message to display in case the check does not pass. 39 | * 40 | * @param array $config 41 | * @return string 42 | */ 43 | public function message(array $config): string 44 | { 45 | return trans('self-diagnosis::checks.php_extensions_are_installed.message', [ 46 | 'extensions' => $this->extensions->implode(PHP_EOL), 47 | ]); 48 | } 49 | 50 | /** 51 | * Perform the actual verification of this check. 52 | * 53 | * @param array $config 54 | * @return bool 55 | */ 56 | public function check(array $config): bool 57 | { 58 | $this->extensions = Collection::make(Arr::get($config, 'extensions', [])); 59 | if (Arr::get($config, 'include_composer_extensions', false)) { 60 | $this->extensions = $this->extensions->merge($this->getExtensionsRequiredInComposerFile()); 61 | $this->extensions = $this->extensions->unique(); 62 | } 63 | $this->extensions = $this->extensions->reject(function ($ext) { 64 | return extension_loaded($ext); 65 | }); 66 | 67 | return $this->extensions->isEmpty(); 68 | } 69 | 70 | /** 71 | * @return array 72 | * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException 73 | */ 74 | public function getExtensionsRequiredInComposerFile() 75 | { 76 | $installedPackages = json_decode($this->filesystem->get(base_path('vendor/composer/installed.json')), true); 77 | 78 | $extensions = []; 79 | foreach ($installedPackages as $installedPackage) { 80 | $filtered = Arr::where(array_keys(Arr::get($installedPackage, 'require', [])), function ($value, $key) { 81 | return Str::startsWith($value, self::EXT); 82 | }); 83 | foreach ($filtered as $extension) { 84 | $extensions[] = Str::replaceFirst(self::EXT, '', $extension); 85 | } 86 | } 87 | return array_unique($extensions); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/Checks/RedisCanBeAccessed.php: -------------------------------------------------------------------------------- 1 | testConnection()) { 34 | $this->message = trans('self-diagnosis::checks.redis_can_be_accessed.message.default_cache'); 35 | return false; 36 | } 37 | } 38 | 39 | foreach (Arr::get($config, 'connections', []) as $connection) { 40 | if (!$this->testConnection($connection)) { 41 | $this->message = trans('self-diagnosis::checks.redis_can_be_accessed.message.named_cache', [ 42 | 'name' => $connection, 43 | ]); 44 | return false; 45 | } 46 | } 47 | } catch (\Exception $e) { 48 | $this->message = $e->getMessage(); 49 | return false; 50 | } 51 | 52 | return true; 53 | } 54 | 55 | /** 56 | * The error message to display in case the check does not pass. 57 | * 58 | * @param array $config 59 | * @return string 60 | */ 61 | public function message(array $config): string 62 | { 63 | return trans('self-diagnosis::checks.redis_can_be_accessed.message.not_accessible', [ 64 | 'error' => $this->message, 65 | ]); 66 | } 67 | 68 | /** 69 | * Tests a redis connection and returns whether the connection is opened or not. 70 | * 71 | * @param string|null $name 72 | * @return bool 73 | */ 74 | private function testConnection(string $name = null): bool 75 | { 76 | $connection = Redis::connection($name); 77 | $connection->connect(); 78 | return $connection->isConnected(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Checks/RoutesAreCached.php: -------------------------------------------------------------------------------- 1 | routesAreCached() === true; 28 | } 29 | 30 | /** 31 | * The error message to display in case the check does not pass. 32 | * 33 | * @param array $config 34 | * @return string 35 | */ 36 | public function message(array $config): string 37 | { 38 | return trans('self-diagnosis::checks.routes_are_cached.message'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Checks/RoutesAreNotCached.php: -------------------------------------------------------------------------------- 1 | routesAreCached() === false; 28 | } 29 | 30 | /** 31 | * The error message to display in case the check does not pass. 32 | * 33 | * @param array $config 34 | * @return string 35 | */ 36 | public function message(array $config): string 37 | { 38 | return trans('self-diagnosis::checks.routes_are_not_cached.message'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Checks/ServersArePingable.php: -------------------------------------------------------------------------------- 1 | notReachableServers = $this->parseConfiguredServers(Arr::get($config, 'servers', [])); 39 | if ($this->notReachableServers->isEmpty()) { 40 | return true; 41 | } 42 | 43 | $this->notReachableServers = $this->notReachableServers->reject(function (Server $server) { 44 | $ping = new Ping($server->getHost()); 45 | $ping->setPort($server->getPort()); 46 | $ping->setTimeout($server->getTimeout()); 47 | 48 | if ($ping->getPort() === null) { 49 | $latency = $ping->ping('exec'); 50 | } else { 51 | $latency = $ping->ping('fsockopen'); 52 | } 53 | 54 | return $latency !== false; 55 | }); 56 | 57 | return $this->notReachableServers->isEmpty(); 58 | } 59 | 60 | /** 61 | * The error message to display in case the check does not pass. 62 | * 63 | * @param array $config 64 | * @return string 65 | */ 66 | public function message(array $config): string 67 | { 68 | return $this->notReachableServers->map(function (Server $server) { 69 | return trans('self-diagnosis::checks.servers_are_pingable.message', [ 70 | 'host' => $server->getHost(), 71 | 'port' => $server->getPort() ?? 'n/a', 72 | 'timeout' => $server->getTimeout(), 73 | ]); 74 | })->implode(PHP_EOL); 75 | } 76 | 77 | /** 78 | * Parses an array of servers which can be given in different formats. 79 | * Unifies the format for the resulting collection. 80 | * 81 | * @param array $servers 82 | * @return Collection 83 | * @throws InvalidConfigurationException 84 | */ 85 | private function parseConfiguredServers(array $servers): Collection 86 | { 87 | $result = new Collection(); 88 | 89 | foreach ($servers as $server) { 90 | if (is_array($server)) { 91 | if (!empty(Arr::except($server, ['host', 'port', 'timeout']))) { 92 | throw new InvalidConfigurationException('Servers in array notation may only contain a host, port and timeout parameter.'); 93 | } 94 | if (!Arr::has($server, 'host')) { 95 | throw new InvalidConfigurationException('For servers in array notation, the host parameter is required.'); 96 | } 97 | 98 | $host = Arr::get($server, 'host'); 99 | $port = Arr::get($server, 'port'); 100 | $timeout = Arr::get($server, 'timeout', self::DEFAULT_TIMEOUT); 101 | 102 | $result->push(new Server($host, $port, $timeout)); 103 | } else if (is_string($server)) { 104 | $result->push(new Server($server, null, self::DEFAULT_TIMEOUT)); 105 | } else { 106 | throw new InvalidConfigurationException('The server configuration may only contain arrays or strings.'); 107 | } 108 | } 109 | 110 | return $result; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Checks/StorageDirectoryIsLinked.php: -------------------------------------------------------------------------------- 1 | filesystem = $filesystem; 15 | } 16 | 17 | /** 18 | * The name of the check. 19 | * 20 | * @param array $config 21 | * @return string 22 | */ 23 | public function name(array $config): string 24 | { 25 | return trans('self-diagnosis::checks.storage_directory_is_linked.name'); 26 | } 27 | 28 | /** 29 | * The error message to display in case the check does not pass. 30 | * 31 | * @param array $config 32 | * @return string 33 | */ 34 | public function message(array $config): string 35 | { 36 | return trans('self-diagnosis::checks.storage_directory_is_linked.message'); 37 | } 38 | 39 | /** 40 | * Perform the actual verification of this check. 41 | * 42 | * @param array $config 43 | * @return bool 44 | */ 45 | public function check(array $config): bool 46 | { 47 | try { 48 | return $this->filesystem->isDirectory(public_path('storage')); 49 | } catch (\Exception $e) { 50 | return false; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Checks/SupervisorProgramsAreRunning.php: -------------------------------------------------------------------------------- 1 | systemFunctions = $systemFunctions; 31 | } 32 | 33 | /** 34 | * The name of the check. 35 | * 36 | * @param array $config 37 | * @return string 38 | */ 39 | public function name(array $config): string 40 | { 41 | return trans('self-diagnosis::checks.supervisor_programs_are_running.name'); 42 | } 43 | 44 | /** 45 | * Perform the actual verification of this check. 46 | * 47 | * @param array $config 48 | * @return bool 49 | */ 50 | public function check(array $config): bool 51 | { 52 | $this->notRunningPrograms = new Collection(Arr::get($config, 'programs', [])); 53 | if ($this->notRunningPrograms->isEmpty()) { 54 | return true; 55 | } 56 | 57 | if (!$this->systemFunctions->isFunctionAvailable('shell_exec')) { 58 | $this->message = trans('self-diagnosis::checks.supervisor_programs_are_running.message.shell_exec_not_available'); 59 | return false; 60 | } 61 | 62 | if ($this->systemFunctions->isWindowsOperatingSystem()) { 63 | $this->message = trans('self-diagnosis::checks.supervisor_programs_are_running.message.cannot_run_on_windows'); 64 | return false; 65 | } 66 | 67 | $programs = $this->systemFunctions->callShellExec('supervisorctl status'); 68 | if ($programs === null || $programs === '') { 69 | $this->message = trans('self-diagnosis::checks.supervisor_programs_are_running.message.supervisor_command_not_available'); 70 | return false; 71 | } 72 | 73 | $restartedWithin = Arr::get($config, 'restarted_within', 0); 74 | $programs = explode("\n" , $programs); 75 | foreach ($programs as $program) { 76 | /* 77 | * Capture groups of regex: 78 | * (program name) (process id) (uptime hours) (minutes) (seconds) 79 | */ 80 | $isMatch = preg_match(self::REGEX_SUPERVISORCTL_STATUS, trim($program), $matches); 81 | if ($isMatch) { 82 | if ($restartedWithin > 0) { 83 | $totalSeconds = $matches[3] * 3600 + $matches[4] * 60 + $matches[5]; 84 | if ($totalSeconds > $restartedWithin) { 85 | continue; 86 | } 87 | } 88 | 89 | $this->notRunningPrograms = $this->notRunningPrograms->reject(function ($item) use ($matches) { 90 | return $item === $matches[1]; 91 | }); 92 | } 93 | } 94 | 95 | return $this->notRunningPrograms->isEmpty(); 96 | } 97 | 98 | /** 99 | * The error message to display in case the check does not pass. 100 | * 101 | * @param array $config 102 | * @return string 103 | */ 104 | public function message(array $config): string 105 | { 106 | if ($this->message) { 107 | return $this->message; 108 | } 109 | 110 | return trans('self-diagnosis::checks.supervisor_programs_are_running.message.not_running_programs', [ 111 | 'programs' => $this->notRunningPrograms->implode(PHP_EOL), 112 | ]); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Checks/UsedEnvironmentVariablesAreDefined.php: -------------------------------------------------------------------------------- 1 | $this->amount, 55 | 'undefined' => implode(PHP_EOL, $this->undefined), 56 | ]); 57 | } 58 | 59 | /** 60 | * Perform the actual verification of this check. 61 | * 62 | * @param array $config 63 | * @return bool 64 | * @throws \Exception 65 | */ 66 | public function check(array $config): bool 67 | { 68 | $paths = Collection::make(Arr::get($config, 'directories', [])); 69 | 70 | foreach ($paths as $path) { 71 | $files = $this->recursiveDirSearch($path, '/.*?.php/'); 72 | 73 | foreach ($files as $file) { 74 | preg_match_all( 75 | '# env\((.*?)\)| getenv\((.*?)\)#', 76 | str_replace(["\n", "\r"], '', file_get_contents($file)), 77 | $values 78 | ); 79 | 80 | $values = array_filter( 81 | array_merge($values[1], $values[2]) 82 | ); 83 | 84 | foreach ($values as $value) { 85 | $result = $this->getResult( 86 | explode(',', str_replace(["'", '"', ' '], '', $value)) 87 | ); 88 | 89 | if (!$result) { 90 | continue; 91 | } 92 | 93 | $this->storeResult($result); 94 | } 95 | } 96 | } 97 | 98 | return $this->amount === 0; 99 | } 100 | 101 | /** 102 | * Get result based on comma separated env() or getenv() parameters 103 | * 104 | * @param array $values 105 | * @return object|bool 106 | */ 107 | private function getResult(array $values) 108 | { 109 | $envVar = $values[0]; 110 | 111 | if (in_array($envVar, $this->processed, true)) { 112 | return false; 113 | } 114 | 115 | $this->processed[] = $envVar; 116 | 117 | return (object)[ 118 | 'envVar' => $envVar, 119 | 'hasValue' => env($envVar) !== null, 120 | 'hasDefault' => isset($values[1]), 121 | ]; 122 | } 123 | 124 | /** 125 | * Store result based on getResult's return value 126 | * 127 | * @param $result 128 | */ 129 | private function storeResult($result) 130 | { 131 | if (!$result->hasValue && !$result->hasDefault) { 132 | $this->undefined[] = $result->envVar; 133 | $this->amount++; 134 | } 135 | } 136 | 137 | /** 138 | * Recursively search folder(s) for files matching pattern 139 | * 140 | * @param string $folder 141 | * @param string $pattern 142 | * @return array 143 | */ 144 | private function recursiveDirSearch(string $folder, string $pattern): array 145 | { 146 | if (!file_exists($folder)) { 147 | return []; 148 | } 149 | 150 | $files = new RegexIterator( 151 | new RecursiveIteratorIterator( 152 | new RecursiveDirectoryIterator($folder) 153 | ), 154 | $pattern, RegexIterator::GET_MATCH 155 | ); 156 | 157 | $list = [[]]; 158 | 159 | foreach ($files as $file) { 160 | $list[] = $file; 161 | } 162 | 163 | $list = array_merge(...$list); 164 | 165 | return $list; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/Composer.php: -------------------------------------------------------------------------------- 1 | findComposer(); 10 | 11 | $command = array_merge( 12 | (array) $composer, 13 | ['install', '--dry-run'], 14 | array_filter(array_map('trim', explode(' ', $options))) 15 | ); 16 | 17 | if (is_array($composer)) { 18 | $process = $this->getProcess($command); 19 | } else { 20 | $process = $this->getProcess(); 21 | $process->setCommandLine(trim(implode(' ', $command))); 22 | } 23 | 24 | $process->run(); 25 | 26 | return $process->getOutput() . $process->getErrorOutput(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/Exceptions/InvalidConfigurationException.php: -------------------------------------------------------------------------------- 1 | runChecks(config('self-diagnosis.checks', []), trans('self-diagnosis::commands.self_diagnosis.common_checks')); 29 | 30 | $environment = $this->argument('environment') ?: app()->environment(); 31 | $environmentChecks = config('self-diagnosis.environment_checks.' . $environment, []); 32 | 33 | if (empty($environmentChecks) && array_key_exists($environment, config('self-diagnosis.environment_aliases'))) { 34 | $environment = config('self-diagnosis.environment_aliases.' . $environment); 35 | $environmentChecks = config('self-diagnosis.environment_checks.' . $environment, []); 36 | } 37 | 38 | $this->runChecks($environmentChecks, trans('self-diagnosis::commands.self_diagnosis.environment_specific_checks', ['environment' => $environment])); 39 | 40 | if (count($this->messages)) { 41 | $this->error(trans('self-diagnosis::commands.self_diagnosis.failed_checks')); 42 | 43 | foreach ($this->messages as $message) { 44 | $this->output->writeln(''.$message.''); 45 | $this->output->writeln(''); 46 | } 47 | return 1; // Any other return code then 0 means exit with error 48 | } 49 | $this->info(trans('self-diagnosis::commands.self_diagnosis.success')); 50 | return 0; 51 | } 52 | 53 | protected function runChecks(array $checks, string $title) 54 | { 55 | $max = count($checks); 56 | $current = 1; 57 | 58 | $this->output->writeln('|-------------------------------------'); 59 | $this->output->writeln('| '.$title); 60 | $this->output->writeln('|-------------------------------------'); 61 | 62 | foreach ($checks as $check => $config) { 63 | if (is_numeric($check)) { 64 | $check = $config; 65 | $config = []; 66 | } 67 | 68 | $checkClass = app($check); 69 | 70 | $this->output->write(trans('self-diagnosis::commands.self_diagnosis.running_check', [ 71 | 'current' => $current, 72 | 'max' => $max, 73 | 'name' => $checkClass->name($config), 74 | ])); 75 | 76 | $this->runCheck($checkClass, $config); 77 | 78 | $current++; 79 | } 80 | 81 | $this->output->writeln(''); 82 | } 83 | 84 | protected function runCheck(Check $check, array $config) 85 | { 86 | if ($check->check($config)) { 87 | $this->output->write(''); 88 | } else { 89 | $this->output->write(''); 90 | 91 | $this->messages[] = $check->message($config); 92 | } 93 | 94 | $this->output->write(PHP_EOL); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/SelfDiagnosisServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__.'/../translations', 'self-diagnosis'); 15 | 16 | if ($this->app->runningInConsole()) { 17 | 18 | $this->publishes([ 19 | __DIR__.'/../translations' => resource_path('lang/vendor/self-diagnosis'), 20 | ], 'translations'); 21 | 22 | $this->publishes([ 23 | __DIR__.'/../config/config.php' => config_path('self-diagnosis.php'), 24 | ], 'config'); 25 | } 26 | } 27 | 28 | /** 29 | * Register the application services. 30 | */ 31 | public function register() 32 | { 33 | $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'self-diagnosis'); 34 | 35 | $this->app->bind('command.selfdiagnosis', SelfDiagnosisCommand::class); 36 | 37 | $this->commands([ 38 | 'command.selfdiagnosis', 39 | ]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Server.php: -------------------------------------------------------------------------------- 1 | host = $host; 24 | $this->port = $port; 25 | $this->timeout = $timeout; 26 | } 27 | 28 | public function getHost(): string 29 | { 30 | return $this->host; 31 | } 32 | 33 | public function getPort(): ?int 34 | { 35 | return $this->port; 36 | } 37 | 38 | public function getTimeout(): int 39 | { 40 | return $this->timeout; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/SystemFunctions.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'message' => 'Der Anwendungsschlüssel ist nicht gesetzt. Nutze "php artisan key:generate", um einen zu erstellen und zu setzen.', 6 | 'name' => 'Anwendungsschlüssel ist gesetzt', 7 | ], 8 | 'composer_with_dev_dependencies_is_up_to_date' => [ 9 | 'message' => 'Die Composer Abhängigkeiten sind nicht aktuell. Nutze "composer install", um diese zu aktualisieren. :more', 10 | 'name' => 'Composer Abhängigkeiten (inkl. dev) sind aktuell', 11 | ], 12 | 'composer_without_dev_dependencies_is_up_to_date' => [ 13 | 'message' => 'Die Composer Abhängigkeiten sind nicht aktuell. Nutze "composer install", um diese zu aktualisieren. :more', 14 | 'name' => 'Composer Abhängigkeiten (ohne dev) sind aktuell', 15 | ], 16 | 'configuration_is_cached' => [ 17 | 'message' => 'Die Konfiguration sollte für bessere Performance gecached sein im Produktivbetrieb. Nutze "php artisan config:cache", um den Konfigurations-Cache zu erstellen.', 18 | 'name' => 'Konfiguration ist gecached', 19 | ], 20 | 'configuration_is_not_cached' => [ 21 | 'message' => 'Die Konfiguration sollte während der Entwicklung nicht gecached sein. Nutze "php artisan config:clear", um den Konfigurations-Cache zu leeren.', 22 | 'name' => 'Konfiguration ist nicht gecached', 23 | ], 24 | 'correct_php_version_is_installed' => [ 25 | 'message' => 'Die benötigte PHP Version ist nicht installiert.' . PHP_EOL . 'Benötigt: :required' . PHP_EOL . 'In Verwendung: :used', 26 | 'name' => 'Die richtige PHP Version ist installiert', 27 | ], 28 | 'database_can_be_accessed' => [ 29 | 'message' => 'Auf die Datenbank kann nicht zugegriffen werden: :error', 30 | 'name' => 'Die Datenbank ist erreichbar', 31 | ], 32 | 'debug_mode_is_not_enabled' => [ 33 | 'message' => 'Der Debugging-Modus sollte im Produktivbetrieb nicht genutzt werden. Setze "APP_DEBUG" in der .env Datei auf "false".', 34 | 'name' => 'Der Debugging-Modus ist deaktiviert', 35 | ], 36 | 'directories_have_correct_permissions' => [ 37 | 'message' => 'Folgende Verzeichnisse sind nicht beschreibbar:' . PHP_EOL .':directories', 38 | 'name' => 'Alle Verzeichnisse haben die richtigen Berechtigungen', 39 | ], 40 | 'env_file_exists' => [ 41 | 'message' => 'Die .env Datei existiert nicht. Bitte kopiere die Datei .env.example zu .env und passe diese entsprechend an.', 42 | 'name' => 'Die Umgebungsvariablendatei existiert', 43 | ], 44 | 'example_environment_variables_are_set' => [ 45 | 'message' => 'Folgende Umgebungsvariablen fehlen im .env Umgebungsfile, sind aber in .env.example definiert:' . PHP_EOL . ':variables', 46 | 'name' => 'Die Beispiel-Umgebungsvariablen sind gesetzt', 47 | ], 48 | 'locales_are_installed' => [ 49 | 'message' => [ 50 | 'cannot_run_on_windows' => 'Dieser Check kann unter Windows nicht ausgeführt werden..', 51 | 'locale_command_not_available' => 'Der Befehl "locale -a" ist auf dem aktuellen System nicht verfügbar.', 52 | 'missing_locales' => 'Folgende Sprachumgebungen (locales) fehlen:' . PHP_EOL . ':locales', 53 | 'shell_exec_not_available' => 'Die Funktion "shell_exec" ist entweder nicht definiert oder deaktiviert, daher können die Sprachumgebungen nicht abgefragt werden.', 54 | ], 55 | 'name' => 'Benötigte Sprachumgebungen sind installiert', 56 | ], 57 | 'maintenance_mode_not_enabled' => [ 58 | 'message' => 'Der Wartungsmodus ist noch aktiv. Deaktiviere ihn mit "php artisan up".', 59 | 'name' => 'Wartungsmodus ist nicht aktiv', 60 | ], 61 | 'migrations_are_up_to_date' => [ 62 | 'message' => [ 63 | 'need_to_migrate' => 'Die Datenbank muss aktualisiert werden. Nutze "php artisan migrate", um die Migrationen einzuspielen.', 64 | 'unable_to_check' => 'Die Migrationen konnten nicht geprüft werden: :reason', 65 | ], 66 | 'name' => 'Die Migrationen sind aktuell', 67 | ], 68 | 'php_extensions_are_disabled' => [ 69 | 'message' => 'Die folgenden Erweiterungen sind noch immer aktiviert:' . PHP_EOL . ':extensions', 70 | 'name' => 'Unerwünschte PHP Erweiterungen sind deaktiviert', 71 | ], 72 | 'php_extensions_are_installed' => [ 73 | 'message' => 'Die folgenden Erweiterungen fehlen:' . PHP_EOL . ':extensions', 74 | 'name' => 'Die benötigten PHP Erweiterungen sind installiert', 75 | ], 76 | 'redis_can_be_accessed' => [ 77 | 'message' => [ 78 | 'not_accessible' => 'Auf den Redis Cache kann nicht zugegriffen werden: :error', 79 | 'default_cache' => 'Der Standard-Cache ist nicht erreichbar.', 80 | 'named_cache' => 'Der Cache :name ist nicht erreichbar.', 81 | ], 82 | 'name' => 'Der Redis Cache ist erreichbar', 83 | ], 84 | 'routes_are_cached' => [ 85 | 'message' => 'Die Routen sollten für bessere Performance gecached sein im Produktivbetrieb. Nutze "php artisan route:cache", um den Routen-Cache zu erstellen.', 86 | 'name' => 'Routen sind gecached', 87 | ], 88 | 'routes_are_not_cached' => [ 89 | 'message' => 'Die Routen sollten während der Entwicklung nicht gecached sein. Nutze "php artisan route:clear", um den Routen-Cache zu leeren.', 90 | 'name' => 'Routen sind nicht gecached', 91 | ], 92 | 'servers_are_pingable' => [ 93 | 'message' => "Der Server ':host' (Port: :port) ist nicht erreichbar (Timeout nach :timeout Sekunden).", 94 | 'name' => 'Benötigte Server sind pingbar', 95 | ], 96 | 'storage_directory_is_linked' => [ 97 | 'message' => 'Das Speicherverzeichnis ist nicht verlinkt. Nutze "php artisan storage:link", um eine symbolische Verknüpfung zu erstellen.', 98 | 'name' => 'Das Speicherverzeichnis ist verlinkt', 99 | ], 100 | 'supervisor_programs_are_running' => [ 101 | 'message' => [ 102 | 'cannot_run_on_windows' => 'Dieser Check kann unter Windows nicht ausgeführt werden..', 103 | 'not_running_programs' => 'Die folgenden Programme laufen nicht oder benötigen einen Neustart:' . PHP_EOL . ':programs', 104 | 'shell_exec_not_available' => 'Die Funktion "shell_exec" ist entweder nicht definiert oder deaktiviert, daher können die laufenden Programme nicht abgefragt werden.', 105 | 'supervisor_command_not_available' => 'Der Befehl "supervisorctl" ist auf dem aktuellen System nicht verfügbar.', 106 | ], 107 | 'name' => 'Alle supervisor Programme sind in Betrieb', 108 | ], 109 | 'used_env_variables_are_defined' => [ 110 | 'message' => ':amount verwendete Umgebungsvariablen sind undefiniert:'.PHP_EOL.':undefined', 111 | 'name' => 'Alle verwendete Umgebungsvariablen sind definiert.', 112 | ], 113 | ]; 114 | -------------------------------------------------------------------------------- /translations/de/commands.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'common_checks' => 'Allgemeine Überprüfungen', 6 | 'environment_specific_checks' => 'Umgebungsspezifische Überprüfungen (:environment)', 7 | 'failed_checks' => 'Folgende Überprüfungen sind fehlgeschlagen:', 8 | 'running_check' => 'Überprüfung :current/:max: :name... ', 9 | 'success' => 'Gute Arbeit, sieht so aus, als wäre alles richtig eingestellt!', 10 | ], 11 | ]; 12 | -------------------------------------------------------------------------------- /translations/en/checks.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'message' => 'The application key is not set. Call "php artisan key:generate" to create and set one.', 6 | 'name' => 'App key is set', 7 | ], 8 | 'composer_with_dev_dependencies_is_up_to_date' => [ 9 | 'message' => 'Your composer dependencies are not up to date. Call "composer install" to update them. :more', 10 | 'name' => 'Composer dependencies (including dev) are up to date', 11 | ], 12 | 'composer_without_dev_dependencies_is_up_to_date' => [ 13 | 'message' => 'Your composer dependencies are not up to date. Call "composer install" to update them. :more', 14 | 'name' => 'Composer dependencies (without dev) are up to date', 15 | ], 16 | 'configuration_is_cached' => [ 17 | 'message' => 'Your configuration should be cached in production for better performance. Call "php artisan config:cache" to create the configuration cache.', 18 | 'name' => 'Configuration is cached', 19 | ], 20 | 'configuration_is_not_cached' => [ 21 | 'message' => 'Your configuration files should not be cached during development. Call "php artisan config:clear" to clear the configuration cache.', 22 | 'name' => 'Configuration is not cached', 23 | ], 24 | 'correct_php_version_is_installed' => [ 25 | 'message' => 'You do not have the required PHP version installed.' . PHP_EOL . 'Required: :required' . PHP_EOL . 'Used: :used', 26 | 'name' => 'The correct PHP version is installed', 27 | ], 28 | 'database_can_be_accessed' => [ 29 | 'message' => 'The database can not be accessed: :error', 30 | 'name' => 'The database can be accessed', 31 | ], 32 | 'debug_mode_is_not_enabled' => [ 33 | 'message' => 'You should not use debug mode in production. Set "APP_DEBUG" in the .env file to "false".', 34 | 'name' => 'Debug mode is not enabled', 35 | ], 36 | 'directories_have_correct_permissions' => [ 37 | 'message' => 'The following directories are not writable:' . PHP_EOL .':directories', 38 | 'name' => 'All directories have the correct permissions', 39 | ], 40 | 'env_file_exists' => [ 41 | 'message' => 'The .env file does not exist. Please copy your .env.example file as .env and adjust accordingly.', 42 | 'name' => 'The environment file exists', 43 | ], 44 | 'example_environment_variables_are_set' => [ 45 | 'message' => 'These environment variables are missing in your .env file, but are defined in your .env.example:' . PHP_EOL . ':variables', 46 | 'name' => 'The example environment variables are set', 47 | ], 48 | 'example_environment_variables_are_up_to_date' => [ 49 | 'message' => 'These environment variables are defined in your .env file, but are missing in your .env.example:' . PHP_EOL . ':variables', 50 | 'name' => 'The example environment variables are up-to-date', 51 | ], 52 | 'horizon_is_running' => [ 53 | 'message' => [ 54 | 'not_running' => 'Horizon is not running.', 55 | 'unable_to_check' => 'Unable to check for horizon: :reason', 56 | ], 57 | 'name' => 'Horizon is running', 58 | ], 59 | 'locales_are_installed' => [ 60 | 'message' => [ 61 | 'cannot_run_on_windows' => 'This check cannot be run on Windows.', 62 | 'locale_command_not_available' => 'The "locale -a" command is not available on the current OS.', 63 | 'missing_locales' => 'The following locales are missing:' . PHP_EOL . ':locales', 64 | 'shell_exec_not_available' => 'The function "shell_exec" is not defined or disabled, so we cannot check the locales.', 65 | ], 66 | 'name' => 'Required locales are installed', 67 | ], 68 | 'maintenance_mode_not_enabled' => [ 69 | 'message' => 'Maintenance mode is still enabled. Disable it with "php artisan up".', 70 | 'name' => 'Maintenance mode is not enabled', 71 | ], 72 | 'migrations_are_up_to_date' => [ 73 | 'message' => [ 74 | 'need_to_migrate' => 'You need to update your database. Call "php artisan migrate" to run migrations.', 75 | 'unable_to_check' => 'Unable to check for migrations: :reason', 76 | ], 77 | 'name' => 'The migrations are up to date', 78 | ], 79 | 'php_extensions_are_disabled' => [ 80 | 'message' => 'The following extensions are still enabled:' . PHP_EOL . ':extensions', 81 | 'name' => 'Unwanted PHP extensions are disabled', 82 | ], 83 | 'php_extensions_are_installed' => [ 84 | 'message' => 'The following extensions are missing:' . PHP_EOL . ':extensions', 85 | 'name' => 'The required PHP extensions are installed', 86 | ], 87 | 'redis_can_be_accessed' => [ 88 | 'message' => [ 89 | 'not_accessible' => 'The Redis cache can not be accessed: :error', 90 | 'default_cache' => 'The default cache is not reachable.', 91 | 'named_cache' => 'The named cache :name is not reachable.', 92 | ], 93 | 'name' => 'The Redis cache can be accessed', 94 | ], 95 | 'routes_are_cached' => [ 96 | 'message' => 'Your routes should be cached in production for better performance. Call "php artisan route:cache" to create the route cache.', 97 | 'name' => 'Routes are cached', 98 | ], 99 | 'routes_are_not_cached' => [ 100 | 'message' => 'Your routes should not be cached during development. Call "php artisan route:clear" to clear the route cache.', 101 | 'name' => 'Routes are not cached', 102 | ], 103 | 'servers_are_pingable' => [ 104 | 'message' => "The server ':host' (port: :port) is not reachable (timeout after :timeout seconds).", 105 | 'name' => 'Required servers are pingable', 106 | ], 107 | 'storage_directory_is_linked' => [ 108 | 'message' => 'The storage directory is not linked. Use "php artisan storage:link" to create a symbolic link.', 109 | 'name' => 'The storage directory is linked', 110 | ], 111 | 'supervisor_programs_are_running' => [ 112 | 'message' => [ 113 | 'cannot_run_on_windows' => 'This check cannot be run on Windows.', 114 | 'not_running_programs' => 'The following programs are not running or require a restart:' . PHP_EOL . ':programs', 115 | 'shell_exec_not_available' => 'The function "shell_exec" is not defined or disabled, so we cannot check the running programs.', 116 | 'supervisor_command_not_available' => 'The "supervisorctl" command is not available on the current OS.', 117 | ], 118 | 'name' => 'All supervisor programs are running', 119 | ], 120 | 'used_env_variables_are_defined' => [ 121 | 'message' => ':amount used environmental variables are undefined:' . PHP_EOL . ':undefined', 122 | 'name' => 'All used environment variables are defined', 123 | ], 124 | ]; 125 | -------------------------------------------------------------------------------- /translations/en/commands.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'common_checks' => 'Common Checks', 6 | 'environment_specific_checks' => 'Environment Specific Checks (:environment)', 7 | 'failed_checks' => 'The following checks failed:', 8 | 'running_check' => 'Running check :current/:max: :name... ', 9 | 'success' => 'Good job, looks like you are all set up!', 10 | ], 11 | ]; 12 | -------------------------------------------------------------------------------- /translations/id/checks.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'message' => 'Kunci aplikasi belum disetel. Panggil "php artisan key:generate" untuk membuat dan mengatur kunci', 6 | 'name' => 'Kunci aplikasi sudah diatur', 7 | ], 8 | 'composer_with_dev_dependencies_is_up_to_date' => [ 9 | 'message' => 'Dependency composer Anda tidak terbaru. Panggil "composer install" untuk memperbaruinya. 10 | :more', 11 | 'name' => 'Dependency composer (termasuk dev) sudah terbaru', 12 | ], 13 | 'composer_without_dev_dependencies_is_up_to_date' => [ 14 | 'message' => 'Dependency composer Anda tidak terbaru. Panggil "composer install" untuk memperbaruinya. 15 | :more', 16 | 'name' => 'Dependency composer (tidak termasuk dev) sudah terbaru', 17 | ], 18 | 'configuration_is_cached' => [ 19 | 'message' => 'Konfigurasi Anda harus di-cache dalam mode production untuk kinerja yang lebih baik. Panggil "php artisan config:cache" untuk membuat cache konfigurasi.', 20 | 'name' => 'Konfigurasi sudah di-cache', 21 | ], 22 | 'configuration_is_not_cached' => [ 23 | 'message' => 'Konfigurasi Anda tidak harus di-cache dalam mode development. Panggil "php artisan config:clear" untuk menghapus cache konfigurasi.', 24 | 'name' => 'Konfigurasi belum di-cache', 25 | ], 26 | 'correct_php_version_is_installed' => [ 27 | 'message' => 'Anda tidak memiliki versi PHP yang diperlukan untuk diinstal.' . PHP_EOL . 'Yang dibutuhkan: 28 | :required' . PHP_EOL . 'Yang dipakai: :used', 29 | 'name' => 'Versi PHP benar yang diinstall', 30 | ], 31 | 'database_can_be_accessed' => [ 32 | 'message' => 'Database tidak dapat diakses: :error', 33 | 'name' => 'Database dapat diakses', 34 | ], 35 | 'debug_mode_is_not_enabled' => [ 36 | 'message' => 'Anda seharusnya tidak menggunakan mode debug dalam mode production. Setel "APP_DEBUG" di file .env ke "false".', 37 | 'name' => 'Mode debug tidak diaktifkan', 38 | ], 39 | 'directories_have_correct_permissions' => [ 40 | 'message' => 'Direktori berikut tidak dapat ditulisi:' . PHP_EOL .':directories', 41 | 'name' => 'Semua direktori memiliki izin yang benar', 42 | ], 43 | 'env_file_exists' => [ 44 | 'message' => 'File .env tidak ada. Harap salin file .env.example sebagai .env dan sesuaikan sesuai kebutuhan.', 45 | 'name' => 'File environment ada', 46 | ], 47 | 'example_environment_variables_are_set' => [ 48 | 'message' => 'Variabel environment ini tidak ada dalam file .env Anda, tetapi didefinisikan dalam .env.example:'. PHP_EOL. ': variables', 49 | 'name' => 'Contoh environment sudah ditetapkan', 50 | ], 51 | 'example_environment_variables_are_up_to_date' => [ 52 | 'message' => 'Variabel environment ini didefinisikan dalam file .env, tetapi tidak ada dalam .env.example Anda: '. PHP_EOL. ': variables', 53 | 'name' => 'Contoh environment sudah terbaru', 54 | ], 55 | 'horizon_is_running' => [ 56 | 'message' => [ 57 | 'not_running' => 'Horizon tidak berjalan.', 58 | 'unable_to_check' => 'Tidak dapat memeriksa horizon: :reason', 59 | ], 60 | 'name' => 'Horizon sudah berjalan', 61 | ], 62 | 'locales_are_installed' => [ 63 | 'message' => [ 64 | 'cannot_run_on_windows' => 'Pemeriksaan ini tidak dapat dijalankan di Windows.', 65 | 'locale_command_not_available' => 'Perintah "locale -a" tidak tersedia di OS ini.', 66 | 'missing_locales' => 'Terjemahan berikut tidak ada:' . PHP_EOL . ':locales', 67 | 'shell_exec_not_available' => 'Fungsi "shell_exec" tidak didefinisikan atau dinonaktifkan, jadi kami tidak dapat memeriksa terjemahan.', 68 | ], 69 | 'name' => 'Terjemahan yang diperlukan sudah diinstal', 70 | ], 71 | 'maintenance_mode_not_enabled' => [ 72 | 'message' => 'Mode maintenance masih diaktifkan. Nonaktifkan dengan "php artisan up".', 73 | 'name' => 'Mode maintenance tidak diaktifkan', 74 | ], 75 | 'migrations_are_up_to_date' => [ 76 | 'message' => [ 77 | 'need_to_migrate' => 'Anda perlu memperbarui database Anda. Panggil "php artisan migrate" untuk 78 | menjalankan migrasi', 79 | 'unable_to_check' => 'Tidak dapat memeriksa migrasi: :reason', 80 | ], 81 | 'name' => 'Migrasi sudah terbaru', 82 | ], 83 | 'php_extensions_are_disabled' => [ 84 | 'message' => 'Ekstensi berikut sudah aktif:' . PHP_EOL . ':extensions', 85 | 'name' => 'Ekstensi PHP yang tidak diinginkan dinonaktifkan', 86 | ], 87 | 'php_extensions_are_installed' => [ 88 | 'message' => 'Ekstensi berikut tidak ada:' . PHP_EOL . ':extensions', 89 | 'name' => 'Ekstensi PHP yang diperlukan telah diinstal', 90 | ], 91 | 'redis_can_be_accessed' => [ 92 | 'message' => [ 93 | 'not_accessible' => 'Cache Redis tidak dapat diakses: :error', 94 | 'default_cache' => 'Cache default tidak dapat dijangkau.', 95 | 'named_cache' => 'Cache bernama :name tidak dapat dijangkau.', 96 | ], 97 | 'name' => 'Cache Redis dapat diakses', 98 | ], 99 | 'routes_are_cached' => [ 100 | 'message' => 'Route Anda harus di-cache dalam mode production untuk kinerja yang lebih baik. Panggil "php artisan route:cache" untuk membuat cache route.', 101 | 'name' => 'Route sudah di-cache', 102 | ], 103 | 'routes_are_not_cached' => [ 104 | 'message' => 'Route Anda tidak harus di-cache dalam mode development. Panggil "php artisan route:clear" untuk menghapus cache route.', 105 | 'name' => 'Routes belum di-cache', 106 | ], 107 | 'servers_are_pingable' => [ 108 | 'message' => "Server ':host' (port: :port) tidak dapat dijangkau (batas waktu habis :timeout detik).", 109 | 'name' => 'Dibutuhkan server yang bisa ping', 110 | ], 111 | 'storage_directory_is_linked' => [ 112 | 'message' => 'Direktori penyimpanan tidak ditautkan. Gunakan "php artisan storage:link" untuk membuat tautan simbolis.', 113 | 'name' => 'Direktori penyimpanan terhubung', 114 | ], 115 | 'supervisor_programs_are_running' => [ 116 | 'message' => [ 117 | 'cannot_run_on_windows' => 'Pemeriksaan ini tidak dapat dijalankan di Windows.', 118 | 'not_running_programs' => 'Program-program berikut ini tidak berjalan atau membutuhkan restart:' . PHP_EOL . ':programs', 119 | 'shell_exec_not_available' => 'Fungsi "shell_exec" tidak didefinisikan atau dinonaktifkan, jadi kami tidak dapat memeriksa program yang sedang berjalan.', 120 | 'supervisor_command_not_available' => 'Perintah "supervisorctl" tidak tersedia di OS ini.', 121 | ], 122 | 'name' => 'Semua supervisor progam sudah berjalan', 123 | ], 124 | ]; 125 | -------------------------------------------------------------------------------- /translations/id/commands.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'common_checks' => 'Cek Umum', 6 | 'environment_specific_checks' => 'Pemeriksaan environment khusus (:environment)', 7 | 'failed_checks' => 'Pemeriksaan berikut gagal:', 8 | 'running_check' => 'Pemeriksaan berjalan :current/:max: :name... ', 9 | 'success' => 'Kerja bagus, semua sudah siap!', 10 | ], 11 | ]; 12 | --------------------------------------------------------------------------------