66
77use Codefy \Framework \Factory \FileLoggerFactory ;
88use Codefy \Framework \Factory \FileLoggerSmtpFactory ;
9+ use Codefy \Framework \Pipeline \PipelineBuilder ;
10+ use Codefy \Framework \Support \BasePathDetector ;
11+ use Codefy \Framework \Support \LocalStorage ;
912use Codefy \Framework \Support \Paths ;
13+ use Dotenv \Dotenv ;
1014use Psr \Container \ContainerInterface ;
1115use Psr \Http \Message \ResponseInterface ;
1216use Psr \Http \Message \ServerRequestInterface ;
1317use Psr \Log \LoggerInterface ;
1418use Qubus \Config \ConfigContainer ;
1519use Qubus \Dbal \Connection ;
1620use Qubus \Dbal \DB ;
21+ use Qubus \EventDispatcher \ActionFilter \Observer ;
22+ use Qubus \EventDispatcher \EventDispatcher ;
1723use Qubus \Exception \Data \TypeException ;
1824use Qubus \Exception \Exception ;
1925use Qubus \Expressive \OrmBuilder ;
26+ use Qubus \Http \Cookies \Factory \HttpCookieFactory ;
27+ use Qubus \Http \Session \Flash ;
28+ use Qubus \Http \Session \PhpSession ;
2029use Qubus \Inheritance \InvokerAware ;
2130use Qubus \Injector \Config \InjectorFactory ;
2231use Qubus \Injector \Psr11 \Container ;
2332use Qubus \Injector \ServiceContainer ;
2433use Qubus \Injector \ServiceProvider \BaseServiceProvider ;
2534use Qubus \Injector \ServiceProvider \Bootable ;
2635use Qubus \Injector \ServiceProvider \Serviceable ;
36+ use Qubus \Mail \Mailer ;
37+ use Qubus \Support \ArrayHelper ;
38+ use Qubus \Support \Assets ;
39+ use Qubus \Support \StringHelper ;
2740use ReflectionException ;
2841
42+ use function dirname ;
2943use function get_class ;
3044use function is_string ;
45+ use function Qubus \Config \Helpers \env ;
46+ use function Qubus \Support \Helpers \is_null__ ;
3147use function rtrim ;
3248
3349use const DIRECTORY_SEPARATOR ;
3450
3551/**
3652 * @property-read ServerRequestInterface $request
3753 * @property-read ResponseInterface $response
38- * @property-read \Qubus\Support\Assets $assets
39- * @property-read \Qubus\Mail\Mailer $mailer
40- * @property-read \Qubus\Http\Session\PhpSession $session
41- * @property-read \Qubus\Http\Session\Flash $flash
42- * @property-read \Qubus\EventDispatcher\EventDispatcher $event
43- * @property-read \Qubus\Http\Cookies\Factory\HttpCookieFactory $httpCookie
44- * @property-read Support\LocalStorage $localStorage
45- * @property-read \Qubus\Config\ConfigContainer $configContainer
54+ * @property-read Assets $assets
55+ * @property-read Mailer $mailer
56+ * @property-read PhpSession $session
57+ * @property-read Flash $flash
58+ * @property-read EventDispatcher $event
59+ * @property-read HttpCookieFactory $httpCookie
60+ * @property-read LocalStorage $localStorage
61+ * @property-read ConfigContainer $configContainer
62+ * @property-read PipelineBuilder $pipeline
63+ * @property-read Observer $hook
64+ * @property-read StringHelper $string
65+ * @property-read ArrayHelper $array
4666 */
4767final class Application extends Container
4868{
4969 use InvokerAware;
5070
51- public const APP_VERSION = '2.0.9 ' ;
71+ public const APP_VERSION = '2.1.0 ' ;
5272
5373 public const MIN_PHP_VERSION = '8.2 ' ;
5474
5575 public const DS = DIRECTORY_SEPARATOR ;
5676
77+ /**
78+ * The current globally available Application (if any).
79+ *
80+ * @var ?self
81+ */
5782 public static ?Application $ APP = null ;
5883
5984 public string $ charset = 'UTF-8 ' ;
@@ -62,9 +87,9 @@ final class Application extends Container
6287
6388 public string $ controllerNamespace = 'App \\Infrastructure \\Http \\Controllers ' ;
6489
65- public static string $ ROOT_PATH ;
90+ public static string $ ROOT_PATH = '' ;
6691
67- protected ? string $ basePath = null ;
92+ protected string $ basePath = '' ;
6893
6994 protected ?string $ appPath = null ;
7095
@@ -93,35 +118,66 @@ public function __construct(array $params)
93118 $ this ->withBasePath (basePath: $ params ['basePath ' ]);
94119 }
95120
96- self ::$ APP = $ this ;
97- self ::$ ROOT_PATH = $ this ->basePath ;
98-
99121 parent ::__construct (InjectorFactory::create (config: $ this ->coreAliases ()));
122+ $ this ->registerBaseBindings ();
100123 $ this ->registerDefaultServiceProviders ();
124+ $ this ->registerPropertyBindings ();
125+ }
101126
102- $ this ->init ();
127+ private function registerBaseBindings (): void
128+ {
129+ self ::$ APP = $ this ;
130+ self ::$ ROOT_PATH = $ this ->basePath ;
131+ $ this ->alias (original: 'app ' , alias: self ::class);
103132 }
104133
105- private function init (): void
134+ /**
135+ * Dynamically created properties.
136+ *
137+ * @return void
138+ * @throws TypeException
139+ */
140+ private function registerPropertyBindings (): void
106141 {
107142 $ contracts = [
108143 'request ' => ServerRequestInterface::class,
109144 'response ' => ResponseInterface::class,
110- 'assets ' => \ Qubus \ Support \ Assets::class,
111- 'mailer ' => \ Qubus \ Mail \ Mailer::class,
112- 'session ' => \ Qubus \ Http \ Session \ PhpSession::class,
113- 'flash ' => \ Qubus \ Http \ Session \ Flash::class,
114- 'event ' => \ Qubus \ EventDispatcher \ EventDispatcher::class,
115- 'httpCookie ' => \ Qubus \ Http \ Cookies \ Factory \ HttpCookieFactory::class,
145+ 'assets ' => Assets::class,
146+ 'mailer ' => Mailer::class,
147+ 'session ' => PhpSession::class,
148+ 'flash ' => Flash::class,
149+ 'event ' => EventDispatcher::class,
150+ 'httpCookie ' => HttpCookieFactory::class,
116151 'localStorage ' => Support \LocalStorage::class,
117- 'configContainer ' => \Qubus \Config \ConfigContainer::class,
152+ 'configContainer ' => ConfigContainer::class,
153+ 'pipeline ' => PipelineBuilder::class,
154+ 'hook ' => Observer::class,
155+ 'string ' => StringHelper::class,
156+ 'array ' => ArrayHelper::class,
118157 ];
119158
120159 foreach ($ contracts as $ property => $ name ) {
121160 $ this ->{$ property } = $ this ->make (name: $ name );
122161 }
123162
124- Codefy::$ PHP = $ this ;
163+ Codefy::$ PHP = $ this ::getInstance ();
164+ }
165+
166+ /**
167+ * Infer the application's base directory
168+ * from the environment and server.
169+ *
170+ * @return string|null
171+ */
172+ protected static function inferBasePath (): ?string
173+ {
174+ $ basePath = (new BasePathDetector ())->getBasePath ();
175+
176+ return match (true ) {
177+ (env ('APP_BASE_PATH ' ) !== null && env ('APP_BASE_PATH ' ) !== false ) => env ('APP_BASE_PATH ' ),
178+ $ basePath !== '' => $ basePath ,
179+ default => dirname (path: __FILE__ , levels: 2 ),
180+ };
125181 }
126182
127183 /**
@@ -138,6 +194,7 @@ public static function getLogger(): LoggerInterface
138194 * FileLogger with SMTP support.
139195 *
140196 * @throws ReflectionException
197+ * @throws TypeException
141198 */
142199 public static function getSmtpLogger (): LoggerInterface
143200 {
@@ -213,8 +270,10 @@ public function singleton(string $key, callable $value): void
213270 */
214271 protected function registerDefaultServiceProviders (): void
215272 {
216- foreach ([
273+ foreach (
274+ [
217275 Providers \ConfigServiceProvider::class,
276+ Providers \PdoServiceProvider::class,
218277 Providers \FlysystemServiceProvider::class,
219278 ] as $ serviceProvider
220279 ) {
@@ -228,11 +287,11 @@ public function bootstrapWith(array $bootstrappers): void
228287 $ this ->hasBeenBootstrapped = true ;
229288
230289 foreach ($ bootstrappers as $ bootstrapper ) {
231- $ this ->make (name: \ Qubus \ EventDispatcher \ EventDispatcher::class)->dispatch ("bootstrapping. {$ bootstrapper }" );
290+ $ this ->make (name: EventDispatcher::class)->dispatch ("bootstrapping. {$ bootstrapper }" );
232291
233292 $ this ->make (name: $ bootstrapper )->bootstrap ($ this );
234293
235- $ this ->make (name: \ Qubus \ EventDispatcher \ EventDispatcher::class)->dispatch ("bootstrapped. {$ bootstrapper }" );
294+ $ this ->make (name: EventDispatcher::class)->dispatch ("bootstrapped. {$ bootstrapper }" );
236295 }
237296 }
238297
@@ -668,7 +727,7 @@ public function getBaseMiddlewares(): array
668727
669728 public function isRunningInConsole (): bool
670729 {
671- return php_sapi_name () === 'cli ' || php_sapi_name () == 'phpdbg ' ;
730+ return in_array ( php_sapi_name (), [ 'cli ' , 'phpdbg ' ]) ;
672731 }
673732
674733 /**
@@ -709,7 +768,7 @@ protected function coreAliases(): array
709768 \Qubus \Config \ConfigContainer::class => \Qubus \Config \Collection::class,
710769 \Qubus \EventDispatcher \EventDispatcher::class => \Qubus \EventDispatcher \Dispatcher::class,
711770 \Qubus \Mail \Mailer::class => \Codefy \Framework \Support \CodefyMailer::class,
712- 'mailer ' => \ Qubus \ Mail \ Mailer::class,
771+ 'mailer ' => Mailer::class,
713772 'dir.path ' => \Codefy \Framework \Support \Paths::class,
714773 'container ' => self ::class,
715774 'codefy ' => self ::class,
@@ -738,6 +797,21 @@ protected function coreAliases(): array
738797 ];
739798 }
740799
800+ /**
801+ * Load environment file(s).
802+ *
803+ * @return void
804+ */
805+ private function loadEnvironment (): void
806+ {
807+ $ dotenv = Dotenv::createImmutable (
808+ paths: $ this ->basePath (),
809+ names: ['.env ' ,'.env.local ' ,'.env.staging ' ,'.env.development ' ,'.env.production ' ],
810+ shortCircuit: false
811+ );
812+ $ dotenv ->safeLoad ();
813+ }
814+
741815 public function __get (mixed $ name )
742816 {
743817 return $ this ->param [$ name ];
@@ -765,4 +839,48 @@ public function __destruct()
765839 $ this ->serviceProvidersRegistered = [];
766840 $ this ->baseMiddlewares = [];
767841 }
842+
843+ /**
844+ * Determine if the application is in production.
845+ *
846+ * @return bool
847+ */
848+ public function isProduction (): bool
849+ {
850+ return env (key: 'APP_ENV ' ) === 'production ' ;
851+ }
852+
853+ /**
854+ * Determine if the application is in development.
855+ *
856+ * @return bool
857+ */
858+ public function isDevelopment (): bool
859+ {
860+ return env (key: 'APP_ENV ' ) === 'development ' ;
861+ }
862+
863+ /**
864+ * Get the globally available instance of the container.
865+ *
866+ * @return static
867+ * @throws TypeException
868+ */
869+ public static function getInstance (?string $ path = null ): self
870+ {
871+ $ basePath = match (true ) {
872+ is_string ($ path ) && $ path !== '' => $ path ,
873+ default => self ::inferBasePath (),
874+ };
875+
876+ if (is_null__ (self ::$ APP )) {
877+ self ::$ APP = new self (
878+ params: [
879+ 'basePath ' => $ basePath ,
880+ ]
881+ );
882+ }
883+
884+ return self ::$ APP ;
885+ }
768886}
0 commit comments