From 7cc7dbae0155f991f404266f3c9b5b272bfab73a Mon Sep 17 00:00:00 2001 From: Franck DAKIA Date: Thu, 20 Mar 2025 01:37:52 +0000 Subject: [PATCH 1/4] test: add notification test --- .../Notification/WithNotification.php | 8 ++ tests/Cache/CacheDatabaseTest.php | 6 +- .../Notification/NotificationDatabaseTest.php | 73 +++++++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 tests/Notification/NotificationDatabaseTest.php diff --git a/src/Database/Notification/WithNotification.php b/src/Database/Notification/WithNotification.php index c583c98a..abf22679 100644 --- a/src/Database/Notification/WithNotification.php +++ b/src/Database/Notification/WithNotification.php @@ -17,6 +17,14 @@ public function notifications() ->where('concern_type', get_class($this)); } + /** + * @throws ConnectionException|Exception\QueryBuilderException + */ + public function unreadNotifications() + { + return $this->notifications()->whereNull('read_at'); + } + /** * @throws ConnectionException|Exception\QueryBuilderException */ diff --git a/tests/Cache/CacheDatabaseTest.php b/tests/Cache/CacheDatabaseTest.php index 0e4747b6..dcab47f9 100644 --- a/tests/Cache/CacheDatabaseTest.php +++ b/tests/Cache/CacheDatabaseTest.php @@ -17,9 +17,9 @@ public static function setUpBeforeClass(): void Database::statement("drop table if exists caches;"); Database::statement(" create table if not exists caches ( - `keyname` varchar(500) not null primary key, - `data` text null, - `expire` datetime null + keyname varchar(500) not null primary key, + data text null, + expire datetime null )"); Cache::configure($config["cache"]); diff --git a/tests/Notification/NotificationDatabaseTest.php b/tests/Notification/NotificationDatabaseTest.php new file mode 100644 index 00000000..93ea90e1 --- /dev/null +++ b/tests/Notification/NotificationDatabaseTest.php @@ -0,0 +1,73 @@ +insert([ + 'type' => 'info', + 'concern_id' => 1, + 'concern_type' => 'user', + 'data' => json_encode(['message' => 'Test notification']), + 'read_at' => null + ]); + + $this->assertTrue($result); + } + + public function testRetrieveNotification() + { + $notification = Database::table('notifications')->where('id', 1)->first(); + + $this->assertNotNull($notification); + $this->assertEquals('info', $notification->type); + $this->assertEquals(1, $notification->concern_id); + $this->assertEquals('user', $notification->concern_type); + $this->assertEquals(json_encode(['message' => 'Test notification']), $notification->data); + $this->assertNull($notification->read_at); + } + + public function testUpdateNotification() + { + $result = Database::table('notifications')->where('id', 1)->update([ + 'read_at' => date('Y-m-d H:i:s') + ]); + + $this->assertTrue($result); + + $notification = Database::table('notifications')->where('id', 1)->first(); + $this->assertNotNull($notification->read_at); + } + + public function testDeleteNotification() + { + $result = Database::table('notifications')->where('id', 1)->delete(); + + $this->assertTrue($result); + + $notification = Database::table('notifications')->where('id', 1)->first(); + $this->assertNull($notification); + } +} From 029a3ddf137e6bd6fb2752d98ec27e5dd0e1d429 Mon Sep 17 00:00:00 2001 From: Franck DAKIA Date: Thu, 20 Mar 2025 01:47:18 +0000 Subject: [PATCH 2/4] refactor: update readme --- CONTRIBUTING.md | 8 ++++---- readme.md | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 35e41f6b..5742b225 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,10 @@ # Contribution - [Contribution](#contribution) - - [Introduction](#introduction) - - [Cutting the project](#cutting-the-project) - - [How to make the commits](#how-to-make-the-commits) - - [Contact](#contact) + - [Introduction](#introduction) + - [Cutting the project](#cutting-the-project) + - [How to make the commits](#how-to-make-the-commits) + - [Contact](#contact) ## Introduction diff --git a/readme.md b/readme.md index bf3b8fe3..7f6f1fe6 100644 --- a/readme.md +++ b/readme.md @@ -36,6 +36,36 @@ To use this package, please create an application from this package [bowphp/app] - The native authentication system - Producer/Consumer with beanstalkd, database, Redis, SQS backend +## Project Structure + +The project is organized into the following directories, each representing an independent module: + +- **src/**: Source code for the Bow Framework. + - **Application/**: Main application logic and configuration. + - **Auth/**: Authentication and authorization management. + - **Cache/**: Caching mechanisms. + - **Configuration/**: Configuration settings management. + - **Console/**: Console commands and utilities. + - **Container/**: Dependency injection and service container. + - **Contracts/**: Interfaces and contracts for various components. + - **Database/**: Database connections and ORM. + - **Event/**: Event management and dispatching. + - **Http/**: HTTP requests and responses management. + - **Mail/**: Email sending and configuration. + - **Messaging/**: Messaging and notifications. + - **Middleware/**: Middleware classes for request handling. + - **Queue/**: Job queues and background processing. + - **Router/**: HTTP request routing. + - **Security/**: Security features like encryption and hashing. + - **Session/**: User session management. + - **Storage/**: File storage and retrieval. + - **Support/**: Utility classes and helper functions. + - **Testing/**: Unit testing classes and utilities. + - **Translate/**: Translation and localization. + - **Validation/**: Data validation. + - **View/**: View rendering and templating. +- **tests/**: Unit tests for the project. + ## Contributing Thank you for considering contributing to Bow Framework! The contribution guide is in the framework documentation. @@ -43,6 +73,17 @@ Thank you for considering contributing to Bow Framework! The contribution guide - [Franck DAKIA](https://github.com/papac) - [Thank's collaborators](https://github.com/bowphp/framework/graphs/contributors) +### Contribution Guidelines + +We welcome contributions from the community! To contribute to the project, please follow these steps: + +1. Fork the project and clone it to your local machine. +2. Create a new branch for your changes. +3. Make your changes and commit them. +4. Push your changes to your fork and create a pull request. + +For more detailed information, refer to the `CONTRIBUTING.md` file. + ## Contact [papac@bowphp.com](mailto:papac@bowphp.com) - [@papacdev](https://twitter.com/papacdev) From 8c516afcf3321c59ff47981bfe5900c564ed0ac3 Mon Sep 17 00:00:00 2001 From: Franck DAKIA Date: Thu, 20 Mar 2025 10:03:59 +0000 Subject: [PATCH 3/4] fix: unity tests --- src/Cache/Adapters/DatabaseAdapter.php | 22 +++++++++---------- src/Console/stubs/model/cache.stub | 2 +- tests/Cache/CacheDatabaseTest.php | 6 ++--- tests/Config/stubs/view.php | 2 +- ...test_generate_cache_migration_stubs__1.txt | 2 +- ...st__test_generate_model_cache_stubs__1.txt | 2 +- tests/View/ViewTest.php | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Cache/Adapters/DatabaseAdapter.php b/src/Cache/Adapters/DatabaseAdapter.php index 65da4d04..0b8dfe76 100644 --- a/src/Cache/Adapters/DatabaseAdapter.php +++ b/src/Cache/Adapters/DatabaseAdapter.php @@ -62,7 +62,7 @@ public function add(string $key, mixed $data, ?int $time = null): bool $time = date("Y-m-d H:i:s"); - return $this->query->insert(['keyname' => $key, "data" => serialize($content), "expire" => $time]); + return $this->query->insert(['key_name' => $key, "data" => serialize($content), "expire" => $time]); } /** @@ -71,7 +71,7 @@ public function add(string $key, mixed $data, ?int $time = null): bool */ public function has(string $key): bool { - return $this->query->where("keyname", $key)->exists(); + return $this->query->where("key_name", $key)->exists(); } /** @@ -91,14 +91,14 @@ public function update(string $key, mixed $data, ?int $time = null): mixed $content = $data; } - $result = $this->query->where("keyname", $key)->first(); + $result = $this->query->where("key_name", $key)->first(); $result->data = serialize($content); if (!is_null($time)) { $result->expire = date("Y-m-d H:i:s", strtotime($result->expire) + $time); } - return $this->query->where("keyname", $key)->update((array)$result); + return $this->query->where("key_name", $key)->update((array)$result); } /** @@ -135,12 +135,12 @@ public function push(string $key, array $data): bool throw new Exception("The key $key is not found"); } - $result = $this->query->where("keyname", $key)->first(); + $result = $this->query->where("key_name", $key)->first(); $value = (array)unserialize($result->data); $result->data = serialize(array_merge($value, $data)); - return (bool)$this->query->where("keyname", $key)->update((array)$result); + return (bool)$this->query->where("key_name", $key)->update((array)$result); } /** @@ -154,11 +154,11 @@ public function addTime(string $key, int $time): bool throw new Exception("The key $key is not found"); } - $result = $this->query->where("keyname", $key)->first(); + $result = $this->query->where("key_name", $key)->first(); $result->expire = date("Y-m-d H:i:s", strtotime($result->expire) + $time); - return (bool)$this->query->where("keyname", $key)->update((array)$result); + return (bool)$this->query->where("key_name", $key)->update((array)$result); } /** @@ -172,7 +172,7 @@ public function timeOf(string $key): int|bool|string throw new Exception("The key $key is not found"); } - $result = $this->query->where("keyname", $key)->first(); + $result = $this->query->where("key_name", $key)->first(); return $result->expire; } @@ -188,7 +188,7 @@ public function forget(string $key): bool throw new Exception("The key $key is not found"); } - return $this->query->where("keyname", $key)->delete(); + return $this->query->where("key_name", $key)->delete(); } /** @@ -210,7 +210,7 @@ public function get(string $key, mixed $default = null): mixed return is_callable($default) ? $default() : $default; } - $result = $this->query->where("keyname", $key)->first(); + $result = $this->query->where("key_name", $key)->first(); $value = unserialize($result->data); diff --git a/src/Console/stubs/model/cache.stub b/src/Console/stubs/model/cache.stub index a62facfe..a127c7a4 100644 --- a/src/Console/stubs/model/cache.stub +++ b/src/Console/stubs/model/cache.stub @@ -11,7 +11,7 @@ class {className} extends Migration public function up(): void { $this->create("caches", function (Table $table) { - $table->addString('keyname', ['primary' => true, 'size' => 500]); + $table->addString('key_name', ['primary' => true, 'size' => 500]); $table->addText('data'); $table->addDatetime('expire', ['nullable' => true]); $table->addTimestamps(); diff --git a/tests/Cache/CacheDatabaseTest.php b/tests/Cache/CacheDatabaseTest.php index dcab47f9..b3da9f94 100644 --- a/tests/Cache/CacheDatabaseTest.php +++ b/tests/Cache/CacheDatabaseTest.php @@ -14,10 +14,10 @@ public static function setUpBeforeClass(): void Database::configure($config["database"]); - Database::statement("drop table if exists caches;"); + Database::statement("DROP TABLE IF EXISTS caches;"); Database::statement(" - create table if not exists caches ( - keyname varchar(500) not null primary key, + CREATE TABLE IF NOT EXISTS caches ( + key_name varchar(500) not null primary key, data text null, expire datetime null )"); diff --git a/tests/Config/stubs/view.php b/tests/Config/stubs/view.php index d474221f..49310c29 100644 --- a/tests/Config/stubs/view.php +++ b/tests/Config/stubs/view.php @@ -11,7 +11,7 @@ 'cache' => TESTING_RESOURCE_BASE_DIRECTORY . '/cache', // Le repertoire des vues. - 'path' => __DIR__ . '/../../View/stubs', + 'path' => realpath(__DIR__ . '/../../View/stubs'), 'additionnal_options' => [ 'auto_reload' => true diff --git a/tests/Console/__snapshots__/GeneratorDeepTest__test_generate_cache_migration_stubs__1.txt b/tests/Console/__snapshots__/GeneratorDeepTest__test_generate_cache_migration_stubs__1.txt index daa208f5..a0feccd0 100644 --- a/tests/Console/__snapshots__/GeneratorDeepTest__test_generate_cache_migration_stubs__1.txt +++ b/tests/Console/__snapshots__/GeneratorDeepTest__test_generate_cache_migration_stubs__1.txt @@ -11,7 +11,7 @@ class FakeCacheMigration extends Migration public function up(): void { $this->create("caches", function (Table $table) { - $table->addString('keyname', ['primary' => true, 'size' => 500]); + $table->addString('key_name', ['primary' => true, 'size' => 500]); $table->addText('data'); $table->addDatetime('expire', ['nullable' => true]); $table->addTimestamps(); diff --git a/tests/Console/__snapshots__/GeneratorDeepTest__test_generate_model_cache_stubs__1.txt b/tests/Console/__snapshots__/GeneratorDeepTest__test_generate_model_cache_stubs__1.txt index 7cc6db8c..ad3431de 100644 --- a/tests/Console/__snapshots__/GeneratorDeepTest__test_generate_model_cache_stubs__1.txt +++ b/tests/Console/__snapshots__/GeneratorDeepTest__test_generate_model_cache_stubs__1.txt @@ -11,7 +11,7 @@ class FakeCacheMigration extends Migration public function up(): void { $this->create("caches", function (SQLGenerator $table) { - $table->addString('keyname', ['primary' => true, 'size' => 500]); + $table->addString('key_name', ['primary' => true, 'size' => 500]); $table->addText('data'); $table->addDatetime('expire', ['nullable' => true]); $table->addTimestamps(); diff --git a/tests/View/ViewTest.php b/tests/View/ViewTest.php index 82ce1e2a..9c9f8c19 100644 --- a/tests/View/ViewTest.php +++ b/tests/View/ViewTest.php @@ -10,7 +10,7 @@ class ViewTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass(): void { $config = TestingConfiguration::getConfig(); - + View::configure($config["view"]); } From 2922959043e5e3eb15769aea3361350a8e8d34c8 Mon Sep 17 00:00:00 2001 From: Franck DAKIA Date: Sun, 23 Mar 2025 01:21:02 +0000 Subject: [PATCH 4/4] fix: messaging --- src/Database/Migration/Shortcut/DateColumn.php | 17 +++++++++++++++++ src/Messaging/Messaging.php | 2 +- src/Support/helpers.php | 10 +++++----- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Database/Migration/Shortcut/DateColumn.php b/src/Database/Migration/Shortcut/DateColumn.php index e92689c4..6f5ba12a 100644 --- a/src/Database/Migration/Shortcut/DateColumn.php +++ b/src/Database/Migration/Shortcut/DateColumn.php @@ -99,6 +99,23 @@ public function addTimestamps(): Table return $this; } + /** + * Add default timestamps + * + * @return Table + * @throws SQLGeneratorException + */ + public function addSoftDelete(): Table + { + if ($this->adapter == 'pgsql') { + $this->addTimestamp('deleted_at', ['default' => 'CURRENT_TIMESTAMP', 'nullable' => true]); + } else { + $this->addColumn('updated_at', 'datetime', ['nullable' => true]); + } + + return $this; + } + /** * Change datetime column * diff --git a/src/Messaging/Messaging.php b/src/Messaging/Messaging.php index ec42aea3..68e608f5 100644 --- a/src/Messaging/Messaging.php +++ b/src/Messaging/Messaging.php @@ -106,7 +106,7 @@ public function process(Model $context): void foreach ($channels as $channel) { if (array_key_exists($channel, static::$channels)) { $target_channel = new static::$channels[$channel](); - $target_channel->send($context); + $target_channel->send($context, $this); } } } diff --git a/src/Support/helpers.php b/src/Support/helpers.php index a6d4ff78..b864a9e1 100644 --- a/src/Support/helpers.php +++ b/src/Support/helpers.php @@ -1220,7 +1220,7 @@ function app_mode(): string */ function app_in_debug(): bool { - return (bool)app_env('APP_DEBUG'); + return (bool) app_env('APP_DEBUG'); } } @@ -1228,9 +1228,9 @@ function app_in_debug(): bool /** * Get client request language * - * @return string + * @return ?string */ - function client_locale(): string + function client_locale(): ?string { return request()->lang(); } @@ -1259,7 +1259,7 @@ function old(string $key, mixed $fullback = null): mixed * @throws AuthenticationException * @deprecated */ - function auth(string $guard = null): GuardContract + function auth(?string $guard = null): GuardContract { $auth = Auth::getInstance(); @@ -1279,7 +1279,7 @@ function auth(string $guard = null): GuardContract * @return GuardContract * @throws AuthenticationException */ - function app_auth(string $guard = null): GuardContract + function app_auth(?string $guard = null): GuardContract { $auth = Auth::getInstance();