From 4abae5a837a5a0e1b2351afb07243f455c7de9f3 Mon Sep 17 00:00:00 2001 From: Made Mas Adi Winata Date: Fri, 6 Sep 2024 09:57:38 +0700 Subject: [PATCH 1/2] Update TraitDtos.php --- src/Dtos/TraitDtos.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Dtos/TraitDtos.php b/src/Dtos/TraitDtos.php index 03f302a..8292a56 100644 --- a/src/Dtos/TraitDtos.php +++ b/src/Dtos/TraitDtos.php @@ -15,6 +15,15 @@ namespace Spotlibs\PhpLib\Dtos; +/** + * TraitDtos + * + * @category Library + * @package Dtos + * @author Made Mas Adi Winata + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ trait TraitDtos { public function __construct(array $data = []) { @@ -40,4 +49,4 @@ public function toJson() $data = $this->toArray(); return json_encode($data); } -} \ No newline at end of file +} From 5394d98260452a8b7178d1def11eea2e93d30377 Mon Sep 17 00:00:00 2001 From: Made Mas Adi Winata Date: Wed, 11 Sep 2024 13:33:45 +0700 Subject: [PATCH 2/2] make controller and test commands --- phpcs.xml | 10 +- phpunit.xml | 1 + src/Commands/ControllerMakeCommand.php | 154 ++++++++++++++ src/Commands/TestMakeCommand.php | 88 ++++++++ src/Commands/stubs/controller.plain.stub | 49 +++++ src/Commands/stubs/test.plain.stub | 36 ++++ src/Dtos/TraitDtos.php | 27 ++- src/Libraries/Kafka.php | 210 +++++++++++--------- src/Libraries/KafkaCallable.php | 11 +- src/Middlewares/ServiceActivity.php | 53 +++-- src/Providers/ValidationServiceProvider.php | 93 ++++++--- src/Responses/StdResponse.php | 38 ++-- src/Services/ContextService.php | 46 ++++- src/Validations/GeneralValidation.php | 37 ---- src/Validations/StdValidation.php | 64 +++--- 15 files changed, 692 insertions(+), 225 deletions(-) create mode 100644 src/Commands/ControllerMakeCommand.php create mode 100644 src/Commands/TestMakeCommand.php create mode 100644 src/Commands/stubs/controller.plain.stub create mode 100644 src/Commands/stubs/test.plain.stub delete mode 100644 src/Validations/GeneralValidation.php diff --git a/phpcs.xml b/phpcs.xml index a4e9bac..3e266ef 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -6,10 +6,18 @@ + + + + + + + + src/ - tests/ + tests/ vendor resources database/ diff --git a/phpunit.xml b/phpunit.xml index 97c84eb..d562a33 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -25,6 +25,7 @@ src/Exceptions/Handler.php + src/Commands src/Libraries src/Providers src/Validations diff --git a/src/Commands/ControllerMakeCommand.php b/src/Commands/ControllerMakeCommand.php new file mode 100644 index 0000000..35a074b --- /dev/null +++ b/src/Commands/ControllerMakeCommand.php @@ -0,0 +1,154 @@ + + * @license https://mit-license.org/ MIT License + * @version GIT: 0.0.6 + * @link https://github.com/spotlibs + */ + +declare(strict_types=1); + +namespace Spotlibs\PhpLib\Commands; + +use Illuminate\Console\GeneratorCommand; +use Symfony\Component\Console\Input\InputOption; +use Illuminate\Support\Str; + +/** + * ControllerMakeCommand + * + * Standard command + * + * @category Console + * @package Commands + * @author Made Mas Adi Winata + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ +class ControllerMakeCommand extends GeneratorCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'make:controller'; + /** + * The console command description. + * + * @var string + */ + protected $description = 'Create a new controller class'; + /** + * The type of class being generated. + * + * @var string + */ + protected $type = 'Controller'; + /** + * Execute the console command. + * + * @return void + */ + public function handle() + { + parent::handle(); + $this->createSwagger(); + $this->createTest(); + } + /** + * Create a swagger file controller. + * + * @return void + */ + protected function createSwagger() + { + $className = class_basename($this->argument('name')); + $this->call( + 'make:controller-swagger', + [ + 'name' => $className + ] + ); + } + /** + * Create a unit test file. + * + * @return void + */ + protected function createTest() + { + $className = class_basename($this->argument('name')); + $this->call( + 'make:test', + [ + 'name' => $className + ] + ); + } + /** + * Get the destination class path. + * + * @param string $name name of the type + * + * @return string + */ + protected function getPath($name) + { + return parent::getPath($name . 'Controller'); + } + /** + * ReplaceClass + * + * @param string $stub filename of stub file + * @param string $name name of the type + * + * @return string|string[] + */ + protected function replaceClass($stub, $name) + { + $stub = parent::replaceClass($stub, $name); + $stub = str_replace('DummyUsecase', Str::ucfirst($this->argument('name')) . 'Usecase', $stub); + $stub = str_replace('dummyUsecase', Str::lower($this->argument('name')) . 'Usecase', $stub); + return $stub; + } + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getStub() + { + if ($this->option('resource')) { + return __DIR__ . '/stubs/controller.stub'; + } + return __DIR__ . '/stubs/controller.plain.stub'; + } + /** + * Get the default namespace for the class. + * + * @param string $rootNamespace namespace of root (generally App) + * + * @return string + */ + protected function getDefaultNamespace($rootNamespace) + { + return $rootNamespace . '\Http\Controllers'; + } + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return [ + ['resource', null, InputOption::VALUE_NONE, 'Generate a resource controller class.'], + ]; + } +} diff --git a/src/Commands/TestMakeCommand.php b/src/Commands/TestMakeCommand.php new file mode 100644 index 0000000..7f585f3 --- /dev/null +++ b/src/Commands/TestMakeCommand.php @@ -0,0 +1,88 @@ + + * @license https://mit-license.org/ MIT License + * @version GIT: 0.0.1 + * @link https://brispot.bri.co.id/ + */ + +declare(strict_types=1); + +namespace App\Console\Commands; + +use Illuminate\Console\GeneratorCommand; +use Symfony\Component\Console\Input\InputOption; +use Illuminate\Support\Str; + +/** + * CollectionMakeCommand + * + * Custom command + * + * @category Console + * @package Commands + * @author Made Mas Adi Winata + * @license https://mit-license.org/ MIT License + * @link https://brispot.bri.co.id/ + */ +class TestMakeCommand extends GeneratorCommand +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'make:test'; + /** + * The console command description. + * + * @var string + */ + protected $description = 'Create a new test class'; + /** + * The type of class being generated. + * + * @var string + */ + protected $type = 'Test'; + /** + * Get the destination class path. + * + * @param string $name name of the type + * + * @return string + */ + protected function getPath($name) + { + $name = Str::replaceFirst($this->laravel->getNamespace(), '', $name); + return $this->laravel->basePath() . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $name . 'Test') . '.php'; + } + /** + * Get the stub file for the generator. + * + * @return string + */ + protected function getStub() + { + if ($this->option('resource')) { + return __DIR__ . '/stubs/test.stub'; + } + return __DIR__ . '/stubs/test.plain.stub'; + } + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return [ + ['resource', null, InputOption::VALUE_NONE, 'Generate a resource test class.'], + ]; + } +} diff --git a/src/Commands/stubs/controller.plain.stub b/src/Commands/stubs/controller.plain.stub new file mode 100644 index 0000000..817ba16 --- /dev/null +++ b/src/Commands/stubs/controller.plain.stub @@ -0,0 +1,49 @@ +dummyUsecase = $dummyUsecase; + $this->output = new stdClass(); + $this->output->responseCode = ''; + $this->output->responseDesc = ''; + } +} \ No newline at end of file diff --git a/src/Commands/stubs/test.plain.stub b/src/Commands/stubs/test.plain.stub new file mode 100644 index 0000000..dab8ea3 --- /dev/null +++ b/src/Commands/stubs/test.plain.stub @@ -0,0 +1,36 @@ +assertTrue(true); + } +} \ No newline at end of file diff --git a/src/Dtos/TraitDtos.php b/src/Dtos/TraitDtos.php index 8292a56..35dd7b9 100644 --- a/src/Dtos/TraitDtos.php +++ b/src/Dtos/TraitDtos.php @@ -26,12 +26,27 @@ */ trait TraitDtos { - public function __construct(array $data = []) { + /** + * Construct a DTO instance from associative array. Array key and value data type must comply DTO class property + * + * @param array $data associative array + * + * @return mixed + */ + public function __construct(array $data = []) + { foreach ($data as $key => $value) { $this->{$key} = $value; } } + /** + * Create a DTO instance from associative array. Array key and value data type must comply DTO class property + * + * @param array $data associative array + * + * @return mixed + */ public static function create(array $data): mixed { $self = new self($data); @@ -39,11 +54,21 @@ public static function create(array $data): mixed return $self; } + /** + * Convert instance to associative array + * + * @return array + */ public function toArray(): array { return (array) $this; } + /** + * Convert instance to json + * + * @return bool|string + */ public function toJson() { $data = $this->toArray(); diff --git a/src/Libraries/Kafka.php b/src/Libraries/Kafka.php index bf16446..2a60bc6 100644 --- a/src/Libraries/Kafka.php +++ b/src/Libraries/Kafka.php @@ -1,18 +1,18 @@ - * @license https://mit-license.org/ MIT License * @version GIT: 0.0.4 * @link https://github.com/spotlibs */ +declare(strict_types=1); + namespace Spotlibs\PhpLib\Libraries; use GuzzleHttp\Client; @@ -33,62 +33,77 @@ use Jobcloud\Kafka\Message\Decoder\JsonDecoder; use Jobcloud\Kafka\Producer\KafkaProducerInterface; -class Kafka +/** + * Kafka + * + * @category StandardLibrary + * @package Libraries + * @author Hendri Nursyahbani + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ +class Kafka { - const SCHEMALESS = 1; // Tidak berskema - const SCHEMALESS_WITH_SERDE = 2; // Tidak berskema tapi memiliki mekanisme encode dan decode - const SCHEMAFULL_WITH_SERDE = 3; // Berskema sekaligus memiliki mekanisme encode dan decode + public const SCHEMALESS = 1; // Tidak berskema + public const SCHEMALESS_WITH_SERDE = 2; // Tidak berskema tapi memiliki mekanisme encode dan decode + public const SCHEMAFULL_WITH_SERDE = 3; // Berskema sekaligus memiliki mekanisme encode dan decode /** * Publish new message to Kafka topic * - * @param string $topic_name - * @param int $schematype - * @param string|null $definitionSchemaBody - * @param string|null $definitionSchemaKey - * @return \Jobcloud\Kafka\Producer\KafkaProducerInterface + * @param string $topic_name kafka topic name + * @param int $schematype kafka schema type + * @param string|null $definitionSchemaBody schema body + * @param string|null $definitionSchemaKey schema key + * + * @return \Jobcloud\Kafka\Producer\KafkaProducerInterface */ - public function publishOn(string $topic_name, int $schematype, string $definitionSchemaBody = null, string $definitionSchemaKey = null) : KafkaProducerInterface - { - if(env('KAFKA_SCHEME_REGISTRY_URL') === null) { - throw new \Exception('Env KAFKA_SCHEME_REGISTRY_URL not provide yet'); - } - - if(env('KAFKA_USER_PRODUCE') === null) { - throw new \Exception('Env KAFKA_USER_PRODUCE not provide yet'); - } - - if(env('KAFKA_PASS_PRODUCE') === null) { - throw new \Exception('Env KAFKA_PASS_PRODUCE not provide yet'); - } - - if($schematype === self::SCHEMAFULL_WITH_SERDE) { - $cachedRegistry = new CachedRegistry( - new BlockingRegistry( - new PromisingRegistry( - new Client([ - 'base_uri' => env('KAFKA_SCHEME_REGISTRY_URL'), - 'auth' => [env('KAFKA_USER_PRODUCE'), env('KAFKA_PASS_PRODUCE')] - ]) - ) - ), - new AvroObjectCacheAdapter() - ); - - $registry = new AvroSchemaRegistry($cachedRegistry); - $recordSerializer = new RecordSerializer($cachedRegistry, [ - RecordSerializer::OPTION_REGISTER_MISSING_SUBJECTS => true, // otomatis di daftarkan subjectny jika belum ada di registry - RecordSerializer::OPTION_REGISTER_MISSING_SCHEMAS => true, // otomatis di daftarkan schemany jika belum ada di registry - ]); - - if($definitionSchemaBody !== null) { + public function publishOn(string $topic_name, int $schematype, string $definitionSchemaBody = null, string $definitionSchemaKey = null): KafkaProducerInterface + { + if (env('KAFKA_SCHEME_REGISTRY_URL') === null) { + throw new \Exception('Env KAFKA_SCHEME_REGISTRY_URL not provide yet'); + } + + if (env('KAFKA_USER_PRODUCE') === null) { + throw new \Exception('Env KAFKA_USER_PRODUCE not provide yet'); + } + + if (env('KAFKA_PASS_PRODUCE') === null) { + throw new \Exception('Env KAFKA_PASS_PRODUCE not provide yet'); + } + + if ($schematype === self::SCHEMAFULL_WITH_SERDE) { + $cachedRegistry = new CachedRegistry( + new BlockingRegistry( + new PromisingRegistry( + new Client( + [ + 'base_uri' => env('KAFKA_SCHEME_REGISTRY_URL'), + 'auth' => [env('KAFKA_USER_PRODUCE'), env('KAFKA_PASS_PRODUCE')] + ] + ) + ) + ), + new AvroObjectCacheAdapter() + ); + + $registry = new AvroSchemaRegistry($cachedRegistry); + $recordSerializer = new RecordSerializer( + $cachedRegistry, + [ + RecordSerializer::OPTION_REGISTER_MISSING_SUBJECTS => true, // otomatis di daftarkan subjectny jika belum ada di registry + RecordSerializer::OPTION_REGISTER_MISSING_SCHEMAS => true, // otomatis di daftarkan schemany jika belum ada di registry + ] + ); + + if ($definitionSchemaBody !== null) { $registry->addBodySchemaMappingForTopic( $topic_name, new KafkaAvroSchema($topic_name . '-value', KafkaAvroSchemaInterface::LATEST_VERSION, \AvroSchema::parse($definitionSchemaBody)) ); } - - if($definitionSchemaKey !== null) { + + if ($definitionSchemaKey !== null) { $registry->addKeySchemaMappingForTopic( $topic_name, new KafkaAvroSchema($topic_name . '-key', KafkaAvroSchemaInterface::LATEST_VERSION, \AvroSchema::parse($definitionSchemaKey)) @@ -96,9 +111,9 @@ public function publishOn(string $topic_name, int $schematype, string $definitio } $encoder = new AvroEncoder($registry, $recordSerializer); - } + } - if($schematype === self::SCHEMALESS_WITH_SERDE) { + if ($schematype === self::SCHEMALESS_WITH_SERDE) { $encoder = new JsonEncoder(); } @@ -119,45 +134,48 @@ public function publishOn(string $topic_name, int $schematype, string $definitio ->withLogCallback([KafkaCallable::class, 'logCallback']) ->withErrorCallback([KafkaCallable::class, 'errorProduceCallback']); - if($schematype === self::SCHEMALESS_WITH_SERDE || $schematype === self::SCHEMAFULL_WITH_SERDE) { + if ($schematype === self::SCHEMALESS_WITH_SERDE || $schematype === self::SCHEMAFULL_WITH_SERDE) { $producerBuilder->withEncoder($encoder); } $producer = $producerBuilder->build(); return $producer; - } + } /** * Publish new message to Kafka topic * - * @param string $topic_name - * @param int $schematype - * @param string|null $congrup_name - * @return \Jobcloud\Kafka\Consumer\KafkaConsumerInterface + * @param string $topic_name kafka topic name + * @param int $schematype kafka schema type + * @param string|null $congrup_name kafka consumer group name + * + * @return \Jobcloud\Kafka\Consumer\KafkaConsumerInterface */ - public function consumeOn(string $topic_name, int $schematype, string $congrup_name = null) : KafkaConsumerInterface - { - if(env('KAFKA_SCHEME_REGISTRY_URL') === null) { - throw new \Exception('Env KAFKA_SCHEME_REGISTRY_URL not provide yet'); - } + public function consumeOn(string $topic_name, int $schematype, string $congrup_name = null): KafkaConsumerInterface + { + if (env('KAFKA_SCHEME_REGISTRY_URL') === null) { + throw new \Exception('Env KAFKA_SCHEME_REGISTRY_URL not provide yet'); + } - if(env('KAFKA_USER_CONSUME') === null) { - throw new \Exception('Env KAFKA_USER_CONSUME not provide yet'); - } + if (env('KAFKA_USER_CONSUME') === null) { + throw new \Exception('Env KAFKA_USER_CONSUME not provide yet'); + } - if(env('KAFKA_PASS_CONSUME') === null) { - throw new \Exception('Env KAFKA_PASS_CONSUME not provide yet'); - } + if (env('KAFKA_PASS_CONSUME') === null) { + throw new \Exception('Env KAFKA_PASS_CONSUME not provide yet'); + } - if($schematype === self::SCHEMAFULL_WITH_SERDE) { + if ($schematype === self::SCHEMAFULL_WITH_SERDE) { $cachedRegistry = new CachedRegistry( new BlockingRegistry( new PromisingRegistry( - new Client([ + new Client( + [ 'base_uri' => env('KAFKA_SCHEME_REGISTRY_URL'), 'auth' => [env('KAFKA_USER_CONSUME'), env('KAFKA_PASS_CONSUME')] - ]) + ] + ) ) ), new AvroObjectCacheAdapter() @@ -176,19 +194,19 @@ public function consumeOn(string $topic_name, int $schematype, string $congrup_n $topic_name, new KafkaAvroSchema($topic_name . '-key', KafkaAvroSchemaInterface::LATEST_VERSION) ); - + $decoder = new AvroDecoder($registry, $recordSerializer); } - if($schematype === self::SCHEMALESS_WITH_SERDE) { + if ($schematype === self::SCHEMALESS_WITH_SERDE) { $decoder = new JsonDecoder(); } - - if($schematype === self::SCHEMALESS_WITH_SERDE || $schematype === self::SCHEMAFULL_WITH_SERDE) { + + if ($schematype === self::SCHEMALESS_WITH_SERDE || $schematype === self::SCHEMAFULL_WITH_SERDE) { $consumer = KafkaConsumerBuilder::create()->withAdditionalConfig( [ - 'client.id' => env('APP_NAME').'-'.gethostname(), + 'client.id' => env('APP_NAME') . '-' . gethostname(), 'sasl.username' => env('KAFKA_USER_CONSUME'), 'sasl.password' => env('KAFKA_PASS_CONSUME'), 'sasl.mechanism' => 'PLAIN', @@ -196,19 +214,19 @@ public function consumeOn(string $topic_name, int $schematype, string $congrup_n 'socket.timeout.ms' => '10000' ] )->withAdditionalBroker(env('KAFKA_BROKERS_URL', '')) - ->withConsumerGroup($topic_name.'_'.(isset($congrup_name) ? $congrup_name : 'congrup')) - ->withAdditionalSubscription($topic_name) - ->withDecoder($decoder) - ->withErrorCallback([KafkaCallable::class, 'errorConsumeCallback']) - ->withRebalanceCallback([KafkaCallable::class, 'rebalanceCallback']) - ->withConsumeCallback([KafkaCallable::class, 'consumeCallback']) - ->withLogCallback([KafkaCallable::class, 'logCallback']) - ->withOffsetCommitCallback([KafkaCallable::class, 'offsetCommitCallback']) - ->build(); + ->withConsumerGroup($topic_name . '_' . (isset($congrup_name) ? $congrup_name : 'congrup')) + ->withAdditionalSubscription($topic_name) + ->withDecoder($decoder) + ->withErrorCallback([KafkaCallable::class, 'errorConsumeCallback']) + ->withRebalanceCallback([KafkaCallable::class, 'rebalanceCallback']) + ->withConsumeCallback([KafkaCallable::class, 'consumeCallback']) + ->withLogCallback([KafkaCallable::class, 'logCallback']) + ->withOffsetCommitCallback([KafkaCallable::class, 'offsetCommitCallback']) + ->build(); } else { $consumer = KafkaConsumerBuilder::create()->withAdditionalConfig( [ - 'client.id' => env('APP_NAME').'-'.gethostname(), + 'client.id' => env('APP_NAME') . '-' . gethostname(), 'sasl.username' => env('KAFKA_USER_CONSUME'), 'sasl.password' => env('KAFKA_PASS_CONSUME'), 'sasl.mechanism' => 'PLAIN', @@ -216,18 +234,18 @@ public function consumeOn(string $topic_name, int $schematype, string $congrup_n 'socket.timeout.ms' => '5000' ] )->withAdditionalBroker(env('KAFKA_BROKERS_URL', '')) - ->withConsumerGroup($topic_name . '_' . (isset($congrup_name) ? $congrup_name : 'congrup')) - ->withAdditionalSubscription($topic_name) - ->withErrorCallback([KafkaCallable::class, 'errorConsumeCallback']) - ->withRebalanceCallback([KafkaCallable::class, 'rebalanceCallback']) - ->withConsumeCallback([KafkaCallable::class, 'consumeCallback']) - ->withLogCallback([KafkaCallable::class, 'logCallback']) - ->withOffsetCommitCallback([KafkaCallable::class, 'offsetCommitCallback']) - ->build(); + ->withConsumerGroup($topic_name . '_' . (isset($congrup_name) ? $congrup_name : 'congrup')) + ->withAdditionalSubscription($topic_name) + ->withErrorCallback([KafkaCallable::class, 'errorConsumeCallback']) + ->withRebalanceCallback([KafkaCallable::class, 'rebalanceCallback']) + ->withConsumeCallback([KafkaCallable::class, 'consumeCallback']) + ->withLogCallback([KafkaCallable::class, 'logCallback']) + ->withOffsetCommitCallback([KafkaCallable::class, 'offsetCommitCallback']) + ->build(); } $consumer->subscribe(); return $consumer; - } -} \ No newline at end of file + } +} diff --git a/src/Libraries/KafkaCallable.php b/src/Libraries/KafkaCallable.php index f5d7228..f148e28 100644 --- a/src/Libraries/KafkaCallable.php +++ b/src/Libraries/KafkaCallable.php @@ -21,7 +21,16 @@ use RdKafka\Producer; use RdKafka\KafkaConsumer; -class KafkaCallable extends KafkaLibrary +/** + * KafkaCallable + * + * @category Library + * @package Libraries + * @author Hendri Nursyahbani + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ +class KafkaCallable extends KafkaLibrary { public static function deliveryReportCallback(Producer $producer, Message $message) { if ($message->err == RD_KAFKA_RESP_ERR_NO_ERROR) { diff --git a/src/Middlewares/ServiceActivity.php b/src/Middlewares/ServiceActivity.php index 6787657..e5f3c56 100644 --- a/src/Middlewares/ServiceActivity.php +++ b/src/Middlewares/ServiceActivity.php @@ -1,4 +1,17 @@ - + * @license https://mit-license.org/ MIT License + * @version GIT: 0.0.4 + * @link https://github.com/spotlibs + */ + +declare(strict_types=1); namespace Spotlibs\PhpLib\Middlewares; @@ -7,13 +20,23 @@ use Illuminate\Support\Facades\Log; use Spotlibs\PhpLib\Services\ContextService; +/** + * ServiceActivity + * + * @category StandardMiddleware + * @package Middlewares + * @author Hendri Nursyahbani + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ class ServiceActivity { private ContextService $contextService; /** * Create instance of ServiceActivity - * @param \Spotlibs\PhpLib\Services\ContextService $contextService + * + * @param \Spotlibs\PhpLib\Services\ContextService $contextService context instance */ public function __construct(ContextService $contextService) { @@ -23,8 +46,9 @@ public function __construct(ContextService $contextService) /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next + * @param \Illuminate\Http\Request $request http request instance + * @param \Closure $next next middleware in the pipeline + * * @return mixed */ public function handle($request, Closure $next) @@ -53,20 +77,21 @@ public function handle($request, Closure $next) $this->contextService->set('X-Path-Gateway', $request->header('X-Path-Gateway')); $this->contextService->set('Authorization', $request->header('Authorization')); $this->contextService->set('X-Api-Key', $request->header('X-Api-Key')); - + return $next($request); } /** * Handle tasks after the response has been sent to the browser. * - * @param \Illuminate\Http\Request $request - * @param \Illuminate\Http\Response $response + * @param \Illuminate\Http\Request $request http request instance + * @param \Illuminate\Http\Response $response http response instance + * * @return mixed */ public function terminate($request, $response) { - $log = new StdClass; + $log = new StdClass(); $log->app_name = getenv('APP_NAME'); $log->host = getenv('HTTP_HOST'); $log->clientip = $request->header('X-Forwarded-For') !== null ? $request->header('X-Forwarded-For') : $request->ip(); @@ -79,21 +104,21 @@ public function terminate($request, $response) $log->deviceID = $request->header('X-Device-ID') !== null ? $request->header('X-Device-ID') : null; $log->requestTags = $request->header('X-Request-Tags') !== null ? $request->header('X-Request-Tags') : null; $log->requestBody = strlen(json_encode($request->all())) < 3000 ? $request->all() : null; - - # hashing secret information - if(isset($log->requestBody['password'])) { + + // hashing secret information + if (isset($log->requestBody['password'])) { $log->requestBody['password'] = hash('sha256', $log->requestBody['password']); } $responseObjContent = json_decode($response->getContent()); - if(strlen($response->getContent()) > 5000 && isset($responseObjContent->responseData)) { + if (strlen($response->getContent()) > 5000 && isset($responseObjContent->responseData)) { unset($responseObjContent->responseData); } $log->responseBody = $request->getPathInfo() !== '/docs' ? $responseObjContent : ['responseCode' => '00', 'responseDesc' => 'Sukses API Docs']; - $log->responseTime = round((microtime(true) - $request->server('REQUEST_TIME_FLOAT'))*1000); + $log->responseTime = round((microtime(true) - $request->server('REQUEST_TIME_FLOAT')) * 1000); $log->httpCode = $response->status(); $log->memoryUsage = memory_get_usage(); $log->requestAt = \DateTime::createFromFormat( - 'U.u', + 'U.u', number_format((float) $request->server('REQUEST_TIME_FLOAT'), 6, '.', '') ) ->setTimezone(new \DateTimeZone('Asia/Jakarta')) diff --git a/src/Providers/ValidationServiceProvider.php b/src/Providers/ValidationServiceProvider.php index 37d987c..2c0d3ac 100644 --- a/src/Providers/ValidationServiceProvider.php +++ b/src/Providers/ValidationServiceProvider.php @@ -21,6 +21,15 @@ use Illuminate\Contracts\Translation\Translator; use Illuminate\Support\Facades\Validator as ValidatorFacade; +/** + * ValidationServiceProvider + * + * @category ServiceProvider + * @package Providers + * @author Hendri Nursyahbani + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ class ValidationServiceProvider extends ServiceProvider { private array $messages_validation = [ @@ -145,7 +154,7 @@ class ValidationServiceProvider extends ServiceProvider | Baris Bahasa untuk Validasi Kustom |--------------------------------------------------------------------------------------- | - | Di sini Anda dapat menentukan pesan validasi untuk atribut sesuai keinginan dengan menggunakan + | Di sini Anda dapat menentukan pesan validasi untuk atribut sesuai keinginan dengan menggunakan | konvensi "attribute.rule" dalam penamaan barisnya. Hal ini mempercepat dalam menentukan | baris bahasa kustom yang spesifik untuk aturan atribut yang diberikan. | @@ -171,7 +180,7 @@ class ValidationServiceProvider extends ServiceProvider 'attributes' => [ ], ]; - + /** * Register services. * @@ -179,14 +188,19 @@ class ValidationServiceProvider extends ServiceProvider */ public function register() { - $this->app->singleton('validator', function ($app) { - $validator = $app->make(ValidationFactory::class); - $validator->resolver(function (Translator $translator, array $data, array $rules, array $messages, array $customAttributes) { - $messages = array_merge($messages, $this->messages_validation); - return new Validator($translator, $data, $rules, $messages, $customAttributes); - }); - return $validator; - }); + $this->app->singleton( + 'validator', + function ($app) { + $validator = $app->make(ValidationFactory::class); + $validator->resolver( + function (Translator $translator, array $data, array $rules, array $messages, array $customAttributes) { + $messages = array_merge($messages, $this->messages_validation); + return new Validator($translator, $data, $rules, $messages, $customAttributes); + } + ); + return $validator; + } + ); } /** @@ -196,25 +210,44 @@ public function register() */ public function boot() { - ValidatorFacade::extend('nik_pattern', function ($attribute, $value, $parameters, $validator) { - return is_string($value) && strlen($value) === 16 && preg_match('/^[0-9]+$/', $value); - }, ':attribute harus 16 digit angka.'); - - ValidatorFacade::extend('npwp_pattern', function ($attribute, $value, $parameters, $validator) { - return is_string($value) && in_array(strlen($value), [15, 16]) && preg_match('/^[0-9]+$/', $value); - }, ':attribute harus 15/16 digit angka.'); - - ValidatorFacade::extend('gender_pattern', function ($attribute, $value, $parameters, $validator) { - return is_string($value) && in_array($value, ['L', 'P']); - }, ':attribute harus L/P.'); - - ValidatorFacade::extend('phone_pattern', function ($attribute, $value, $parameters, $validator) { - return is_string($value) && preg_match('/^[0-9]+$/', $value); - }, ':attribute harus digit angka.'); - - ValidatorFacade::extend('email_pattern', function ($attribute, $value, $parameters, $validator) { - return is_string($value) && str_contains($value, '@'); - }, ':attribute format tidak valid.'); + ValidatorFacade::extend( + 'nik_pattern', + function ($attribute, $value, $parameters, $validator) { + return is_string($value) && strlen($value) === 16 && preg_match('/^[0-9]+$/', $value); + }, + ':attribute harus 16 digit angka.' + ); + + ValidatorFacade::extend( + 'npwp_pattern', + function ($attribute, $value, $parameters, $validator) { + return is_string($value) && in_array(strlen($value), [15, 16]) && preg_match('/^[0-9]+$/', $value); + }, + ':attribute harus 15/16 digit angka.' + ); + + ValidatorFacade::extend( + 'gender_pattern', + function ($attribute, $value, $parameters, $validator) { + return is_string($value) && in_array($value, ['L', 'P']); + }, + ':attribute harus L/P.' + ); + + ValidatorFacade::extend( + 'phone_pattern', + function ($attribute, $value, $parameters, $validator) { + return is_string($value) && preg_match('/^[0-9]+$/', $value); + }, + ':attribute harus digit angka.' + ); + + ValidatorFacade::extend( + 'email_pattern', + function ($attribute, $value, $parameters, $validator) { + return is_string($value) && str_contains($value, '@'); + }, + ':attribute format tidak valid.' + ); } } - diff --git a/src/Responses/StdResponse.php b/src/Responses/StdResponse.php index 71c9bc4..719df9b 100644 --- a/src/Responses/StdResponse.php +++ b/src/Responses/StdResponse.php @@ -4,14 +4,14 @@ * PHP version 8 * * @category Library - * @package Exceptions + * @package Responses * @author Made Mas Adi Winata * @license https://mit-license.org/ MIT License * @version GIT: 0.0.2 * @link https://github.com/spotlibs */ -declare(strict_types= 1); +declare(strict_types=1); namespace Spotlibs\PhpLib\Responses; @@ -19,19 +19,24 @@ use Illuminate\Http\Response; use Spotlibs\PhpLib\Exceptions\ParameterException; +/** + * StdResponse + * + * @category Library + * @package Responses + * @author Made Mas Adi Winata + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ class StdResponse { - public static array $headers = [ - 'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains; preload', - 'Server'=> 'BRISPOT', - 'X-Powered-By' => 'BRISPOT' - ]; /** * Create success http response * - * @param string $responseDesc - * @param mixed $responseData nullable - * @return \Illuminate\Http\Response + * @param string $responseDesc description of response + * @param mixed $responseData data of response, nullable + * + * @return \Illuminate\Http\Response */ public static function success(string $responseDesc, mixed $responseData = null): Response { @@ -42,14 +47,15 @@ public static function success(string $responseDesc, mixed $responseData = null) if ($responseData !== null) { $result['responseData'] = $responseData; } - return new Response($result, 200, self::$headers); + return new Response($result, 200); } - + /** * Create failure http response * - * @param \Spotlibs\PhpLib\Exceptions\ExceptionInterface $exception - * @return \Illuminate\Http\Response + * @param \Spotlibs\PhpLib\Exceptions\ExceptionInterface $exception throwed exception + * + * @return \Illuminate\Http\Response */ public static function error(ExceptionInterface $exception): Response { @@ -64,6 +70,6 @@ public static function error(ExceptionInterface $exception): Response $result['responseValidation'] = $exception->getValidationErrors(); } - return new Response($result, $exception->getHttpCode(), self::$headers); + return new Response($result, $exception->getHttpCode()); } -} \ No newline at end of file +} diff --git a/src/Services/ContextService.php b/src/Services/ContextService.php index 8dd420c..6026abc 100644 --- a/src/Services/ContextService.php +++ b/src/Services/ContextService.php @@ -1,21 +1,57 @@ - + * @license https://mit-license.org/ MIT License + * @version GIT: 0.0.3 + * @link https://github.com/spotlibs + */ declare(strict_types=1); namespace Spotlibs\PhpLib\Services; +/** + * ContextService + * + * Standard validation static methods + * + * @category StandardService + * @package Services + * @author Hendri Nursyahbani + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ class ContextService { protected $data = []; - public function set($key, $value) + /** + * Set new key value to context + * + * @param string $key context key + * @param mixed $value context value + * + * @return void + */ + public function set(string $key, mixed $value) { $this->data[$key] = $value; } - public function get($key) + /** + * Get context value based on given context key + * + * @param string $key given key + * + * @return mixed + */ + public function get(string $key) { return $this->data[$key] ?? null; } - -} \ No newline at end of file +} diff --git a/src/Validations/GeneralValidation.php b/src/Validations/GeneralValidation.php deleted file mode 100644 index 9e49ff7..0000000 --- a/src/Validations/GeneralValidation.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @license https://mit-license.org/ MIT License - * @version GIT: 0.0.5 - * @link https://github.com/spotlibs - */ - -declare(strict_types=1); - -namespace Spotlibs\PhpLib\Validations; - -class GeneralValidation -{ - /** - * Get header keys - * @param array $header - * @param array $rules - * @return array - */ - public static function getHeaderFromRules(array $header, array &$rules): array - { - $result = []; - foreach ($rules as $key => $value) { - if (!isset($header[strtolower($key)])) { - continue; - } - $result[$key] = $header[strtolower($key)][0]; - } - return $result; - } -} \ No newline at end of file diff --git a/src/Validations/StdValidation.php b/src/Validations/StdValidation.php index e3f276c..2e7c20e 100644 --- a/src/Validations/StdValidation.php +++ b/src/Validations/StdValidation.php @@ -4,7 +4,7 @@ * PHP version 8 * * @category Library - * @package Exceptions + * @package Validations * @author Hendri Nursyahbani * @license https://mit-license.org/ MIT License * @version GIT: 0.0.4 @@ -18,34 +18,45 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; +/** + * StdValidation + * + * Standard validation static methods + * + * @category Validation + * @package Validations + * @author Hendri Nursyahbani + * @license https://mit-license.org/ MIT License + * @link https://github.com/spotlibs + */ class StdValidation { /** * Get all required header from rules * - * @param array $header - * @param array &$rules - * @return array + * @param array $header request headers in associative array + * @param array $rules pointer of array of rules from handler + * + * @return array */ public static function getHeaderFromRules(array $header, array &$rules): array { $result = []; foreach ($rules as $key => $value) { - if (str_contains($value, 'required')) { - if (!isset($header[strtolower($key)])) { - continue; - } - $result[$key] = $header[strtolower($key)][0]; + if (!isset($header[strtolower($key)])) { + continue; } + $result[$key] = $header[strtolower($key)][0]; } return $result; } - + /** * Validate nik on request body * - * @param \Illuminate\Http\Request $request - * @return void + * @param \Illuminate\Http\Request $request http request object + * + * @return void */ public static function validateNIK(Request $request): void { @@ -58,8 +69,9 @@ public static function validateNIK(Request $request): void /** * Validate npwp on request body * - * @param \Illuminate\Http\Request $request - * @return void + * @param \Illuminate\Http\Request $request http request object + * + * @return void */ public static function validateNPWP(Request $request): void { @@ -72,8 +84,9 @@ public static function validateNPWP(Request $request): void /** * Validate tanggal_lahir on request body * - * @param \Illuminate\Http\Request $request - * @return void + * @param \Illuminate\Http\Request $request http request object + * + * @return void */ public static function validateTanggalLahir(Request $request): void { @@ -86,8 +99,9 @@ public static function validateTanggalLahir(Request $request): void /** * Validate jenis_kelamin on request body * - * @param \Illuminate\Http\Request $request - * @return void + * @param \Illuminate\Http\Request $request http request object + * + * @return void */ public static function validateJenisKelamin(Request $request): void { @@ -100,12 +114,13 @@ public static function validateJenisKelamin(Request $request): void /** * Validate agama on request body * - * @param \Illuminate\Http\Request $request - * @return void + * @param \Illuminate\Http\Request $request http request object + * + * @return void */ public static function validateAgama(Request $request): void { - $rules = [ + $rules = [ 'agama' => 'required|string|in:islam,kristen,katolik,hindu,budha' ]; Validator::make($request->all(), $rules)->validate(); @@ -114,8 +129,9 @@ public static function validateAgama(Request $request): void /** * Validate no_hp on request body * - * @param \Illuminate\Http\Request $request - * @return void + * @param \Illuminate\Http\Request $request http request object + * + * @return void */ public static function validateNoHP(Request $request): void { @@ -124,4 +140,4 @@ public static function validateNoHP(Request $request): void ]; Validator::make($request->all(), $rules)->validate(); } -} \ No newline at end of file +}