Skip to content

Commit 7232bba

Browse files
committed
Create new application class and improve application building process using bootstrappers
1 parent 124034c commit 7232bba

File tree

9 files changed

+489
-0
lines changed

9 files changed

+489
-0
lines changed

src/Application.php

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Longman\TelegramBot;
5+
6+
use Illuminate\Container\Container;
7+
use Illuminate\Support\Str;
8+
9+
use const DIRECTORY_SEPARATOR;
10+
11+
class Application extends Telegram
12+
{
13+
protected $basePath;
14+
protected $appPath;
15+
protected $environmentPath;
16+
protected $environmentFile = '.env';
17+
protected $hasBeenBootstrapped = false;
18+
19+
public function __construct(string $basePath = null)
20+
{
21+
if ($basePath) {
22+
$this->setBasePath($basePath);
23+
}
24+
25+
$this->registerBaseBindings();
26+
27+
$bootstrappers = [
28+
\Longman\TelegramBot\Bootstrap\LoadEnvironmentVariables::class,
29+
\Longman\TelegramBot\Bootstrap\SetupDatabase::class,
30+
\Longman\TelegramBot\Bootstrap\SetupMigrations::class,
31+
];
32+
33+
$this->bootstrapWith($bootstrappers);
34+
35+
parent::__construct(env('TG_API_KEY'), env('TG_BOT_NAME'));
36+
}
37+
38+
protected function registerBaseBindings(): void
39+
{
40+
static::setInstance($this);
41+
42+
$this->instance('app', $this);
43+
44+
$this->instance(Container::class, $this);
45+
}
46+
47+
public function bootstrapWith(array $bootstrappers)
48+
{
49+
$this->hasBeenBootstrapped = true;
50+
51+
foreach ($bootstrappers as $bootstrapper) {
52+
$this->make($bootstrapper)->bootstrap($this);
53+
}
54+
}
55+
56+
public function hasBeenBootstrapped(): bool
57+
{
58+
return $this->hasBeenBootstrapped;
59+
}
60+
61+
public function setBasePath($basePath): Application
62+
{
63+
$this->basePath = rtrim($basePath, '\/');
64+
65+
$this->bindPathsInContainer();
66+
67+
return $this;
68+
}
69+
70+
protected function bindPathsInContainer()
71+
{
72+
$this->instance('path', $this->path());
73+
$this->instance('path.base', $this->basePath());
74+
//$this->instance('path.config', $this->configPath());
75+
}
76+
77+
public function path(string $path = ''): string
78+
{
79+
$appPath = $this->appPath ?: $this->basePath . DIRECTORY_SEPARATOR . 'app';
80+
81+
return $appPath . ($path ? DIRECTORY_SEPARATOR . $path : $path);
82+
}
83+
84+
public function basePath(string $path = ''): string
85+
{
86+
return $this->basePath . ($path ? DIRECTORY_SEPARATOR . $path : $path);
87+
}
88+
89+
public function environmentPath(): string
90+
{
91+
return $this->environmentPath ?: $this->basePath;
92+
}
93+
94+
public function configPath(string $path = ''): string
95+
{
96+
return $this->basePath . DIRECTORY_SEPARATOR . 'config' . ($path ? DIRECTORY_SEPARATOR . $path : $path);
97+
}
98+
99+
public function bootstrapPath(string $path = ''): string
100+
{
101+
return $this->basePath . DIRECTORY_SEPARATOR . 'bootstrap' . ($path ? DIRECTORY_SEPARATOR . $path : $path);
102+
}
103+
104+
public function getCachedConfigPath(): string
105+
{
106+
return $_ENV['APP_CONFIG_CACHE'] ?? $this->bootstrapPath() . '/cache/config.php';
107+
}
108+
109+
public function loadEnvironmentFrom($file): Application
110+
{
111+
$this->environmentFile = $file;
112+
113+
return $this;
114+
}
115+
116+
public function environmentFile(): string
117+
{
118+
return $this->environmentFile ?: '.env';
119+
}
120+
121+
public function environmentFilePath(): string
122+
{
123+
return $this->environmentPath() . DIRECTORY_SEPARATOR . $this->environmentFile();
124+
}
125+
126+
public function environment(...$environments)
127+
{
128+
if (count($environments) > 0) {
129+
$patterns = is_array($environments[0]) ? $environments[0] : $environments;
130+
131+
return Str::is($patterns, $this['env']);
132+
}
133+
134+
return $this['env'];
135+
}
136+
137+
public function isLocal(): bool
138+
{
139+
return $this['env'] === 'local';
140+
}
141+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Longman\TelegramBot\Bootstrap;
5+
6+
use Dotenv\Dotenv;
7+
use Dotenv\Environment\Adapter\EnvConstAdapter;
8+
use Dotenv\Environment\Adapter\PutenvAdapter;
9+
use Dotenv\Environment\Adapter\ServerConstAdapter;
10+
use Dotenv\Environment\DotenvFactory;
11+
use Exception;
12+
use Longman\TelegramBot\Application;
13+
14+
class LoadEnvironmentVariables
15+
{
16+
public function bootstrap(Application $app)
17+
{
18+
try {
19+
$this->createDotenv($app)->load();
20+
} catch (Exception $e) {
21+
$this->writeErrorAndDie($e);
22+
}
23+
}
24+
25+
protected function createDotenv(Application $app): Dotenv
26+
{
27+
return Dotenv::create(
28+
$app->environmentPath(),
29+
$app->environmentFile(),
30+
new DotenvFactory([new EnvConstAdapter, new ServerConstAdapter, new PutenvAdapter])
31+
);
32+
}
33+
34+
protected function writeErrorAndDie(Exception $e)
35+
{
36+
$message = 'The environment file is invalid! ' . $e->getMessage();
37+
die($message);
38+
}
39+
}

src/Bootstrap/SetupDatabase.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Longman\TelegramBot\Bootstrap;
5+
6+
use Illuminate\Database\Capsule\Manager as Capsule;
7+
use Illuminate\Database\ConnectionResolver;
8+
use Illuminate\Events\Dispatcher;
9+
use Longman\TelegramBot\Application;
10+
11+
use PDO;
12+
use function array_filter;
13+
use function env;
14+
use function extension_loaded;
15+
16+
class SetupDatabase
17+
{
18+
public function bootstrap(Application $app)
19+
{
20+
$config = $this->getConfig();
21+
$capsule = new Capsule($app);
22+
$capsule->addConnection($config);
23+
24+
$capsule->setEventDispatcher(new Dispatcher($app));
25+
26+
$capsule->setAsGlobal();
27+
28+
// $capsule->bootEloquent();
29+
30+
$app->instance('db', $capsule);
31+
32+
$app->bind('db.connection', function ($app) {
33+
return $app['db']->connection();
34+
});
35+
36+
$app->bind('db.resolver', function ($app) {
37+
$resolver = new ConnectionResolver(['default' => $app['db.connection']]);
38+
$resolver->setDefaultConnection('default');
39+
return $resolver;
40+
});
41+
42+
$app->enableExternalMySql($capsule->getConnection()->getPdo());
43+
}
44+
45+
private function getConfig(): array
46+
{
47+
return [
48+
'driver' => 'mysql',
49+
'host' => env('TG_DB_HOST', '127.0.0.1'),
50+
'port' => env('TG_DB_PORT', '3306'),
51+
'database' => env('TG_DB_DATABASE', 'forge'),
52+
'username' => env('TG_DB_USERNAME', 'forge'),
53+
'password' => env('TG_DB_PASSWORD', ''),
54+
'unix_socket' => env('TG_DB_SOCKET', ''),
55+
'charset' => 'utf8mb4',
56+
'collation' => 'utf8mb4_unicode_ci',
57+
'prefix' => env('TG_DB_PREFIX', ''),
58+
'prefix_indexes' => true,
59+
'strict' => env('TG_DB_STRICT', false),
60+
'engine' => null,
61+
'options' => extension_loaded('pdo_mysql') ? array_filter([
62+
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
63+
]) : [],
64+
];
65+
}
66+
}

src/Bootstrap/SetupMigrations.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Longman\TelegramBot\Bootstrap;
5+
6+
use Illuminate\Database\Migrations\DatabaseMigrationRepository;
7+
use Illuminate\Database\Migrations\MigrationCreator;
8+
use Illuminate\Database\Migrations\Migrator;
9+
use Illuminate\Filesystem\Filesystem;
10+
use Longman\TelegramBot\Application;
11+
12+
use function env;
13+
14+
class SetupMigrations
15+
{
16+
public function bootstrap(Application $app)
17+
{
18+
$app->singleton('files', function (Application $app) {
19+
return new Filesystem();
20+
});
21+
22+
$app->singleton('migration.repository', function (Application $app) {
23+
$table = env('TG_DB_MIGRATIONS_TABLE', 'migrations');
24+
25+
return new DatabaseMigrationRepository($app['db.resolver'], $table);
26+
});
27+
28+
$app->singleton('migrator', function (Application $app) {
29+
$repository = $app['migration.repository'];
30+
31+
return new Migrator($repository, $app['db.resolver'], $app['files']);
32+
});
33+
34+
$app->singleton('migration.creator', function (Application $app) {
35+
return new MigrationCreator($app['files']);
36+
});
37+
}
38+
}

src/Console/MigrateCommand.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Longman\TelegramBot\Console;
5+
6+
use Illuminate\Console\Command;
7+
8+
use function array_merge;
9+
use function collect;
10+
11+
use const DIRECTORY_SEPARATOR;
12+
13+
class MigrateCommand extends Command
14+
{
15+
protected $signature = 'migrate
16+
{--path= : The path to the migrations files to be executed}
17+
{--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}
18+
{--pretend : Dump the SQL queries that would be run}
19+
{--step : Force the migrations to be run so they can be rolled back individually}';
20+
21+
protected $description = 'Run the database migrations';
22+
23+
/** @var \Illuminate\Database\Migrations\Migrator */
24+
protected $migrator;
25+
26+
public function handle(): void
27+
{
28+
$app = $this->getApplication()->getLaravel();
29+
$this->migrator = $app['migrator'];
30+
31+
$this->prepareDatabase();
32+
33+
$this->migrator->setOutput($this->output)
34+
->run($this->getMigrationPaths(), [
35+
'pretend' => $this->option('pretend'),
36+
'step' => $this->option('step'),
37+
]);
38+
}
39+
40+
protected function prepareDatabase(): void
41+
{
42+
$this->migrator->setConnection('default');
43+
44+
if (! $this->migrator->repositoryExists()) {
45+
$this->call('migrate:install');
46+
}
47+
}
48+
49+
protected function getMigrationPaths(): array
50+
{
51+
// Here, we will check to see if a path option has been defined. If it has we will
52+
// use the path relative to the root of the installation folder so our database
53+
// migrations may be run for any customized path from within the application.
54+
if ($this->input->hasOption('path') && $this->option('path')) {
55+
return collect($this->option('path'))->map(function ($path) {
56+
return ! $this->usingRealPath()
57+
? $this->laravel->basePath() . '/' . $path
58+
: $path;
59+
})->all();
60+
}
61+
62+
return array_merge(
63+
$this->migrator->paths(), [$this->getMigrationPath()]
64+
);
65+
}
66+
67+
protected function usingRealPath(): bool
68+
{
69+
return $this->input->hasOption('realpath') && $this->option('realpath');
70+
}
71+
72+
protected function getMigrationPath(): string
73+
{
74+
return $this->laravel->basePath() . DIRECTORY_SEPARATOR . 'migrations';
75+
}
76+
}
77+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace Longman\TelegramBot\Console;
5+
6+
use Illuminate\Console\Command;
7+
use Illuminate\Database\Migrations\DatabaseMigrationRepository;
8+
9+
class MigrateInstallCommand extends Command
10+
{
11+
protected $signature = 'migrate:install';
12+
13+
protected $description = 'Create the migration repository';
14+
15+
public function handle(): void
16+
{
17+
$app = $this->getApplication()->getLaravel();
18+
19+
$repository = new DatabaseMigrationRepository($app['db.resolver'], 'migrations');
20+
21+
$repository->createRepository();
22+
23+
$this->info('Migration table created successfully.');
24+
}
25+
}
26+

0 commit comments

Comments
 (0)