Commit 7e52c9e8 by Mohammad Izzat Johari

initial commit

parents
docs/node_modules
vendor
composer.lock
# Alurkerja CRUD
{
"name": "alurkerja-laravolt/crud",
"type": "package",
"version": "1.0.2",
"description": "Alurkerja Lowcode",
"keywords": ["laravel", "alurkerja", "lowcode", "crud", "workflow"],
"license": "MIT",
"require": {
"php": "^8.1",
"doctrine/dbal": "^3.6",
"laravolt/camunda": "^2.5",
"laravolt/laravolt": "^5.6",
"ramsey/uuid": "^4.7",
"beyondcode/laravel-websockets": "^1.14"
},
"require-dev": {
"knuckleswtf/scribe": "^4.18",
"phpstan/phpstan": "^1.10"
},
"autoload": {
"psr-4": {
"Laravolt\\Crud\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"extra": {
"laravel": {
"providers": [
"Laravolt\\Crud\\CrudServiceProvider"
]
}
}
}
<?php
return [
"ID" => [
"create_button_label" => "Tambah %s",
"detail_button_label" => "Detail %s",
"edit_button_label" => "Edit %s",
"delete_button_label" => "Delete %s",
"start_process_button_label" => "Start Process %s",
"create_then_start_process_button_label" => "Tambah Dan Start Process %s",
"submit_task_button_label" => "Submit Task %s",
"submit_task_confirm_message" => "Apakah anda yakin ingin submit task untuk data ini?",
"submit_task_confirm_header" => "Submit Task",
"submit_task_confirm_conirm_label" => "Lanjutkan",
"submit_task_confirm_cancel_label" => "Batal",
"delete_confirm_message" => "Apakah anda yakin ingin menghapus data ini?1",
"delete_confirm_header" => "Hapus Data",
"delete_confirm_conirm_label" => "Lanjutkan",
"delete_confirm_cancel_label" => "Batal",
"start_process_confirm_message" => "Apakah anda yakin ingin submit process untuk data ini?",
"start_process_confirm_header" => "Submit Process",
"start_process_confirm_conirm_label" => "Lanjutkan",
"start_process_confirm_cancel_label" => "Batal",
"field_list_description" => "Field Dari %s",
"upload_action_message" => "Klik Untuk Mengunggah Atau Drag File",
"upload_file_type_message" => "File yang bisa diupload adalah ",
"upload_uploading_message" => "Mengunggah...",
"upload_upload_error_header" => "Gagal Menggungah",
"upload_upload_error_message" => "Terjadi kesalahan ketika mengunggah file",
"upload_file_type_error_message" => "Type file tidak bisa di upload ",
"upload_file_size_exceed_header" => "Size File Terlalu Besar",
"upload_file_size_exceed_message" => "Size file lebih besar dari yang di perbolehkan",
"pagination_info" => "Memunculkan data dari %s sampai %s total %s",
"empty_data_message" => "Tidak ada data yang ditampilkan",
"filter_title" => "Filter",
"filter_submit" => "Filter",
"filter_reset" => "Clear Filter",
"filter_cancel" => "Kembali",
],
"default" => "ID"
];
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (!(Schema::hasTable('ak_activity_log'))) {
Schema::create('ak_activity_log', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('class_name', 255)->nullable();
$table->string('action')->nullable();
$table->string('business_key')->nullable();
$table->string('entity_id')->nullable();
$table->string('log_type')->nullable();
$table->text('payload')->nullable();
$table->string('remarks', 255)->nullable();
$table->string('status_after', 255)->nullable();
$table->string('status_before', 255)->nullable();
$table->string('act_by_name', 255)->nullable();
$table->string('decision', 255)->nullable();
$table->string('decision_remark', 255)->nullable();
$table->boolean('latest')->nullable();
$table->timestamps();
$table->userstamps();
});
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('ak_activity_log');
}
};
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (!Schema::hasTable('ak_notif_users')) {
Schema::create('ak_notif_users', function (Blueprint $table) {
$table->id();
$table->string("title");
$table->string("message");
$table->text("payload");
$table->string("url_to");
$table->string("user_id");
$table->date("read_at")->nullable();
$table->date("sent_at")->nullable();
$table->timestamps();
});
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('ak_notif_users');
}
};
<?php
namespace App\Http\Controllers\Api\Bpmn;
use App\Models\Bpmn\{Class};
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Laravolt\Crud\BpmnController;
use Laravolt\Crud\BpmnModel;
use App\Services\Bpmn\{Module}\{Class}Service;
use Laravolt\Crud\BpmnService;
class {Class}Controller extends BpmnController
{
public function model(): BpmnModel
{
return new {Class}();
}
/**
* @return BpmnService
*/
public function service(): BpmnService
{
return new {Class}Service($this->model(), $this->user);
}
}
<?php
namespace App\Jobs\{bpmn};
use Laravolt\Camunda\Dto\ExternalTask;
use Laravolt\Camunda\Http\ExternalTaskClient;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class {Class}Job implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*/
public function __construct(
public string $workerId,
public ExternalTask $task
) {
}
/**
* Execute the job.
*/
public function handle()
{
$status = ExternalTaskClient::complete($this->task->id, $this->workerId);
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('{table}', function (Blueprint $table) {
$table->id();
$table->string("process_instance_id")->nullable();
$table->timestamps();
$table->userstamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('{table}');
}
};
<?php
namespace App\Models\Bpmn;
use Laravolt\Crud\BpmnModel;
use Laravolt\Crud\Enum\AutoMode;
class {Class} extends BpmnModel
{
protected $table = '{table}';
protected string $path = "{path}";
public AutoMode $filterMode = AutoMode::BLACKLIST;
public AutoMode $searchMode = AutoMode::BLACKLIST;
public AutoMode $sortMode = AutoMode::BLACKLIST;
}
<?php
namespace App\Services\Bpmn\{Module};
use App\Models\Bpmn\{Module}\{Class};
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Laravolt\Crud\BpmnService;
class {Class}Service extends BpmnService
{
}
<?php
namespace App\Http\Controllers\Api\Bpmn\{Module};
use App\Models\Bpmn\{Module}\{Class};
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Laravolt\Crud\UserTaskController;
use Laravolt\Crud\UserTaskModel;
use App\Services\Bpmn\{Module}\{Class}Service;
use Laravolt\Crud\UserTaskService;
class {Class}Controller extends UserTaskController
{
public function model(): UserTaskModel
{
return new {Class}();
}
/**
* @return UserTaskService
*/
public function service(): UserTaskService
{
return new {Class}Service($this->model(), $this->user);
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('{table}', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger("business_key")->nullable();
$table->timestamps();
$table->userstamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('{table}');
}
};
<?php
namespace App\Models\Bpmn\{Module};
use Laravolt\Crud\UserTaskModel;
use Laravolt\Crud\Enum\AutoMode;
class {Class} extends UserTaskModel
{
protected $table = '{table}';
protected string $path = "{path}";
public AutoMode $filterMode = AutoMode::BLACKLIST;
public AutoMode $searchMode = AutoMode::BLACKLIST;
public AutoMode $sortMode = AutoMode::BLACKLIST;
}
<?php
namespace App\Services\Bpmn\{Module};
use App\Models\Bpmn\{Module}\{Class};
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Laravolt\Crud\UserTaskService;
class {Class}Service extends UserTaskService
{
}
<?php
namespace App\Http\Controllers\Api\Crud\{Module};
use App\Models\{Class};
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Laravolt\Crud\ApiCrudController;
use Laravolt\Crud\CrudModel;
use App\Services\{Module}\{Class}Service;
use Laravolt\Crud\CrudService;
class {Class}Controller extends ApiCrudController
{
public function model(): CrudModel
{
return new {Class}();
}
/**
* @return CrudService
*/
public function service(): CrudService
{
return new {Class}Service($this->model(), $this->user);
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('{table}', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->userstamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('{table}');
}
};
<?php
namespace App\Models;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\AutoMode;
class {Class} extends CrudModel
{
protected $table = '{table}';
protected string $path = "{path}";
public AutoMode $filterMode = AutoMode::BLACKLIST;
public AutoMode $searchMode = AutoMode::BLACKLIST;
public AutoMode $sortMode = AutoMode::BLACKLIST;
}
<?php
namespace App\Services\{Module};
use App\Models\{Module}\{Class};
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Laravolt\Crud\CrudService;
class {Class}Service extends CrudService
{
}
<?php
namespace App\Http\Controllers\Api\Crud\{Module};
use App\Services\{Module}\{Class}Service;
use Laravolt\Crud\Traits\CanFormatResource;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Request as HttpRequest;
class {Class}Controller
{
use CanFormatResource;
public function index(HttpRequest $request) : JsonResource
{
return $this->collection((new {Class}Service())->index($request));
}
}
<?php
namespace App\Services\{Module};
use Illuminate\Http\Request as HttpRequest;
use Illuminate\Support\Collection;
class {Class}Service
{
public function index(HttpRequest $request ) : Collection {
return collect($request->all());
}
}
<?php
namespace App\Http\Controllers\Api\Crud\{Module};
use App\Models\{Module}\{Class};
use App\Services\{Module}\{Class}Service;
use Laravolt\Crud\ApiReadonlyController;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\CrudService;
class {Class}Controller extends ApiReadonlyController
{
public function model(): CrudModel
{
return new {Class}();
}
/**
* @return CrudService
*/
public function service(): CrudService
{
return new {Class}Service($this->model(), $this->user);
}
}
<?php
namespace App\Models\{Module};
use Laravolt\Crud\CrudModel;
class {Class} extends CrudModel
{
protected $table = '{table}';
protected string $path = "{path}";
}
<?php
namespace App\Services\{Module};
use App\Models\{Module}\{Class};
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Laravolt\Crud\CrudService;
class {Class}Service extends CrudService
{
}
<x-volt-app title="{{ request()->route()->getName() }}">
<div
id="crudIndex"
data-base-url="{{ config('api.url') }}/{{ \Illuminate\Support\Str::of(request()->route()->getName())->before('.') }}"
data-title="{{ request()->route()->getName() }}"
data-description=""
>
</div>
</x-volt-app>
<?php
namespace Laravolt\Crud;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Laravolt\Crud\BulkActions\BulkCreate;
use Laravolt\Crud\BulkActions\BulkDelete;
use Laravolt\Crud\BulkActions\BulkReplace;
use Laravolt\Crud\BulkActions\BulkSubmitTask;
use Laravolt\Crud\BulkActions\BulkUpdate;
use Laravolt\Crud\Contracts\CrudControllerContract;
use Laravolt\Crud\Contracts\StoreRequestContract;
use Laravolt\Crud\Contracts\UpdateRequestContract;
use Laravolt\Crud\Response\BulkResponse;
use Laravolt\Crud\Response\DeleteFail;
use Laravolt\Crud\Response\DeleteSuccess;
use Laravolt\Crud\Response\NotFound;
use Spatie\RouteDiscovery\Attributes\Route;
abstract class ApiCrudController extends ApiReadonlyController implements CrudControllerContract
{
protected string $storeRequest = CrudRequest::class;
protected string $updateRequest = CrudRequest::class;
private array $bulkActions = [
'create' => BulkCreate::class,
'update' => BulkUpdate::class,
'delete' => BulkDelete::class,
'replace' => BulkReplace::class,
'submitTask' => BulkSubmitTask::class,
];
public function __construct()
{
app()->bind(StoreRequestContract::class, $this->storeRequest);
app()->bind(UpdateRequestContract::class, $this->updateRequest);
}
/**
* POST. Create Data
*/
public function store(StoreRequestContract $request): JsonResource
{
// $this->authorize('create', $this->model());
$this->guard("CREATE");
$model = $this->service->create($request);
$model->refresh();
return $this->single($model);
}
/**
* POST. PUT. Update Data
*/
#[Route(method: ['POST', 'PUT'])]
public function update(UpdateRequestContract $request, mixed $id): JsonResource
{
try {
$this->guard("UPDATE");
// $this->authorize('update', $this->service->find($id));
$model = $this->service->update($id, $request);
return $this->single($model);
} catch (ModelNotFoundException $e) {
return new NotFound($e);
}
}
/**
* DELETE. Data
*/
public function destroy(mixed $id): JsonResource
{
try {
$model = $this->service->find($id);
$this->guard("DELETE");
// $this->authorize('delete', $model);
$deleted = $this->service->delete($model);
return $deleted ? new DeleteSuccess(null) : new DeleteFail(null);
} catch (ModelNotFoundException $e) {
return new NotFound($e);
}
}
public function rules(): JsonResource
{
return $this->collection($this->service->rules());
}
/**
* POST. Bulk Data
*/
#[Route(method: 'POST')]
public function bulk(): JsonResource
{
$actions = $this->bulkActions();
$validActions = request()->only(array_keys($actions));
$this->validateBulkActions($validActions);
$result = [];
foreach ($validActions as $action => $payload) {
$bulkClass = $actions[$action] ?? false;
if ($bulkClass) {
$result[$action] = (new $bulkClass)($payload, $this->model());
}
}
return (new BulkResponse($result))
->withInvalid(request()->except(array_keys($validActions)));
}
protected function bulkActions(): array
{
return $this->bulkActions;
}
/**
* @throws \Laravolt\Crud\Response\AlurKerja\ValidationException
*/
protected function validateBulkActions(array $validActions)
{
// Check number of bulk operations
$validator = Validator::make(
['count' => collect($validActions)->flatten(1)->count()],
['count' => ['numeric', 'max:20']],
[],
['count' => 'number of actions']
);
if ($validator->fails()) {
throw new \Laravolt\Crud\Response\AlurKerja\ValidationException($validator);
}
return true;
}
}
<?php
namespace Laravolt\Crud;
enum ApiFormat
{
case Laravolt;
case AlurKerja;
}
<?php
namespace Laravolt\Crud;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection as BaseResourceCollection;
use Illuminate\Support\Facades\Auth;
use Laravolt\Crud\Response\NotFound;
use Laravolt\Rbac\Contracts\HasRoleAndPermission;
abstract class ApiReadonlyController extends BaseController
{
public function guard($action)
{
// $user = $this->user;
// abort_if($user === null && !config("rbac.guest_access"), 401, 'You have no authorization.');
// if (is_subclass_of($user, '\Laravolt\Rbac\Contracts\HasRoleAndPermission')) {
// if ($user !== null && !$user->getActionPermissionFromUrl(\request()->getPathInfo(), $action)) {
// abort(405, 'You have no access.');
// }
// }
return true;
}
/**
* GET. List Data
*
* @queryParam search string For searching data.
* @queryParam filter string For filtering data.
* @queryParam sort string For sorting data.
*/
public function index(Request $request): BaseResourceCollection
{
// $this->authorize('viewAny', $this->model());
$this->guard("LIST");
return $this->collection($this->service->get($request));
}
/**
* GET. Scope
*/
public function scope(Request $request, $scope): JsonResource
{
try {
return $this->collection($this->service->getByScope($request, $scope));
} catch (\BadMethodCallException $e) {
return new NotFound($e);
}
}
/**
* GET. Detail Data
*/
public function show(Request $request, mixed $id): JsonResource
{
try {
$this->guard("SHOW");
$model = $this->service->find($id);
// $this->authorize('view', $model);
return $this->single($model);
} catch (ModelNotFoundException $e) {
return new NotFound($e);
}
}
/**
* GET. Spec
*/
public function spec(): JsonResource
{
return $this->single($this->service->spec());
}
}
<?php
namespace Laravolt\Crud;
use App\Models\User;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Routing\Controller;
use Laravolt\Crud\Contracts\CrudUser;
use Laravolt\Crud\Traits\CanFormatResource;
abstract class BaseController extends Controller
{
use AuthorizesRequests;
use CanFormatResource;
protected CrudService $service;
protected CrudUser|null $user = null;
abstract public function model(): CrudModel;
protected function service(): CrudService
{
return new CrudService($this->model(), $this->user);
}
protected function isGuest(): bool|int|string
{
$currentMiddleware = \request()?->route()?->gatherMiddleware() ?? [];
return array_search('allow_guest', $currentMiddleware, true);
}
public function callAction($method, $parameters)
{
$this->user = auth()->user();
$this->service = $this->service();
return parent::callAction($method, $parameters);
}
}
<?php
namespace Laravolt\Crud;
use App\Models\Camunda\BpmnTask;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Cache;
use Laravolt\Camunda\Http\ProcessDefinitionClient;
use Laravolt\Camunda\Http\TaskClient;
use Laravolt\Crud\Contracts\BpmnControllerContract;
use Laravolt\Crud\Contracts\StoreRequestContract;
use Laravolt\Crud\Exceptions\CrudException;
use Laravolt\Crud\Helper\BpmnXmlHelper;
use Laravolt\Crud\Helper\TableSpecHelper;
use Laravolt\Crud\Response\DomainViolationResponse;
use Laravolt\Crud\Response\NoContent;
use Laravolt\Crud\Response\NotFound;
use Laravolt\Crud\Traits\CanFormatBpmnVariables;
use Spatie\RouteDiscovery\Attributes\Route;
abstract class BpmnController extends ApiCrudController implements BpmnControllerContract
{
use CanFormatBpmnVariables, BpmnXmlHelper, TableSpecHelper;
abstract public function model(): BpmnModel;
protected function service(): BpmnService
{
return new BpmnService($this->model(), $this->user);
}
/**
* POST. [BPMN] Start Process
*/
#[Route(method: 'POST')]
public function start(StoreRequestContract $request): JsonResource
{
$model = $this->service()->start($request);
return $this->single($model);
}
/**
* POST. [BPMN] Start Existing Process
*/
#[Route(method: 'POST', uri: '{id}/start')]
public function startExisting(Request $request, mixed $modelId): JsonResource
{
$result = $this->service()->startExisting($modelId, $request->all());
return $this->single($result);
}
public function myTask(Request $request): JsonResource
{
$result = $this->service()->getMyTask($request);
return $this->collection($result);
}
public function availableTask(Request $request): JsonResource
{
$result = $this->service()->getAvailableTask($request);
return $this->collection($result);
}
/**
* GET. [BPMN] Diagram
*/
public function xml()
{
$model = $this->model();
try {
$xml = ProcessDefinitionClient::xml(key: $model->processDefinitionKey());
return response(
$xml,
200,
['Content-Type' => 'application/xml']
);
} catch (\TypeError $error) {
return new NotFound(
new CrudException(sprintf('Process definition key "%s" not found', $model->processDefinitionKey()))
);
}
}
/**
* GET. [BPMN] Status Task
*/
public function statistic(): JsonResource
{
$model = $this->model();
$statistic = [];
$processName = $model->processDefinitionKey();
$node = $model->pareseBpmnFromProcessDefinition($processName);
$tasks = Cache::remember("all_task_of_$processName", 5, function () use ($processName) {
$tasks = TaskClient::unfinishedTask([
"processDefinitionKey" => $processName
]);
return $tasks;
});
foreach ($node as $usertask) {
$taskInstance = $usertask["id"];
$statistic[$taskInstance] = collect($tasks)->filter(function ($data) use ($taskInstance) {
return $taskInstance == $data->taskDefinitionKey;
})->count();
}
return JsonResource::make(['tasks' => $statistic]);
}
}
<?php
namespace Laravolt\Crud;
use Laravolt\Camunda\Http\ProcessDefinitionClient;
use Laravolt\Crud\Helper\BpmnXmlHelper;
use Laravolt\Crud\Helper\TableSpecHelper;
use Laravolt\Crud\Models\ActivityLog;
use Laravolt\Crud\Models\BpmnTask;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Facades\Cache;
use Laravolt\Crud\Sys\ActivityLog\AkActivityLog;
abstract class BpmnModel extends CrudModel
{
use BpmnXmlHelper, TableSpecHelper;
protected string $businessKey = 'business_key';
protected array $filterableColumns = [
'bpmnTasks.task_definition_key',
'bpmnTasks.process_definition_key',
];
protected string $processInstanceKey = 'process_instance_id';
protected array $processVariables = [];
protected bool $isBpmn = true;
protected array $transientProcessVariables = [];
public function getProcessInstanceKey(): string
{
return $this->processInstanceKey;
}
public function getBusinessKeyFieldName(): string
{
return $this->businessKey;
}
public function getProcessInstanceId(): string|null
{
return $this->getAttribute($this->getProcessInstanceKey());
}
public function setProcessInstanceId(string $id): static
{
$this->{$this->getProcessInstanceKey()} = $id;
return $this;
}
public function processDefinitionKey(): string
{
return (new \ReflectionClass(static::class))->getShortName();
}
public function processDefinitionLabel(): string
{
return $this->toWord((new \ReflectionClass(static::class))->getShortName());
}
//
// public function bpmnTasks(): HasMany
// {
// if (config("services.camunda.on_premise")) {
// return [];
// } else {
// return $this->hasMany(BpmnTask::class, 'process_instance_id', 'process_instance_id');
// }
// }
public function getProcessVariables(): array
{
return $this->processVariables;
}
function getUserTask(): array
{
$processName = $this->processDefinitionKey();
return $this->pareseBpmnFromProcessDefinition($processName);
}
public function getTransientProcessVariables(): array
{
return $this->transientProcessVariables;
}
public function toProcessVariables(array $data = []): array
{
$variables = [];
foreach ($this->getProcessVariables() as $var) {
$value = $data[$var] ?? $this->getAttribute($var) ?? null;
if ($value !== null) {
$variables[$var] = $value;
}
}
return $variables;
}
// public function logs(): HasMany
// {
// return $this->hasMany(AkActivityLog::class, "business_key" , "id" )->orderBy("created_at", "desc");
// }
/**
* @param string $processName
* @return mixed
*/
public function pareseBpmnFromProcessDefinition(string $processName)
{
return Cache::rememberForever('user_task_list'.$processName, function () use ($processName) {
$xml_string = ProcessDefinitionClient::xml(key: $processName);
$doc = new \DOMDocument();
$doc->loadXML($xml_string);
unset($xml_string);
$childNode = [];
foreach ($doc->childNodes as $node) {
array_push($childNode, $this->parseNode($node));
}
$node = $this->getNodeCollection($childNode, ["bpmn:userTask"]);
return $node->map(function ($usertask) use ($processName) {
return [
'type' => $usertask["name"],
'id' => $usertask["attributes"]['id'],
'label' => $usertask["attributes"]['name'],
'url' => ($this->getPath() ?? "api/bpmn/cuti/" . $this->toSnakeCase($processName)) . "/" . $this->toUrlPath($usertask["attributes"]["id"]),
];
})->toArray();
});
}
}
<?php
namespace Laravolt\Crud\BulkActions;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Traits\CanHandleMedia;
class BulkCreate
{
use AuthorizesRequests;
use CanHandleMedia;
/**
* @throws \Throwable
*/
public function __invoke(array $rawPayload, CrudModel $model): array
{
// $this->authorize('create', $model);
$rules = collect($model->rules(request()))->mapWithKeys(fn ($rule, $key) => ["*.$key" => $rule])->toArray();
$validated = Validator::make($rawPayload, $rules)->validate();
return DB::transaction(function () use ($model, $validated, $rawPayload) {
$result = ['data' => []];
$successCounter = 0;
foreach ($validated as $index => $payload) {
/** @var CrudModel $instance */
$instance = app(get_class($model));
$request = clone request();
$request->replace($rawPayload[$index] ?? []);
if ($instance->fill($payload + $instance->defaultPayload($request))->save()) {
$this->processMediaable($request, $instance);
// $this->processNexcloudable($request, $instance);
$successCounter++;
$result['data'][] = $instance->toArray();
}
}
$result['total'] = $successCounter;
return $result;
});
}
}
<?php
namespace Laravolt\Crud\BulkActions;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\DB;
use Laravolt\Crud\CrudModel;
class BulkDelete
{
use AuthorizesRequests;
/**
* @throws \Throwable
*/
public function __invoke(array $rawPayload, CrudModel $model): int
{
return DB::transaction(function () use ($rawPayload, $model) {
$successCounter = 0;
$models = $model->newQuery()->findMany(collect($rawPayload)->pluck('id'))->keyBy('id');
/** @var CrudModel $item */
foreach ($models as $item) {
// $this->authorize('delete', $item);
$successCounter += (int) $item->delete();
}
return $successCounter;
});
}
}
<?php
namespace Laravolt\Crud\BulkActions;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Laravolt\Crud\CrudModel;
class BulkReplace
{
use AuthorizesRequests;
/**
* @throws \Throwable
*/
public function __invoke(array $rawPayload, CrudModel $model): int
{
return DB::transaction(function () use ($rawPayload, $model) {
$successCounter = 0;
$payload = collect($rawPayload);
$models = $model->newQuery()->findMany($payload->pluck('id'))->keyBy('id');
/** @var CrudModel $item */
foreach ($models as $item) {
// $this->authorize('update', $item);
$toBeReplaced = $payload->where('id', $item->getKey())->first();
unset($toBeReplaced['id']);
foreach ($toBeReplaced as $relation => $bulkData) {
$ids = collect($bulkData)->pluck('id')->filter();
$successCounter += $item->{$relation}()->whereNotIn('id', $ids)->delete();
foreach ($bulkData as $data) {
$id = $data['id'] ?? false;
if ($id) {
$successCounter += $item->{$relation}()
->where('id', $data['id'])
->update(Arr::except($data, 'id'));
} else {
unset($data['id']);
if ($item->{$relation}()->create($data)) {
$successCounter++;
}
}
}
}
}
return $successCounter;
});
}
}
<?php
namespace Laravolt\Crud\BulkActions;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\DB;
use Laravolt\Crud\BpmnService;
use Laravolt\Crud\CrudModel;
class BulkSubmitTask
{
use AuthorizesRequests;
/**
* @throws \Throwable
*/
public function __invoke(array $rawPayload, CrudModel $model): int
{
return DB::transaction(function () use ($rawPayload, $model) {
$successCounter = 0;
$payload = collect($rawPayload);
$models = $model->newQuery()->findMany($payload->pluck('id'))->keyBy('id');
$service = new BpmnService($model, auth()->user());
/** @var \Laravolt\Crud\BpmnModel $model */
foreach ($models as $model) {
// $this->authorize('update', $model);
}
foreach ($rawPayload as $payload) {
$request = clone request();
$request->replace($payload);
$service->submitTask($payload['task_id'], $model, $request);
}
return $successCounter;
});
}
}
<?php
namespace Laravolt\Crud\BulkActions;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\DB;
use Laravolt\Crud\CrudModel;
class BulkUpdate
{
use AuthorizesRequests;
/**
* @throws \Throwable
*/
public function __invoke(array $rawPayload, CrudModel $model): int
{
// TODO: dari FE tidak mengirim semua data, perlu mekanisme validation yang lebih baik
// $rules = collect($model->rules(request()))->mapWithKeys(fn ($rule, $key) => ["*.$key" => $rule])->toArray();
// \Validator::make($rawPayload, $rules)->validate();
return DB::transaction(function () use ($rawPayload, $model) {
$successCounter = 0;
$models = $model->newQuery()->findMany(collect($rawPayload)->pluck('id'))->keyBy('id');
foreach ($rawPayload as $payload) {
$payload = collect($payload);
$item = $models[$payload->get('id')] ?? null;
if ($item) {
// $this->authorize('update', $item);
$successCounter += (int) $item->update($payload->except(['id'])->toArray());
}
}
return $successCounter;
});
}
}
<?php
namespace Laravolt\Crud\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Laravolt\Crud\Helper\TableSpecHelper;
use Laravolt\Crud\Traits\GeneratorTrait;
class CreateBpmnApi extends Command
{
use GeneratorTrait, TableSpecHelper;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'laravolt:bpmn:api {model} {table?} {module?} {replace?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$replace = $this->argument('replace') == "true";
$model = $this->argument('model');
if (!$this->argument('table')) {
$table = "";
while ($table == "") {
$table = $this->ask("What is the table name?", $this->toSnakeCase($model . "s") );
}
} else {
$table = $this->argument('table');
}
if (!$this->argument('module')) {
$module = "";
while ($module == "") {
$module = $this->ask("What is the module name ? ", $model);
}
} else {
$module = $this->argument('module');
}
$class = $model;
$controllerPath = app_path() . "/Http/Controllers/Api/Bpmn/";
$this->checkAndGenerateFolder($controllerPath);
$servicePath = app_path() . "/Services/Bpmn/" . $module . "/";
$this->checkAndGenerateFolder($servicePath);
$modelPath = app_path() . "/Models/Bpmn/";
$this->checkAndGenerateFolder($modelPath);
$migrationPath = base_path() . "/database/migrations/" ;
//
// $this->info("Creating Model $class");
// $modelStub = file_get_contents(__DIR__ . '/../../resources/stubs/Crud/Model.php.stub');
// $modelStub = str_replace("{Class}", $class, $modelStub);
// $modelStub = str_replace("{Module}", $module, $modelStub);
// $modelStub = str_replace("{table}", $table, $modelStub);
// file_put_contents(app_path() . "/Models/$class.php", $modelStub);
$this->info("Creating Model $class");
$this->generateFile($class, __DIR__ . '/../../resources/stubs/Bpmn/PROCESS/Model.php.stub', app_path() . "/Models/Bpmn/", [
"Class" => $class,
"Module" => $module,
"table" => $table,
"path" => "/api/" . $this->toUrlPath($class)
], $replace);
$this->info("Creating Controller $class");
$this->generateFile($class . "Controller", __DIR__ . '/../../resources/stubs/Bpmn/PROCESS/Controller.php.stub', $controllerPath, [
"Class" => $class,
"Module" => $module,
"table" => $table
], $replace);
$this->info("Creating Services $class");
$this->generateFile($class . "Service", __DIR__ . '/../../resources/stubs/Bpmn/PROCESS/Service.php.stub', $servicePath, [
"Class" => $class,
"Module" => $module,
"table" => $table
], $replace);
$this->info("Running Optimize $class");
$this->call('optimize');
$this->info("Running Creating Migration $class");
$class = Carbon::now()->addSecond(-2)->format("Y_m_d_His"). "_create_{$table}_table";
$this->generateFile($class , __DIR__ . '/../../resources/stubs/Bpmn/PROCESS/Migration.php.stub', $migrationPath, [
"Class" => $class,
"Module" => $module,
"table" => $table
], $replace);
return Command::SUCCESS;
}
}
<?php
namespace Laravolt\Crud\Commands;
use Illuminate\Console\Command;
use Laravolt\Crud\Traits\GeneratorTrait;
class CreateControllerWithService extends Command
{
use GeneratorTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'laravolt:controller:api {model}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$model = $this->argument('model');
$table = "";
while ($table == "") {
$table = $this->ask("What Is ControllerName (Without Controller Ex: Report )", $model);
}
$module = "";
while ($module == "") {
$module = $this->ask("What is the module name ? ", $model);
}
$this->info("Creating Module $module");
$class = $model;
$controllerPath = app_path() . "/Http/Controllers/Api/Crud/" . $module . "/";
$this->checkAndGenerateFolder($controllerPath);
$servicePath = app_path() . "/Services/" . $module . "/";
$this->checkAndGenerateFolder($servicePath);
$this->info("Creating Controller $class");
$this->generateFile($class . "Controller", __DIR__ . '/../../resources/stubs/SimpleController/Controller.php.stub', $controllerPath, [
"Class" => $class,
"Module" => $module,
"table" => $table
]);
$this->info("Creating Services $class");
$this->generateFile($class . "Service", __DIR__ . '/../../resources/stubs/SimpleController/Service.php.stub', $servicePath, [
"Class" => $class,
"Module" => $module,
"table" => $table
]);
$this->info("Running Optimize $class");
$this->call('optimize');
$this->call('make:test' , [
'name' => $class."Controller".'Test'
]);
return Command::SUCCESS;
}
}
<?php
namespace Laravolt\Crud\Commands;
use Illuminate\Console\Command;
use Laravolt\Crud\Helper\TableSpecHelper;
use Laravolt\Crud\Traits\GeneratorTrait;
class CreateCrudApi extends Command
{
use GeneratorTrait, TableSpecHelper;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'laravolt:crud:api {model}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$model = $this->argument('model');
$table = "";
while ($table == "") {
$table = $this->ask("What is the table name?", $this->toSnakeCase($model . "s"));
}
$module = "";
while ($module == "") {
$module = $this->ask("What is the module name ? ", $model);
}
$class = $model;
$controllerPath = app_path() . "/Http/Controllers/Api/Crud/" . $module . "/";
$this->checkAndGenerateFolder($controllerPath);
$servicePath = app_path() . "/Services/" . $module . "/";
$this->checkAndGenerateFolder($servicePath);
$modelPath = app_path() . "/Models/Bpmn/" . $module;
$this->checkAndGenerateFolder($modelPath);
//
//
// $this->info("Creating Model $class");
// $modelStub = file_get_contents(__DIR__ . '/../../resources/stubs/Crud/Model.php.stub');
// $modelStub = str_replace("{Class}", $class, $modelStub);
// $modelStub = str_replace("{Module}", $module, $modelStub);
// $modelStub = str_replace("{table}", $table, $modelStub);
// file_put_contents(app_path() . "/Models/$class.php", $modelStub);
$migrationPath = base_path() . "/database/migrations/";
$this->info("Creating Model $class");
$this->generateFile($class, __DIR__ . '/../../resources/stubs/Crud/Model.php.stub', app_path() . "/Models/", [
"Class" => $class,
"Module" => $module,
"table" => $table,
"path" => "/api/" . $this->toUrlPath($module). "/" . $this->toUrlPath($class)
]);
$this->info("Creating Controller $class");
$this->generateFile($class . "Controller", __DIR__ . '/../../resources/stubs/Crud/Controller.php.stub', $controllerPath, [
"Class" => $class,
"Module" => $module,
"table" => $table
]);
$this->info("Creating Services $class");
$this->generateFile($class . "Service", __DIR__ . '/../../resources/stubs/Crud/Service.php.stub', $servicePath, [
"Class" => $class,
"Module" => $module,
"table" => $table
]);
$this->info("Running Optimize $class");
$this->call('optimize');
$this->info("Running Creating Migration $class");
// $this->call('make:migration', ['name' => "create_{$table}_table", '--create' => $table]);
$class = date("Y_m_d_His") . "_create_{$table}_table";
$this->generateFile($class, __DIR__ . '/../../resources/stubs/Crud/Migration.php.stub', $migrationPath, [
"Class" => $class,
"Module" => $module,
"table" => $table
]);
return Command::SUCCESS;
}
}
<?php
namespace Laravolt\Crud\Commands;
use Illuminate\Console\Command;
use Laravolt\Crud\Helper\TableSpecHelper;
use Laravolt\Crud\Traits\GeneratorTrait;
class CreateServiceTaskJob extends Command
{
use GeneratorTrait, TableSpecHelper;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'laravolt:servicetask:create {bpmn} {serviceTask} {topic} {replace?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$bpmn = $this->argument('bpmn');
if (!$bpmn) {
$bpmn = $this->ask("What is the model name?", $bpmn);
}
$replace = $this->argument('replace') == "true";
$serviceTask = $this->argument('serviceTask');
if (!$serviceTask) {
$serviceTask = $this->ask("What is Service Task name?", $serviceTask);
}
$topic = $this->argument('topic');
if (!$topic) {
$topic = $this->ask("What is topic name?", $topic);
}
$jobFolder = app_path() . "/Jobs" . "/" . $bpmn . "/";
$this->checkAndGenerateFolder($jobFolder);
$this->info("Creating Job $serviceTask");
$this->generateFile($serviceTask. "Job" , __DIR__ . '/../../resources/stubs/Bpmn/PROCESS/Job.php.stub', $jobFolder, [
"Class" => $serviceTask,
"bpmn" => $bpmn,
], $replace);
return Command::SUCCESS;
}
}
<?php
namespace Laravolt\Crud\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Laravolt\Crud\Helper\TableSpecHelper;
use Laravolt\Crud\Traits\GeneratorTrait;
class CreateUserTaskComand extends Command
{
use GeneratorTrait, TableSpecHelper;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'laravolt:usertask:api {model} {table?} {module?} {replace?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command descriptUserTaskComandion';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$model = $this->argument('model');
$replace = $this->argument('replace') == "true";
if (!$this->argument("table")) {
$table = "";
while ($table == "") {
$table = $this->ask("What is the table name?", $this->toSnakeCase($model . "s") );
}
} else {
$table = $this->argument('table');
}
if (!$this->argument('module')) {
$module = "";
while ($module == "") {
$module = $this->ask("What is the module name ? ", $model);
}
} else {
$module = $this->argument('module');
}
$class = $model;
$controllerPath = app_path() . "/Http/Controllers/Api/Bpmn/" . $module . "/";
$this->checkAndGenerateFolder($controllerPath);
$servicePath = app_path() . "/Services/Bpmn/" . $module. "/";
$this->checkAndGenerateFolder($servicePath);
$modelPath = app_path() . "/Models/Bpmn/" . $module. "/" ;
$this->checkAndGenerateFolder($modelPath);
$migrationPath = base_path() . "/database/migrations/" ;
//
//
// $this->info("Creating Model $class");
// $modelStub = file_get_contents(__DIR__ . '/../../resources/stubs/Crud/Model.php.stub');
// $modelStub = str_replace("{Class}", $class, $modelStub);
// $modelStub = str_replace("{Module}", $module, $modelStub);
// $modelStub = str_replace("{table}", $table, $modelStub);
// file_put_contents(app_path() . "/Models/$class.php", $modelStub);
$this->info("Creating Model $class");
$this->generateFile($class, __DIR__ . '/../../resources/stubs/Bpmn/US/Model.php.stub', app_path() . "/Models/Bpmn/" .$module ."/" , [
"Class" => $class,
"Module" => $module,
"table" => $table,
"path" => "/api/" . $this->toUrlPath($module) . "/" . $this->toUrlPath($class)
], $replace);
$this->info("Creating Controller $class");
$this->generateFile($class. "Controller", __DIR__ . '/../../resources/stubs/Bpmn/US/Controller.php.stub', $controllerPath, [
"Class" => $class,
"Module" => $module,
"table" => $table
], $replace);
$this->info("Creating Services $class");
$this->generateFile($class . "Service", __DIR__ . '/../../resources/stubs/Bpmn/US/Service.php.stub', $servicePath, [
"Class" => $class,
"Module" => $module,
"table" => $table
], $replace);
$this->info("Creating Migration $class");
$this->info("Running Optimize");
$this->call('optimize');
$this->info("Running Creating Migration $class");
// $this->call('make:migration', ['name' => "create_{$table}_table", '--create' => $table]);
$class = Carbon::now()->format("Y_m_d_His"). "_create_{$table}_table";
$this->generateFile($class , __DIR__ . '/../../resources/stubs/Bpmn/US/Migration.php.stub', $migrationPath, [
"Class" => $class,
"Module" => $module,
"table" => $table
], $replace);
return Command::SUCCESS;
}
}
<?php
namespace Laravolt\Crud\Commands;
use Illuminate\Console\Command;
class CreateView extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'laravolt:make:view {tableName}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$tableName = $this->argument('tableName');
$class = $tableName;
// list file ON FOLDER
$controllerPath = base_path() . "/database/views/";
if (!is_dir($controllerPath)) {
mkdir($controllerPath, 0755, true);
}
$path = base_path() . "/database/views/" ;
$files = array_filter(scandir($path) , function ($file) {
return !in_array($file, ['.', '..']);
});
$number = 1;
if(count($files) == 0) {
$number = 1;
}else {
$lastFile = end($files);
$number = (int)explode("_", $lastFile)[0] + 1;
}
$filenme = base_path() . "/database/views/" . $number. "_" . $tableName . ".sql";
file_put_contents($filenme, "");
$this->info("File Created: " . $filenme);
return Command::SUCCESS;
}
}
<?php
namespace Laravolt\Crud\Commands;
use Illuminate\Console\Command;
use Laravolt\Crud\Traits\GeneratorTrait;
class CreateViewApi extends Command
{
use GeneratorTrait;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'laravolt:view:api {model}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$model = $this->argument('model');
$table = "";
while ($table == "") {
$table = $this->ask("What is the table name? {with schema name if needed}", strtolower($model));
}
$module = "";
while ($module == "") {
$module = $this->ask("What is the module name ? ", $model);
}
$this->info("Creating Module $module");
$createViewMigration = "";
while ($createViewMigration == "") {
$createViewMigration = $this->ask("Create migration [Y/n]? ", "Y");
}
$class = $model;
$controllerPath = app_path() . "/Http/Controllers/Api/Crud/" . $module. "/";
$this->checkAndGenerateFolder($controllerPath);
$servicePath = app_path() . "/Services/";
$this->checkAndGenerateFolder($controllerPath);
$this->checkAndGenerateFolder( app_path() . "/Models/$module/");
$this->info("Creating Model $class");
$this->generateFile($class, __DIR__ . '/../../resources/stubs/View/Model.php.stub', app_path() . "/Models/$module/", [
"Class" => $class,
"Module" => $module,
"table" => $table
]);
$this->info("Creating Controller $class");
$this->generateFile($class . "Controller", __DIR__ . '/../../resources/stubs/View/Controller.php.stub', $controllerPath, [
"Class" => $class,
"Module" => $module,
"table" => $table
]);
$this->info("Creating Services $class");
$this->generateFile($class . "Service", __DIR__ . '/../../resources/stubs/View/Service.php.stub', $servicePath, [
"Class" => $class,
"Module" => $module,
"table" => $table
]);
$this->info("Running Optimize $class");
$this->call('optimize');
if($createViewMigration == "Y") {
$this->info("Running Creating Migration $class");
$this->call('laravolt:make:view', ['tableName' => $table]);
}
return Command::SUCCESS;
}
}
<?php
namespace Laravolt\Crud\Commands;
use App\Jobs\IzinFindTribeleadJob;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Laravolt\Camunda\Http\ExternalTaskClient;
use Laravolt\Camunda\Http\ProcessDefinitionClient;
use Laravolt\Crud\Helper\BpmnXmlHelper;
use Laravolt\Crud\Helper\TableSpecHelper;
use Laravolt\Crud\Schema\ColumnFactory;
use function Symfony\Component\String\s;
class PullProcessInstanceToExtend extends Command
{
use TableSpecHelper, BpmnXmlHelper;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'alurkerja:pullprocess:scafond {processDefinition} {replace?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
//
$replace = $this->argument('replace') == "true";
$this->info("Running Genearator With replace $replace " . ($replace ? "File akan di replace " : "File akan di skip"));
if ($replace) {
$resp = $this->ask("Lanjutkan ? (y/N)", $this->toSnakeCase("N"));
if ($resp == "N" || $resp == "n") {
return;
}
}
// $processName = $this->ask('Process Definition Key?');
$processName = $this->argument('processDefinition');
$specPath = resource_path($processName . '_spec.json');
$snakecase = $this->toSnakeCase($processName);
$xml_string = ProcessDefinitionClient::xml(key: $processName);
$doc = new \DOMDocument();
$doc->loadXML($xml_string);
$childNode = [];
foreach ($doc->childNodes as $node) {
array_push($childNode, $this->parseNode($node));
}
$data = $this->getNodeCollection($childNode);
$tasks = [];
foreach ($data as $index => $item) {
$attr = collect($item)->get('attributes');
$taskData = [
"type" => str_replace("bpmn:", "", $item['name']),
"name" => in_array('name', $attr) ? $attr['name'] : $attr['id']
];
if ($item['name'] == "bpmn:serviceTask") {
$taskData ['action_type'] = $attr['type'];
$taskData ['topic'] = $attr['topic'];
$this->info("Generating Service Task");
Artisan::call("laravolt:servicetask:create", [
'serviceTask' => ucfirst($taskData['name']),
'topic' => $attr['topic'],
'bpmn' => $processName,
'replace' => $replace
]);
$this->info("\nTambahkan text di bawha ini Pada `app/Providers/AppServiceProvider.php` \n" . "ExternalTaskClient::subscribe('" . $attr['topic'] . "', \App\Jobs\PengajuanIzinPegawai\\" . ucfirst($taskData['name'] . "Job::class") . "\n\n");
} else if ($item['name'] == "bpmn:userTask") {
$this->info("Generating US");
Artisan::call("laravolt:usertask:api", [
'table' => $this->toSnakeCase($processName) . "_" . $this->toSnakeCase($taskData['name']),
'model' => ucfirst($taskData['name']),
'module' => $processName,
'replace' => $replace
]);
} else if ($item['name'] == "bpmn:startEvent") {
$this->info("Generating Bpmn");
Artisan::call("laravolt:bpmn:api", [
'table' => $this->toSnakeCase($processName),
'model' => $processName,
'module' => $processName,
'replace' => $replace
]);
}
$tasks[$attr['id']] = $taskData;
}
$spec["tasks"] = $tasks;
// Write back to file
file_put_contents($specPath, json_encode($spec, JSON_PRETTY_PRINT));
return Command::SUCCESS;
}
}
<?php
namespace Laravolt\Crud\Contracts;
interface BpmnControllerContract
{
}
<?php
namespace Laravolt\Crud\Contracts;
interface CrudControllerContract
{
}
<?php
namespace Laravolt\Crud\Contracts;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
/**
* @property \Illuminate\Support\Collection $roles
* @property string $email
*/
interface CrudUser
{
// public function permissionForView(CrudModel $model): PermissionLevel;
//
// public function permissionForCreate(CrudModel $model): PermissionLevel;
//
// public function permissionForUpdate(CrudModel $model): PermissionLevel;
//
// public function permissionForDelete(CrudModel $model): PermissionLevel;
}
<?php
namespace Laravolt\Crud\Contracts;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
/**
* @property \Illuminate\Support\Collection $roles
* @property string $email
*/
interface CustomFieldContract
{
function getValue();
}
<?php
namespace Laravolt\Crud\Contracts;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
/**
* @property \Illuminate\Support\Collection $roles
* @property string $email
*/
interface FeFormatSpecContract
{
function getValue();
function getName();
}
<?php
namespace Laravolt\Crud\Contracts;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
/**
* @property \Illuminate\Support\Collection $roles
* @property string $email
*/
interface FieldSpecContract
{
function getValue();
}
<?php
namespace Laravolt\Crud\Contracts;
interface LazyExport
{
public function getLazyExportView(): string;
}
<?php
namespace Laravolt\Crud\Contracts;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
/**
* @property \Illuminate\Support\Collection $roles
* @property string $email
*/
interface SelectionContract
{
function getValue();
}
<?php
namespace Laravolt\Crud\Contracts;
interface StoreRequestContract
{
public function all();
public function validated();
public function input(string $field, mixed $default = null);
public function except(string $field);
public function rules();
public function merge(array $input);
public function only(array $keys);
}
<?php
namespace Laravolt\Crud\Contracts;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
/**
* @property \Illuminate\Support\Collection $roles
* @property string $email
*/
interface TableValueContract
{
function getValue();
}
<?php
namespace Laravolt\Crud\Contracts;
interface ToExcel
{
public function toExcel(): array;
}
<?php
namespace Laravolt\Crud\Contracts;
interface UpdateRequestContract
{
public function all();
public function validated();
public function input(string $field);
public function except(array $except);
public function rules();
}
<?php
namespace Laravolt\Crud\Contracts;
interface UsertaskControllerContract
{
}
<?php
namespace Laravolt\Crud;
class CrudManager
{
private static ApiFormat $apiFormat = ApiFormat::Laravolt;
private static PrimaryKeyFormat $primaryKeyFormat = PrimaryKeyFormat::AUTO;
public static function setApiFormat(ApiFormat $format): void
{
self::$apiFormat = $format;
ApiCrudController::setFormat($format);
}
public static function getApiFormat(): ApiFormat
{
return self::$apiFormat;
}
/**
* @return \Laravolt\Crud\PrimaryKeyFormat
*/
public static function getPrimaryKeyFormat(): PrimaryKeyFormat
{
return self::$primaryKeyFormat;
}
/**
* @param \Laravolt\Crud\PrimaryKeyFormat $primaryKeyFormat
*/
public static function setPrimaryKeyFormat(PrimaryKeyFormat $primaryKeyFormat): void
{
self::$primaryKeyFormat = $primaryKeyFormat;
}
}
<?php
namespace Laravolt\Crud;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Laravolt\Crud\Contracts\StoreRequestContract;
use Laravolt\Crud\Contracts\UpdateRequestContract;
class CrudRequest extends FormRequest implements StoreRequestContract, UpdateRequestContract
{
protected function prepareForValidation()
{
$model = request()?->route()?->getController()->model();
if (in_array(request()?->route()?->getActionMethod(), ['store', 'start', 'bulk'])) {
$this->merge($model->defaultPayload($this));
request()->request->add($model->defaultPayload($this));
}
}
public function rules()
{
/** @var \Laravolt\Crud\CrudModel $model */
$model = request()?->route()?->getController()->model();
if (!$model) {
return [];
}
return $model->rules($this);
}
protected function failedValidation(Validator $validator)
{
if (CrudManager::getApiFormat() === ApiFormat::AlurKerja) {
throw new \Laravolt\Crud\Response\AlurKerja\ValidationException($validator);
}
parent::failedValidation($validator);
}
}
<?php
namespace Laravolt\Crud;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Laravolt\Crud\Commands\CreateBpmnApi;
use Laravolt\Crud\Commands\CreateControllerWithService;
use Laravolt\Crud\Commands\CreateCrudApi;
use Laravolt\Crud\Commands\CreateServiceTaskJob;
use Laravolt\Crud\Commands\CreateUserTaskComand;
use Laravolt\Crud\Commands\CreateView;
use Laravolt\Crud\Commands\CreateViewApi;
use Laravolt\Crud\Commands\PullProcessInstanceToExtend;
use Laravolt\Crud\Commands\PullServiceTaskToExtend;
use Laravolt\Crud\Contracts\CrudUser;
use Laravolt\Crud\Enum\PermissionLevel;
use Laravolt\Crud\RouteDiscovery\HandleCrudRoutes;
use ParseTableToSpec;
enum DataType
{
case UUID;
case INTEGER;
}
class CrudServiceProvider extends ServiceProvider
{
public function boot(): void
{
$default = config()->get('route-discovery.pending_route_transformers');
if ($default) {
if (!in_array(HandleCrudRoutes::class, $default, true)) {
$default[] = HandleCrudRoutes::class;
config()->set('route-discovery.pending_route_transformers', $default);
}
}
$this->loadViewsFrom(__DIR__ . '/../resources/views', 'crud');
Blueprint::macro('userstamps', function (array $only = [], DataType|string $created_by_type = DataType::INTEGER) {
/** @var Blueprint $blueprint */
$blueprint = $this;
if (empty($only)) {
$only = ['created_by', 'updated_by', 'deleted_by'];
}
foreach ($only as $column) {
switch ($created_by_type) {
case DataType::UUID :
$blueprint->uuid($column)->nullable();
break;
default :
$blueprint->unsignedBigInteger($column)->nullable();
break;
}
}
});
Blueprint::macro('dropUserstamps', function (array $only = []) {
/** @var Blueprint $blueprint */
$blueprint = $this;
if (empty($only)) {
$only = ['created_by', 'updated_by', 'deleted_by'];
}
foreach ($only as $column) {
if (Schema::hasColumn($blueprint->getTable(), $column)) //check the column
{
$blueprint->dropColumn($column);
}
}
});
Gate::define('viewAny', function (?CrudUser $user, CrudModel $model) {
//TODO butuh mekanisme yang lebih secure
if (is_null($user) && request()->hasHeader('x-widget')) {
return true;
}
$currentMiddleware = \request()?->route()?->gatherMiddleware() ?? [];
$guestAllowed = array_search('allow_guest', $currentMiddleware) > 0;
return !$guestAllowed ? ($model->permissionForView($user) !== PermissionLevel::NOTHING) : PermissionLevel::GUEST;
});
Gate::define('view', function (?CrudUser $user, CrudModel $model) {
//TODO butuh mekanisme yang lebih secure
if (is_null($user) && request()->hasHeader('x-widget')) {
return true;
}
return match ($model->permissionForView($user)) {
PermissionLevel::NOTHING => false,
PermissionLevel::MINE => $model->isMine($user),
PermissionLevel::OWNED => $model->isOwned($user),
default => true,
};
});
Gate::define('create', function (CrudUser $user, CrudModel $model) {
//TODO butuh mekanisme yang lebih secure
if (is_null($user) && request()->hasHeader('x-widget')) {
return true;
}
return $model->permissionForCreate($user) !== PermissionLevel::NOTHING;
});
Gate::define('update', function (CrudUser $user, CrudModel $model) {
return match ($model->permissionForUpdate($user)) {
PermissionLevel::NOTHING => false,
PermissionLevel::MINE => $model->isMine($user),
PermissionLevel::OWNED => $model->isOwned($user),
default => true,
};
});
Gate::define('delete', function (CrudUser $user, CrudModel $model) {
return match ($model->permissionForDelete($user)) {
PermissionLevel::NOTHING => false,
PermissionLevel::MINE => $model->isMine($user),
PermissionLevel::OWNED => $model->isOwned($user),
default => true,
};
});
Gate::after(function ($user, $ability, $result, $arguments) {
if (!in_array($ability, ['viewAny', 'view', 'create', 'update', 'delete'])) {
foreach ($arguments as $model) {
if ($model instanceof CrudModel) {
$method = 'permissionFor' . ucfirst($ability);
if (!method_exists($model, $method)) {
continue;
}
$allowed = match ($model->$method($user)) {
PermissionLevel::ALL => true,
PermissionLevel::NOTHING => false,
PermissionLevel::MINE => $model->isMine($user),
PermissionLevel::OWNED => $model->isOwned($user),
default => null,
};
if ($allowed !== null) {
return $allowed;
}
}
}
}
});
$default = config()->get('scribe.strategies.bodyParameters');
if ($default) {
if (!in_array(\Laravolt\Crud\Docs\Strategy\GetFromFormRequest::class, $default, true)) {
$default[] = \Laravolt\Crud\Docs\Strategy\GetFromFormRequest::class;
config()->set('scribe.strategies.bodyParameters', $default);
}
if (!in_array(\Laravolt\Crud\Docs\Strategy\GetFormFieldFromSpec::class, $default, true)) {
$default[] = \Laravolt\Crud\Docs\Strategy\GetFormFieldFromSpec::class;
config()->set('scribe.strategies.bodyParameters', $default);
}
}
/*
* use Illuminate\Support\Collection;
* use Illuminate\Pagination\LengthAwarePaginator;
*
* Paginate a standard Laravel Collection.
*
* @param int $perPage
* @param int $total
* @param int $page
* @param string $pageName
* @return array
*/
Collection::macro('paginate', function($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
$default = config()->get('scribe.strategies.metadata');
if ($default) {
if (!in_array(\Laravolt\Crud\Docs\Strategy\GetGroupByControllerName::class, $default, true)) {
$default[] = \Laravolt\Crud\Docs\Strategy\GetGroupByControllerName::class;
config()->set('scribe.strategies.metadata', $default);
}
}
$this->publishes([
__DIR__ . '/../config/alurkerjalang.php' => config_path('alurkerjalang.php'),
], 'config');
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
}
public function register()
{
$this->commands([
CreateView::class,
CreateCrudApi::class,
CreateViewApi::class,
CreateBpmnApi::class,
CreateUserTaskComand::class,
CreateControllerWithService::class,
PullProcessInstanceToExtend::class,
CreateServiceTaskJob::class
]);
$this->mergeConfigFrom(
__DIR__ . '/../config/alurkerjalang.php', 'alurkerjalang'
);
parent::register(); // TODO: Change the autogenerated stub
}
}
<?php
namespace Laravolt\Crud\Docs\Strategy;
use Knuckles\Camel\Extraction\ExtractedEndpointData;
use Knuckles\Scribe\Extracting\Strategies\Strategy;
use Laravolt\Crud\BaseController;
use Laravolt\Crud\BpmnModel;
use Laravolt\Crud\UserTaskModel;
use ReflectionMethod;
class GetFormFieldFromSpec extends Strategy
{
public function __invoke(ExtractedEndpointData $endpointData, array $routeRules = []): ?array
{
/**
* @var \Laravolt\Crud\BaseController;
*/
$controller = new ($endpointData->controller->name);
$method = $endpointData->httpMethods[0];
$result = [];
$mappingType = [
'text' => 'string',
'number' => 'integer',
'json' => 'object',
];
$excludes = [
'id',
'created',
'creator_id',
'updated',
'updater_id',
'is_deleted',
'deleted',
'deleter_id',
'process_instance_id',
'available_task',
];
if ($controller instanceof BaseController && $method === 'POST') {
$reflection = new ReflectionMethod($controller, 'service');
if ($reflection->isPublic()) {
/**
* @var \Laravolt\Crud\CrudService
*/
$service = $controller->service();
$spec = $service->spec();
$fields = $spec['fields'];
foreach ($fields as $field => $value) {
if (! in_array($field, $excludes)) {
$result[$field] = [
'name' => $value['name'],
'type' => $mappingType[$value['type']] ?? 'string',
'description' => $value['label'],
'required' => $value['required'],
];
}
}
$model = $controller->model();
if ($model instanceof BpmnModel || $model instanceof UserTaskModel) {
$variables = $model->getProcessVariables();
foreach ($variables as $variable) {
if (! array_key_exists($variable, $result)) {
$result[$variable] = [
'name' => $variable,
'type' => 'string',
'description' => 'Camunda variable',
'required' => true,
];
}
}
}
}
}
return $result;
}
}
<?php
namespace Laravolt\Crud\Docs\Strategy;
use Illuminate\Http\Request;
use Knuckles\Scribe\Extracting\Strategies\GetFromFormRequestBase;
use Laravolt\Crud\Contracts\StoreRequestContract;
use Laravolt\Crud\CrudRequest;
use ReflectionClass;
use ReflectionException;
use ReflectionFunctionAbstract;
use ReflectionUnionType;
class GetFromFormRequest extends GetFromFormRequestBase
{
protected string $customParameterDataMethodName = 'bodyParameters';
protected function isFormRequestMeantForThisStrategy(ReflectionClass $formRequestReflectionClass): bool
{
// Only use this FormRequest for body params if there's no "Query parameters" in the docblock
// Or there's a bodyParameters() method\
$formRequestDocBlock = $formRequestReflectionClass->getDocComment();
if (strpos(strtolower($formRequestDocBlock), "query parameters") !== false
|| $formRequestReflectionClass->hasMethod('queryParameters')) {
return false;
}
return true;
}
protected function getFormRequestReflectionClass(ReflectionFunctionAbstract $method): ?ReflectionClass
{
foreach ($method->getParameters() as $argument) {
$argType = $argument->getType();
if ($argType === null || $argType instanceof ReflectionUnionType) continue;
$argumentClassName = $argType->getName();
if($argumentClassName == "Laravolt\Crud\Contracts\StoreRequestContract" || $argumentClassName == "Laravolt\Crud\Contracts\UpdateRequestContract") {
$argumentClass = new CrudRequest();
$argumentClassName ="Laravolt\Crud\CrudRequest";
}
if (!class_exists($argumentClassName)) continue;
try {
$argumentClass = new ReflectionClass($argumentClassName);
} catch (ReflectionException $e) {
continue;
}
if (
(class_exists(LaravelFormRequest::class) && $argumentClass->isSubclassOf(LaravelFormRequest::class))
|| (class_exists(DingoFormRequest::class) && $argumentClass->isSubclassOf(DingoFormRequest::class))
|| (class_exists(CrudRequest::class) && $argumentClass->isSubclassOf(Request::class))
) {
return $argumentClass;
}
}
return null;
}
}
<?php
namespace Laravolt\Crud\Docs\Strategy;
use Knuckles\Camel\Extraction\ExtractedEndpointData;
use Knuckles\Scribe\Attributes\Authenticated;
use Knuckles\Scribe\Attributes\Endpoint;
use Knuckles\Scribe\Attributes\Group;
use Knuckles\Scribe\Attributes\Subgroup;
use Knuckles\Scribe\Attributes\Unauthenticated;
use Knuckles\Scribe\Extracting\ParamHelpers;
use Knuckles\Scribe\Extracting\Strategies\PhpAttributeStrategy;
use Knuckles\Scribe\Extracting\Strategies\Strategy;
/**
* @extends PhpAttributeStrategy<Group|Subgroup|Endpoint|Authenticated>
*/
class GetGroupByControllerName extends Strategy
{
public function __invoke(ExtractedEndpointData $endpointData, array $routeRules = []): array
{
$groupname = explode("/" , $endpointData->uri)[config("scribe.module_index") ?? 1] ;
$metadata = [
'groupName' => ucfirst($groupname),
'authenticated' => true
];
return $metadata;
}
}
<?php
namespace Laravolt\Crud\Enum;
enum AutoMode: int
{
case WHITELIST= 1;
case BLACKLIST= 2;
}
<?php
namespace Laravolt\Crud\Enum;
enum PermissionLevel: int
{
case NOTHING = 0;
case MINE = 1;
case OWNED = 2;
case ALL = 3;
case GUEST = -99;
case CUSTOM = -98;
}
<?php
namespace Laravolt\Crud\Exceptions;
class CrudException extends \Exception
{
}
<?php
namespace Laravolt\Crud\Helper;
trait BpmnXmlHelper
{
public function parseAtribute(\DOMNamedNodeMap $attributes)
{
$childNode = [];
foreach ($attributes as $index => $node) {
$data = [
"name" => $node->name,
"value" => $node->value,
];
if ($this->parseChildNode($node->childNodes)) {
$data["child"] = $this->parseChildNode($node->childNodes);
}
$childNode[$node->name] = $node->value;
}
return $childNode;
}
public function parseNode($node)
{
$nodeData = [];
$attr = $node->attributes ? $this->parseAtribute($node->attributes) : [];
if ($attr) {
$nodeData["name"] = $node->nodeName;
$nodeData["attributes"] = $attr;
}
$childNode = [];
if ($node->childNodes) {
foreach ($node->childNodes as $index => $node) {
$childNode[$index] = $this->parseNode($node);
}
}
if ($childNode)
$nodeData['child'] = $childNode;
return $nodeData;
}
public function parseChildNode($childNodes)
{
$childNode = [];
if ($childNodes) {
foreach ($childNodes as $index => $node) {
$childNode[$index] = $this->parseNode($node);
}
}
return $childNode;
}
/**
* @param array $childNode
* @return \Illuminate\Support\Collection
*/
public function getNodeCollection(array $childNode, $types = ['bpmn:userTask', 'bpmn:serviceTask', 'bpmn:startEvent']): \Illuminate\Support\Collection
{
$collected = collect($childNode);
$collected = collect($collected->first());
$collected = collect($collected->get("child"));
$data = collect($collected->where("name", "bpmn:process")->first());
$data = collect($data)->get("child");
$data = collect($data)->whereIn("name", $types);
return $data;
}
}
<?php
namespace Laravolt\Crud\Input;
use Laravolt\Crud\Contracts\CustomFieldContract;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
use Laravolt\Crud\Helper\TableSpecHelper;
class BaseCustomFieldAtribute implements CustomFieldContract
{
use TableSpecHelper;
protected $table = "";
protected $method = "";
protected $overrides = [];
protected $path = "";
protected $name = "";
protected $type = "INPUT_TABLE";
public function __construct(string $name, string $table, array $overrides, $path)
{
$this->table = $table;
$this->name = $name;
$this->overrides = $overrides;
$this->path = $path;
}
function getValue()
{
return [
"table" => $this->table,
"name" => $this->name,
"type" => $this->type,
"spec" => $this->getTableSpec($this->table, $this->overrides, $this->path)
];
}
}
<?php
namespace Laravolt\Crud\Input;
use Laravolt\Crud\Contracts\CustomFieldContract;
use Laravolt\Crud\Contracts\FeFormatSpecContract;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
use Laravolt\Crud\Helper\TableSpecHelper;
class BaseFeFormatAtribute implements FeFormatSpecContract
{
protected $name;
protected $format;
/**
* @param $name
* @param $format
*/
public function __construct($name, $format)
{
$this->name = $name;
$this->format = $format;
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
public function getValue()
{
return [
'name' => $this->name,
'format' => $this->format
];
}
}
<?php
namespace Laravolt\Crud\Input;
use Laravolt\Crud\Contracts\CustomFieldContract;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
use Laravolt\Crud\Helper\TableSpecHelper;
use Laravolt\Crud\Spec\BaselanguageSpec;
class BaseUploadFileFieldAtribute implements CustomFieldContract
{
use TableSpecHelper;
protected $service = "";
protected $name = "";
protected $type = "INPUT_FILE_UPLOAD";
protected $isMultiple = true;
protected $actionMessage = "Klik Untuk Mengunggah Atau Drag File";
protected $fileTypeMessage = "File yang bisa diupload adalah ";
protected $uploadingMessage = "Mengunggah ...";
protected $uploadErrorHeader = "Gagal Menggungah";
protected $uploadErrorMessage = "Terjadi kesalahan ketika mengunggah file";
protected $fileTypeErrorMessage = "Type file tidak bisa di upload ";
protected $fileSizeExceedHeader = "Size File Terlalu Besar";
protected $fileSizeExceedMessage = "Size file lebih besar dari yang di perbolehkan";
protected $allowedExtension = [];
public function __construct(string $name, string $service, bool $isMultiple = true, array $allowedExtension = [],
$actionMessage = null,
$fileTypeMessage = null)
{
$this->name = $name;
$this->service = $service;
$this->allowedExtension = $allowedExtension;
$this->isMultiple = $isMultiple;
$defaultclang = config("alurkerjalang.default") ?? "ID";
$lang = BaselanguageSpec::loadFromArray(config("alurkerjalang.$defaultclang"));
$this->actionMessage = $actionMessage ?? $lang->getLang("upload_action_message");
$this->fileTypeMessage = $fileTypeMessage ?? $lang->getLang("upload_file_type_message");
$this->uploadingMessage = $lang->getLang("upload_uploading_message");
$this->uploadErrorMessage = $lang->getLang("upload_upload_error_message");
$this->uploadErrorHeader = $lang->getLang("upload_upload_error_header");
$this->fileTypeErrorMessage = $lang->getLang("upload_file_type_error_message");
$this->fileSizeExceedHeader = $lang->getLang("upload_file_size_exceed_header");
$this->fileSizeExceedMessage = $lang->getLang("upload_file_size_exceed_message");
}
/**
* @param string $service
*/
public function setService(string $service): self
{
$this->service = $service;
return $this;
}
/**
* @param string $name
*/
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* @param string $type
*/
public function setType(string $type): self
{
$this->type = $type;
return $this;
}
/**
* @param bool $isMultiple
*/
public function setIsMultiple(bool $isMultiple): self
{
$this->isMultiple = $isMultiple;
return $this;
}
/**
* @param mixed|string $actionMessage
*/
public function setActionMessage(mixed $actionMessage): self
{
$this->actionMessage = $actionMessage;
return $this;
}
/**
* @param mixed|string $fileTypeMessage
*/
public function setFileTypeMessage(mixed $fileTypeMessage): self
{
$this->fileTypeMessage = $fileTypeMessage;
return $this;
}
/**
* @param string $uploadingMessage
*/
public function setUploadingMessage(string $uploadingMessage): self
{
$this->uploadingMessage = $uploadingMessage;
return $this;
}
/**
* @param string $uploadErrorHeader
*/
public function setUploadErrorHeader(string $uploadErrorHeader): self
{
$this->uploadErrorHeader = $uploadErrorHeader;
return $this;
}
/**
* @param string $uploadErrorMessage
*/
public function setUploadErrorMesage(string $uploadErrorMessage): self
{
$this->uploadErrorMessage = $uploadErrorMessage;
return $this;
}
/**
* @param array $allowedExtension
*/
public function setAllowedExtension(array $allowedExtension): self
{
$this->allowedExtension = $allowedExtension;
return $this;
}
/**
* @param string $fileTypeErrorMessage
*/
public function setFileTypeErrorMessage(string $fileTypeErrorMessage): self
{
$this->fileTypeErrorMessage = $fileTypeErrorMessage;
return $this;
}
/**
* @param string $fileSizeExceedHeader
*/
public function setFileSizeExceedHeader(string $fileSizeExceedHeader): self
{
$this->fileSizeExceedHeader = $fileSizeExceedHeader;
return $this;
}
/**
* @param string $fileSizeExceedMessage
*/
public function setFileSizeExceedMessage(string $fileSizeExceedMessage): self
{
$this->fileSizeExceedMessage = $fileSizeExceedMessage;
return $this;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
function getValue()
{
return [
"type" => $this->type,
"name" => $this->name,
"is_multiple" => $this->isMultiple,
"allowed_extension" => $this->allowedExtension,
"action_message" => $this->actionMessage,
"file_type_message" => $this->fileTypeMessage,
"uploading_message" => $this->uploadingMessage,
"upload_error_header" => $this->uploadErrorHeader,
"upload_error_message" => $this->uploadErrorMessage,
"service" => $this->service,
];
}
}
<?php
namespace Laravolt\Crud\Input;
use Laravolt\Crud\Contracts\CustomFieldContract;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
use Laravolt\Crud\Helper\TableSpecHelper;
class BaseUploadImageFieldAtribute extends BaseUploadFileFieldAtribute implements CustomFieldContract
{
use TableSpecHelper;
protected $type = "INPUT_IMAGE_UPLOAD";
}
<?php
namespace Laravolt\Crud\Input\Selection;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
class StaticRadioSelection extends StaticSelection implements SelectionContract
{
protected $type = "INPUT_RADIO";
}
<?php
namespace Laravolt\Crud\Input\Selection;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
class StaticSelection implements SelectionContract
{
protected $options = [];
protected $option_key = "";
protected $option_label = "";
protected $type = "INPUT_SELECT";
/**
* @param array $options
* @param string $option_key
* @param string $option_label
*/
public function __construct(array $options, string $option_key, string $option_label)
{
$this->options = $options;
$this->option_key = $option_key;
$this->option_label = $option_label;
}
function getValue()
{
return [
"options" => $this->options,
"option_key" => $this->option_key,
"type" => $this->type,
"option_label" => $this->option_label];
}
}
<?php
namespace Laravolt\Crud\Input\Selection;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
use Laravolt\Crud\Helper\TableSpecHelper;
class TableSelection implements SelectionContract
{
use TableSpecHelper;
protected $table = "";
protected $method = "";
protected $overrides = [];
protected $path = "";
protected $type = "INPUT_TABLE";
public function __construct(string $table, array $overrides, $path)
{
$this->table = $table;
$this->overrides = $overrides;
$this->path = $path;
}
function getValue()
{
return [
"table" => $this->table,
"type" => $this->type,
"spec" => $this->getTableSpec($this->table, $this->overrides, $this->path)
];
}
}
<?php
namespace Laravolt\Crud\Input\Selection;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
class UrlForeignSelection implements SelectionContract
{
protected $url = "";
protected $method = "";
protected $option_key = "";
protected $option_label = "";
protected $type = "INPUT_FOREIGN-SELECT";
/**
* @param array $url
* @param string $table
* @param string $method
* @param string $option_key
* @param string $option_label
*/
public function __construct(string $url, string $method, string $option_key, string $option_label)
{
$this->url = $url;
$this->method = $method;
$this->option_key = $option_key;
$this->option_label = $option_label;
}
function getValue()
{
return [
"url" => $this->url,
"method" => $this->method,
"type" => $this->type,
"option_key" => $this->option_key,
"option_label" => $this->option_label];
}
}
<?php
namespace Laravolt\Crud\Input\Selection;
use Laravolt\Crud\Contracts\SelectionContract;
use Laravolt\Crud\CrudModel;
use Laravolt\Crud\Enum\PermissionLevel;
class UrlSelection implements SelectionContract
{
protected $url = "";
protected $table = "";
protected $method = "";
protected $option_key = "";
protected $option_label = "";
protected $type = "INPUT_SELECT";
/**
* @param array $url
* @param string $table
* @param string $method
* @param string $option_key
* @param string $option_label
*/
public function __construct(string $url, string $table, string $method, string $option_key, string $option_label)
{
$this->url = $url;
$this->table = $table;
$this->method = $method;
$this->option_key = $option_key;
$this->option_label = $option_label;
}
function getValue()
{
return [
"url" => $this->url,
"table" => $this->table,
"method" => $this->method,
"type" => $this->type,
"option_key" => $this->option_key,
"option_label" => $this->option_label];
}
}
<?php
declare(strict_types=1);
namespace Laravolt\Crud\Mixin;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Arr;
/** @mixin \Illuminate\Database\Eloquent\Builder */
class QueryBuilderMixin
{
public function firstOrFail()
{
return function () {
$result = $this->first();
if (! $result) {
abort(404);
}
return $result;
};
}
public function whereLike()
{
return function ($attributes, ?string $searchTerm) {
if ($searchTerm) {
$searchTerm = addslashes(strtolower($searchTerm));
$this->where(function (Builder $query) use ($attributes, $searchTerm) {
foreach (Arr::wrap($attributes) as $column) {
$query->orWhereRaw(sprintf("LOWER(%s) LIKE '%%%s%%'", $column, $searchTerm));
}
});
}
return $this;
};
}
public function autoFilter()
{
return function () {
foreach (request('filter', []) as $column => $value) {
if ($value) {
/** @phpstan-ignore-next-line */
$this->whereLike($column, $value);
}
}
return $this;
};
}
public function autoSort()
{
return function ($sortByKey = 'sort', $sortDirectionKey = 'direction') {
$direction = request()->get($sortDirectionKey, 'asc');
if (request()->has($sortByKey)) {
$column = request()->get($sortByKey);
$this->orderBy($column, $direction);
}
return $this;
};
}
}
<?php
namespace Laravolt\Crud\Models;
use Illuminate\Database\Eloquent\Casts\AsCollection;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Laravolt\Crud\CrudModel;
class ActivityLog extends CrudModel
{
protected $table = "camunda.activity_logs";
protected $casts = [
'decision' => AsCollection::class,
'status_after' => AsCollection::class,
];
protected $with = [
'updatedByUser',
];
public function loggable(): MorphTo
{
return $this->morphTo();
}
public function updatedByUser(): BelongsTo
{
return $this->belongsTo(config('auth.providers.users.model'), 'updated_by', 'id');
}
}
<?php
namespace Laravolt\Crud\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Laravolt\Crud\CrudModel;
class BpmnTask extends CrudModel
{
use HasFactory;
protected $table = 'camunda.v_bpmn_tasks';
protected array $filterableColumns = ['process_instance_id',
'process_definition_key',
'business_key', 'task_id', 'task_definition_key',
'task_name', 'start_time', 'end_time', 'status', 'parent_process_id', ];
}
<?php
namespace Laravolt\Crud;
use Spatie\RouteDiscovery\Attributes\Where;
enum PrimaryKeyFormat
{
case NUMERIC;
case UUID;
case AUTO;
public static function getRouteConstraint(self $format): string
{
return match ($format) {
self::NUMERIC => Where::numeric,
self::UUID => Where::uuid,
self::AUTO => "AUTO",
};
}
}
<?php
namespace Laravolt\Crud\Response\AlurKerja;
use Illuminate\Http\Resources\Json\PaginatedResourceResponse as BasePaginatedResourceResponse;
class PaginatedResourceResponse extends BasePaginatedResourceResponse
{
public function toArray()
{
return $this->resource->resource->toArray();
}
protected function paginationInformation($request)
{
$pagination = parent::paginationInformation($request);
unset($pagination['meta'], $pagination['links']);
return $pagination;
}
}
<?php
namespace Laravolt\Crud\Response\AlurKerja;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Resources\Json\JsonResource;
class Resource extends JsonResource
{
public function with($request)
{
$status = 200;
if ($this->resource instanceof Model && $this->resource->wasRecentlyCreated) {
$status = 201;
}
return [
'status' => $status,
'message' => 'success',
];
}
}
<?php
namespace Laravolt\Crud\Response\AlurKerja;
use Illuminate\Http\Resources\Json\ResourceCollection as BaseResourceCollection;
use Illuminate\Pagination\AbstractCursorPaginator;
use Illuminate\Pagination\AbstractPaginator;
class ResourceCollection extends BaseResourceCollection
{
public function with($request)
{
return [
'status' => 200,
'message' => 'success',
];
}
public function toArray($request)
{
$response = ['data' => $this->collection];
if ($this->resource instanceof AbstractPaginator || $this->resource instanceof AbstractCursorPaginator) {
$response = ['data' => ['content' => $this->collection]];
$pagination = (new PaginatedResourceResponse($this))->toArray();
$response['data'] += [
'pageable' => [
// 'sort' => [
// 'sorted' => $request->has('sort'),
// 'unsorted' => ! $request->has('sort'),
// 'empty' => $this->collection->isEmpty(),
// ],
'offset' => $pagination['per_page'] * ($pagination['current_page'] - 1),
// 'pageNumber' => $pagination['current_page'] - 1,
// 'pageSize' => $pagination['per_page'],
'paged' => true,
'unpaged' => false,
],
'total_page' => $pagination['last_page'],
'total_elements' => $pagination['total'],
'number_of_element' => $pagination['total'],
'first' => $pagination['current_page'] === 1,
'last' => $pagination['current_page'] === $pagination['last_page'],
'size' => $pagination['per_page'],
'number' => $pagination['current_page'] - 1,
'empty' => $pagination['total'] === 0,
'sort' => [
'sorted' => $request->has('sort'),
'unsorted' => ! $request->has('sort'),
'empty' => $this->collection->isEmpty(),
],
];
}
return $response;
}
/**
* Create a paginate-aware HTTP response.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
protected function preparePaginatedResponse($request)
{
if ($this->preserveAllQueryParameters) {
$this->resource->appends($request->query());
} elseif (! is_null($this->queryParameters)) {
$this->resource->appends($this->queryParameters);
}
return (new PaginatedResourceResponse($this))->toResponse($request);
}
}
<?php
namespace Laravolt\Crud\Response\AlurKerja;
use Illuminate\Contracts\Support\Responsable;
class ValidationException extends \Illuminate\Validation\ValidationException implements Responsable
{
public $status = 400;
public function toResponse($request)
{
$data = [];
foreach ($this->errors() as $key => $errors) {
foreach ($errors as $error) {
$data[] = [$key => $error];
}
}
return response()->json(
[
'status' => $this->status,
'message' => $this->getMessage(),
'data' => $data,
],
$this->status
);
}
}
<?php
namespace Laravolt\Crud\Response;
use Illuminate\Http\Resources\Json\JsonResource;
class BulkResponse extends JsonResource
{
private const STATUS = 200;
protected array $invalid = [];
public function withResponse($request, $response)
{
$response->setStatusCode(self::STATUS);
}
public function withInvalid(array $invalid): static
{
$this->invalid = $invalid;
return $this;
}
public function toArray($request)
{
return [
'status' => self::STATUS,
'message' => null,
'data' => $this->resource,
'invalid_actions' => $this->invalid,
];
}
}
<?php
namespace Laravolt\Crud\Response;
use Illuminate\Http\Resources\Json\JsonResource;
class DeleteFail extends JsonResource
{
private const STATUS = 422;
public function withResponse($request, $response)
{
$response->setStatusCode(self::STATUS);
}
public function toArray($request)
{
return [
'status' => self::STATUS,
'message' => 'error',
'data' => 'Object deletion failed',
];
}
}
<?php
namespace Laravolt\Crud\Response;
use Illuminate\Http\Resources\Json\JsonResource;
class DeleteSuccess extends JsonResource
{
private const STATUS = 200;
public function withResponse($request, $response)
{
$response->setStatusCode(self::STATUS);
}
public function toArray($request)
{
return [
'status' => self::STATUS,
'message' => 'success',
'data' => 'Object was deleted',
];
}
}
<?php
namespace Laravolt\Crud\Response;
use Illuminate\Http\Resources\Json\JsonResource;
class DomainViolationResponse extends JsonResource
{
private const STATUS = 400;
public function withResponse($request, $response)
{
$response->setStatusCode(self::STATUS);
}
public function toArray($request)
{
return [
'status' => self::STATUS,
'message' => $this->resource,
'data' => [],
];
}
}
<?php
namespace Laravolt\Crud\Response;
use Illuminate\Http\Resources\Json\JsonResource;
class Forbidden extends JsonResource
{
private const STATUS = 403;
public function withResponse($request, $response)
{
$response->setStatusCode(self::STATUS);
}
public function toArray($request)
{
return [
'status' => self::STATUS,
'message' => 'This action is unauthorized',
'data' => [
'url' => $request->fullUrl(),
'payload' => $request->json()->all(),
],
];
}
}
<?php
namespace Laravolt\Crud\Response\Laravolt;
use Illuminate\Http\Resources\Json\JsonResource;
class Resource extends JsonResource
{
public function with($request)
{
return [
'status' => 200,
'message' => 'success',
];
}
}
<?php
namespace Laravolt\Crud\Response\Laravolt;
use Illuminate\Http\Resources\Json\ResourceCollection as BaseResourceCollection;
class ResourceCollection extends BaseResourceCollection
{
public function with($request)
{
return [
'status' => 200,
'message' => 'success',
];
}
}
<?php
namespace Laravolt\Crud\Response;
use Illuminate\Http\Resources\Json\JsonResource;
class NoContent extends JsonResource
{
private const STATUS = 204;
public function withResponse($request, $response)
{
$response->setStatusCode(self::STATUS);
}
public function toArray($request)
{
return [
'status' => self::STATUS,
'message' => 'no_content',
'data' => null,
];
}
}
<?php
namespace Laravolt\Crud\Response;
use Illuminate\Http\Resources\Json\JsonResource;
class NotFound extends JsonResource
{
private const STATUS = 404;
public function withResponse($request, $response)
{
$response->setStatusCode(self::STATUS);
}
public function toArray($request)
{
return [
'status' => self::STATUS,
'message' => $this->resource->getMessage(),
'data' => $this->resource->getTrace(),
];
}
}
<?php
namespace Laravolt\Crud\RouteDiscovery;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Laravolt\Crud\CrudManager;
use Laravolt\Crud\PrimaryKeyFormat;
use Spatie\RouteDiscovery\Attributes\Where;
use Spatie\RouteDiscovery\PendingRoutes\PendingRoute;
use Spatie\RouteDiscovery\PendingRoutes\PendingRouteAction;
use Spatie\RouteDiscovery\PendingRouteTransformers\PendingRouteTransformer;
class HandleCrudRoutes implements PendingRouteTransformer
{
private array $crudMethods = [
'index',
'scope',
'spec',
'show',
'task',
'submitTask',
'create',
'edit',
'store',
'update',
'bulk',
'destroy',
];
private array $excepts = [
'__construct',
'model',
'setFormat',
'authorize',
'authorizeForUser',
'service',
'authorizeResource',
'callAction',
'toBpmnVariables',
'rules',
'guard'
];
public function transform(Collection $pendingRoutes): Collection
{
return $pendingRoutes->each(function (PendingRoute $pendingRoute) {
$pendingRoute->actions = $pendingRoute
->actions
->reject(fn (PendingRouteAction $action) => in_array($action->action[1], $this->excepts, true))
->sortBy(function (PendingRouteAction $action) {
return array_search($action->method->getName(), $this->crudMethods, true);
});
$pendingRoute->actions->each(function (PendingRouteAction $action) {
$crudAction = $action->action[1];
$hasId = collect($action->method->getParameters())->first(function (\ReflectionParameter $param) {
return $param->getName() === 'id';
});
$hasSlug = collect($action->method->getParameters())->first(function (\ReflectionParameter $param) {
return $param->getName() === 'slug';
});
if ($hasId) {
$action->uri = "$action->uri/{id}";
if (CrudManager::getPrimaryKeyFormat() != PrimaryKeyFormat::AUTO) {
$constraint = PrimaryKeyFormat::getRouteConstraint(CrudManager::getPrimaryKeyFormat());
$action->addWhere(new Where('id', $constraint));
} else {
$controller = new $action->action[0]();
$keyType = $controller->model()->getKeyType();
// Check if the model uses UUIDs for primary keys
if ($keyType === 'int') {
$action->addWhere(new Where('id', Where::numeric));
} else {
$action->addWhere(new Where('id', Where::uuid));
}
}
}
if ($hasSlug) {
$action->uri = "$action->uri/{slug}";
}
if (!in_array($crudAction, ['spec', 'import', 'export'])) {
if (!Str::of($action->name)->endsWith($crudAction)) {
$action->name = "$action->name.$crudAction";
}
}
if ($crudAction === 'scope') {
$action->uri = "{$action->uri}/{scope}";
$action->addWhere(new Where('scope', Where::alphanumeric));
}
if ($crudAction === 'task') {
$action->uri = Str::of($action->uri)->replace('/task/{id}', '/{id}/task');
}
if ($crudAction === 'submitTask') {
// dd($action->uri);
$action->uri = Str::of($action->uri)->replace('/submit-task/{taskId}', '/task/{taskId}/submit');
// dd($action->uri);
}
if ($crudAction === 'media') {
$action->uri = Str::of($action->uri)->replace('/media/{id}', '/{id}/media');
}
if ($crudAction === 'media') {
$action->uri = Str::of($action->uri)->replace('/media/{id}', '/{id}/media');
}
});
});
}
}
<?php
namespace Laravolt\Crud\Schema;
use Laravolt\Crud\Schema\Columns\Column;
use Laravolt\Crud\Schema\Columns\StringColumn;
class ColumnFactory
{
public static function make(\Doctrine\DBAL\Schema\Column $column): Column
{
$class = ucfirst($column->getType()->getName());
$classpath = "\\Laravolt\\Crud\\Schema\\Columns\\{$class}Column";
if (class_exists($classpath)) {
return new $classpath($column);
}
return new StringColumn($column);
}
}
<?php
namespace Laravolt\Crud\Schema\Columns;
use Doctrine\DBAL\Schema\Column as DoctrineColumn;
use Illuminate\Support\Str;
abstract class BaseColumn implements Column
{
protected DoctrineColumn $column;
protected string $inputType = 'text';
public function __construct(DoctrineColumn $column)
{
$this->column = $column;
}
public function spec(): array
{
$titleForHuman = Str::of($this->column->getName())->title()->replace('_', ' ');
return [
'name' => strtolower($this->column->getName()),
'label' => $titleForHuman->value(),
'required' => $this->column->getNotnull(),
'type' => $this->inputType(),
'constraints' => [],
'metadata' => [
'format' => null,
'canSort' => true,
'placeholder' => $titleForHuman,
'canFilter' => true,
],
];
}
public function lowcodespec(): array
{
$allowedFilterable = ["varchar", "text"];
$titleForHuman = Str::of($this->column->getName())->title()->replace('_', ' ');
return [
'name' => strtolower($this->column->getName()),
'label' => $titleForHuman->value(),
'required' => $this->column->getNotnull(),
'searchable' => in_array( $this->inputType(), $allowedFilterable),
'filterable' => false,
'sortable' => true,
'type' => $this->inputType(),
'form_field_type' => "INPUT_" . strtoupper($this->inputType()),
'primary' => $this->column->getAutoincrement(),
"is_hidden_in_create" => $this->column->getAutoincrement(),
"is_hidden_in_edit" => $this->column->getAutoincrement(),
"is_hidden_in_list" => false,
"is_hidden_in_detail" => false,
"rules" => $this->rules(),
"format" => $this->getFeFormat(),
"prefix" => "",
"suffix" => ""
//
// {
// "id": "63db511575f8fc542d5e06fc",
// "name": "id",
// "label": "Id",
// "type": "input_text",
// "isPrimary": true,
// "isRequired": true,
// "isHiddenInCreate": false,
// "isHiddenInEdit": false,
// "isHiddenInList": false,
// "format": "",
// "prefix": "",
// "suffix": ""
// },
];
}
public function getFeFormat() : string {
return "";
}
public function rules(): array
{
$nullable = $this->column->getNotnull() === false;
$hasDefault = $this->column->getDefault() !== null;
if ($nullable) {
return ['nullable'];
}
if (!$hasDefault) {
return ['required'];
}
return [];
}
public function inputType(): string
{
return $this->inputType ?? $this->column->getType()->getName();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment