mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-19 19:24:03 +00:00
Rename Services/Installation to Services/Setup to match controllers
This commit is contained in:
342
app/Services/Setup/EnvironmentManager.php
Executable file
342
app/Services/Setup/EnvironmentManager.php
Executable file
@@ -0,0 +1,342 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Setup;
|
||||
|
||||
use App\Http\Requests\DatabaseEnvironmentRequest;
|
||||
use App\Http\Requests\DomainEnvironmentRequest;
|
||||
use App\Http\Requests\PDFConfigurationRequest;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class EnvironmentManager
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $envPath;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $delimiter = "\n";
|
||||
|
||||
/**
|
||||
* Set the .env and .env.example paths.
|
||||
*/
|
||||
public function __construct($path = null)
|
||||
{
|
||||
$this->envPath = base_path('.env');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the .env contents
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
private function getEnvContents()
|
||||
{
|
||||
return file_get_contents($this->envPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates .env file - inspired by Akaunting
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function updateEnv(array $data)
|
||||
{
|
||||
if (empty($data) || ! is_array($data) || ! is_file($this->envPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$env = $this->getEnvContents();
|
||||
|
||||
$env = explode($this->delimiter, $env);
|
||||
|
||||
foreach ($data as $data_key => $data_value) {
|
||||
$updated = false;
|
||||
|
||||
foreach ($env as $env_key => $env_value) {
|
||||
$entry = explode('=', $env_value, 2);
|
||||
|
||||
// Check if new or old key
|
||||
if ($entry[0] == $data_key) {
|
||||
$env[$env_key] = sprintf('%s=%s', $data_key, $this->encode($data_value));
|
||||
$updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Lets create if not available
|
||||
if (! $updated) {
|
||||
$env[] = $data_key.'='.$this->encode($data_value);
|
||||
}
|
||||
}
|
||||
|
||||
$env = implode($this->delimiter, $env);
|
||||
|
||||
file_put_contents(base_path('.env'), $env);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes value for .env
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
private function encode($str)
|
||||
{
|
||||
// Convert to string if not already
|
||||
$str = (string) $str;
|
||||
|
||||
// If the value is already properly quoted, return as is
|
||||
if (strlen($str) >= 2 && $str[0] === '"' && $str[strlen($str) - 1] === '"') {
|
||||
return $str;
|
||||
}
|
||||
|
||||
// Check if the value contains characters that need quoting
|
||||
// Using a character class regex to properly match special characters
|
||||
$specialChars = '\^\'£$%&*()}{@#~?><,|=\-_+¬!';
|
||||
$needsQuoting = (
|
||||
strpos($str, ' ') !== false ||
|
||||
preg_match('/['.preg_quote($specialChars, '/').']/', $str)
|
||||
);
|
||||
|
||||
if ($needsQuoting) {
|
||||
// Escape any existing double quotes in the string
|
||||
$str = str_replace('"', '\\"', $str);
|
||||
$str = '"'.$str.'"';
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the database content to the .env file.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function saveDatabaseVariables(DatabaseEnvironmentRequest $request)
|
||||
{
|
||||
$appUrl = $request->get('app_url');
|
||||
if ($appUrl !== config('app.url')) {
|
||||
config(['app.url' => $appUrl]);
|
||||
}
|
||||
[$sanctumDomain, $sessionDomain] = $this->getDomains(
|
||||
$request->getHttpHost()
|
||||
);
|
||||
$dbEnv = [
|
||||
'APP_URL' => $appUrl,
|
||||
'APP_LOCALE' => $request->get('app_locale'),
|
||||
'DB_CONNECTION' => $request->get('database_connection'),
|
||||
'SESSION_DOMAIN' => $sessionDomain,
|
||||
];
|
||||
if ($sanctumDomain !== null) {
|
||||
$dbEnv['SANCTUM_STATEFUL_DOMAINS'] = $sanctumDomain;
|
||||
}
|
||||
if ($dbEnv['DB_CONNECTION'] != 'sqlite') {
|
||||
if ($request->has('database_username') && $request->has('database_password')) {
|
||||
$dbEnv['DB_HOST'] = $request->get('database_hostname');
|
||||
$dbEnv['DB_PORT'] = $request->get('database_port');
|
||||
$dbEnv['DB_DATABASE'] = $request->get('database_name');
|
||||
$dbEnv['DB_USERNAME'] = $request->get('database_username');
|
||||
$dbEnv['DB_PASSWORD'] = $request->get('database_password');
|
||||
}
|
||||
} else {
|
||||
// Laravel 11 requires SQLite at least v3.35.0
|
||||
// https://laravel.com/docs/11.x/database#introduction
|
||||
if (extension_loaded('sqlite3') && class_exists('\SQLite3') && method_exists('\SQLite3', 'version')) {
|
||||
$version = \SQLite3::version();
|
||||
if (! empty($version['versionString']) && version_compare($version['versionString'], '3.35.0', '<')) {
|
||||
return [
|
||||
'error_message' => sprintf('The minimum SQLite version is %s. Your current SQLite version is %s which is not supported. Please upgrade SQLite and retry.', '3.35.0', $version['versionString']),
|
||||
];
|
||||
}
|
||||
} else {
|
||||
return [
|
||||
'error_message' => sprintf('SQLite3 is not present. Please install SQLite >=%s and retry.', '3.35.0'),
|
||||
];
|
||||
}
|
||||
$dbEnv['DB_DATABASE'] = $request->get('database_name');
|
||||
if (! empty($dbEnv['DB_DATABASE'])) {
|
||||
$sqlite_path = $dbEnv['DB_DATABASE'];
|
||||
} else {
|
||||
$sqlite_path = database_path('database.sqlite');
|
||||
}
|
||||
// Create empty SQLite database if it doesn't exist.
|
||||
if (! file_exists($sqlite_path)) {
|
||||
copy(database_path('stubs/sqlite.empty.db'), $sqlite_path);
|
||||
$dbEnv['DB_DATABASE'] = $sqlite_path;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$this->checkDatabaseConnection($request);
|
||||
if ($request->get('database_overwrite')) {
|
||||
Artisan::call('db:wipe --force');
|
||||
}
|
||||
if (\Schema::hasTable('users')) {
|
||||
return [
|
||||
'error' => 'database_should_be_empty',
|
||||
];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'error_message' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
$this->updateEnv($dbEnv);
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'error' => 'database_variables_save_error',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => 'database_variables_save_successfully',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PDO object if all ok.
|
||||
*
|
||||
* @return \Closure|\PDO
|
||||
*/
|
||||
private function checkDatabaseConnection(DatabaseEnvironmentRequest $request)
|
||||
{
|
||||
$connection = $request->get('database_connection');
|
||||
|
||||
$settings = config("database.connections.$connection");
|
||||
|
||||
$connectionArray = array_merge($settings, [
|
||||
'driver' => $connection,
|
||||
'database' => $request->get('database_name'),
|
||||
]);
|
||||
|
||||
if ($connection !== 'sqlite' && $request->has('database_username') && $request->has('database_password')) {
|
||||
$connectionArray = array_merge($connectionArray, [
|
||||
'username' => $request->get('database_username'),
|
||||
'password' => $request->get('database_password'),
|
||||
'host' => $request->get('database_hostname'),
|
||||
'port' => $request->get('database_port'),
|
||||
]);
|
||||
}
|
||||
|
||||
config([
|
||||
'database' => [
|
||||
'migrations' => 'migrations',
|
||||
'default' => $connection,
|
||||
'connections' => [$connection => $connectionArray],
|
||||
],
|
||||
]);
|
||||
|
||||
return DB::connection()->getPdo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the pdf generation content to the .env file.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function savePDFVariables(PDFConfigurationRequest $request)
|
||||
{
|
||||
$pdfEnv = $this->getPDFConfiguration($request);
|
||||
|
||||
try {
|
||||
|
||||
$this->updateEnv($pdfEnv);
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'error' => 'pdf_variables_save_error',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => 'pdf_variables_save_successfully',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the pdf configuration
|
||||
*
|
||||
* @param PDFConfigurationRequest $request
|
||||
* @return array
|
||||
*/
|
||||
private function getPDFConfiguration($request)
|
||||
{
|
||||
$pdfEnv = [];
|
||||
|
||||
$driver = $request->get('pdf_driver');
|
||||
|
||||
switch ($driver) {
|
||||
case 'dompdf':
|
||||
$pdfEnv = [
|
||||
'PDF_DRIVER' => $request->get('pdf_driver'),
|
||||
];
|
||||
break;
|
||||
case 'gotenberg':
|
||||
$pdfEnv = [
|
||||
'PDF_DRIVER' => $request->get('pdf_driver'),
|
||||
'GOTENBERG_HOST' => $request->get('gotenberg_host'),
|
||||
'GOTENBERG_MARGINS' => $request->get('gotenberg_margins'),
|
||||
'GOTENBERG_PAPERSIZE' => $request->get('gotenberg_papersize'),
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
return $pdfEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save sanctum stateful domain to the .env file.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function saveDomainVariables(DomainEnvironmentRequest $request)
|
||||
{
|
||||
try {
|
||||
[$sanctumDomain, $sessionDomain] = $this->getDomains(
|
||||
$request->get('app_domain')
|
||||
);
|
||||
$domainEnv = [
|
||||
'SESSION_DOMAIN' => $sessionDomain,
|
||||
];
|
||||
if ($sanctumDomain !== null) {
|
||||
$domainEnv['SANCTUM_STATEFUL_DOMAINS'] = $sanctumDomain;
|
||||
}
|
||||
$this->updateEnv($domainEnv);
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'error' => 'domain_verification_failed',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => 'domain_variable_save_successfully',
|
||||
];
|
||||
}
|
||||
|
||||
private function getDomains(string $requestDomain): array
|
||||
{
|
||||
$appUrl = config('app.url');
|
||||
|
||||
$port = parse_url($appUrl, PHP_URL_PORT);
|
||||
$currentDomain = parse_url($appUrl, PHP_URL_HOST).(
|
||||
$port ? ':'.$port : ''
|
||||
);
|
||||
|
||||
$requestHost = parse_url($requestDomain, PHP_URL_HOST) ?: $requestDomain;
|
||||
|
||||
$isSame = $currentDomain === $requestDomain;
|
||||
|
||||
return [
|
||||
$isSame && env('SANCTUM_STATEFUL_DOMAINS', false) === false ?
|
||||
null : $requestDomain,
|
||||
$isSame && env('SESSION_DOMAIN', false) === null ?
|
||||
null : $requestHost,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user