Files
thetool/lib/TTCrud/TTCrud.php
2024-11-21 09:12:44 +00:00

280 lines
11 KiB
PHP

<?php
/**
* Class TTCrud
* @property string $headerTitle
* @property string $createText
* @property string|null $historyController
* @property array $columns
* @property array $additionalActions
* @property array $additionalJSVariables
* @property array $infoMessages
* @property bool $onlyView
*/
class TTCrud extends mfBaseController {
public User $user;
private array $checkArray;
public ?array $postData;
/** @noinspection PhpMissingFieldTypeInspection */
public $model;
protected function init() {
$this->needlogin = true;
$me = new User();
$me->loadMe();
$this->user = $me;
$this->layout()->set('me', $me);
if (method_exists($this, 'permissionCheck')) {
$allowed = $this->permissionCheck();
if (!$allowed) {
$this->redirect("Dashboard");
}
} else if (!$me->is(["Admin"])) {
$this->redirect("Dashboard");
}
$modelName = str_replace('Controller', 'Model', get_class($this));
$this->model = new $modelName();
$this->postData = json_decode(file_get_contents('php://input'), true);
$this->checkArray = $this->getCheckArray();
}
/**
* Returns the checkArray for the CRUD component.
* @return array
*/
protected function getCheckArray(): array {
$checkArray = [];
foreach ($this->columns as $column) {
$checkArray[$column['key']] = ['required' => $column['required'] ?? false,
'required_length' => $column['required_length'] ?? 0,
'title' => $column['text'] ?? $column['key'],
'regex' => $column['regex'] ?? false];
}
return $checkArray;
}
protected function indexAction() {
$this->layout()->set('additionalJS', ['js/pages/WarehouseHistory/WarehouseHistoryModal.js']);
$customJsFile = defined('BASEDIR') ? BASEDIR . "/public/js/pages/{$this->mod}/{$this->mod}.js" : null;
if ($customJsFile && file_exists($customJsFile)) {
$pageName = $this->mod;
} else {
$pageName = "DefaultCrudView";
}
$JS_VARIABLES = ["CRUD_CONFIG" => $this->getCrudConfig(),
"CREATE_URL" => $this::getUrl($this->mod . "/create"),
"TABLE_URL" => $this::getUrl($this->mod . "/get"),
"UPDATE_URL" => $this::getUrl($this->mod . "/update"),
"DELETE_URL" => $this::getUrl($this->mod . "/delete"),
"USER_ID" => $this->user->id];
if ($this->additionalJSVariables && is_array($this->additionalJSVariables)) {
$JS_VARIABLES = array_merge($JS_VARIABLES, $this->additionalJSVariables);
}
Helper::renderVue($this, $pageName, $this->headerTitle, $JS_VARIABLES);
}
/**
* Returns the configuration for the CRUD component for the Vue component.
* @return array
*/
protected function getCrudConfig(): array {
if (method_exists($this, 'prepareCrudConfig')) {
$this->prepareCrudConfig();
}
$columns = array_map(function ($column) {
$newColumn = $column;
unset($newColumn['required'], $newColumn['required_length'], $newColumn['regex']);
return $newColumn;
}, $this->columns);
// check if in columns array there is a column with key "actions" and if so, we set the priority of the first column to 20 and actions to 19
$actionsColumn = array_filter($columns, function ($column) {
return $column['key'] === 'actions';
});
if (count($actionsColumn) > 0) {
$columns = array_map(function ($column) {
if ($column['key'] === 'actions') {
$column['priority'] = 119;
}
return $column;
}, $columns);
$columns[0]['priority'] = 120;
}
return ['key' => $this->mod,
'tableHeader' => $this->headerTitle,
'createText' => $this->createText,
'columns' => $columns,
'additionalActions' => $this->additionalActions];
}
protected function getAction() {
$filter = $this->postData['filters'] ?? [];
$order = $this->postData['order'] ?? ['key' => null, 'order' => 'ASC'];
$page = $this->postData['pagination']['page'] ?? 1;
$perPage = $this->postData['pagination']['per_page'] ?? 10;
if ($order['key'] === null && isset($this->defaultOrder)) {
$order = $this->defaultOrder;
}
$rows = $this->model::getAll($filter, $perPage, ($page - 1) * $perPage, $order);
$filteredAvailable = $this->model::count($filter);
$totalRows = $this->model::count();
// check if any column is a autocomplete to add the text to the row
$autoCompleteColumns = array_filter($this->columns, function ($column) {
return isset($column['type']) && isset($column['modal']) && isset($column['modal']['type']) && $column['type'] === 'autocomplete' && $column['modal']['type'] === 'autocomplete';
});
$autocompleteData = [];
foreach ($rows as $row) {
$row = (array) $row;
foreach ($autoCompleteColumns as $column) {
if (isset($autocompleteData[$column['key']][$row[$column['key']]])) {
continue;
}
// if function customAutoComplete"COLUMN_KEY" is defined, we call it instead of the default
$data = null;
if (method_exists($this, 'customAutoComplete' . ucfirst($column['key']))) {
$data = $this->{'customAutoComplete' . ucfirst($column['key'])}($row[$column['key']]);
} else {
$autoCompleteModelName = explode('/', $column['modal']['apiUrl'])[0] . 'Model';
$autoCompleteModel = new $autoCompleteModelName();
$data = $autoCompleteModel::get($row[$column['key']]);
// TODO: fix that keys can be anything
if (isset($data->name) && !isset($data->title)) {
$data->title = $data->name;
}
}
$autocompleteData[$column['key']][$row[$column['key']]] = $data;
}
}
self::returnJson(["rows" => $rows,
"autoCompleteData" => $autocompleteData,
"pagination" => ["page" => $page,
"total_pages" => ceil($filteredAvailable / $perPage),
"per_page" => $perPage,
"filtered_available" => intval($filteredAvailable),
"total_rows" => intval($totalRows)]]);
}
protected function createAction() {
// if this->model has property createBy, set it to the current user id and create to current epoch time
if (property_exists($this->model, 'createBy')) {
$this->postData['createBy'] = $this->user->id;
}
if (property_exists($this->model, 'create')) {
$this->postData['create'] = time();
}
Helper::validateArray($this->postData, $this->checkArray);
if (method_exists($this, 'beforeCreate') && !$this->beforeCreate($this->postData)) {
self::returnJson(['success' => false, 'message' => 'Ein Fehler ist aufgetreten.']);
}
$id = $this->model::create($this->postData);
if (method_exists($this, 'afterCreate')) {
$this->afterCreate(array_merge($this->postData, ['id' => $id]));
}
self::returnJson(['success' => true,
'message' => $this->infoMessages['create'],
'id' => $id]);
}
protected function updateAction() {
if (property_exists($this->model, 'createBy') && !isset($this->postData['createBy'])) {
$this->postData['createBy'] = $this->user->id;
}
if (property_exists($this->model, 'create') && !isset($this->postData['create'])) {
$this->postData['create'] = time();
}
Helper::validateArray($this->postData, array_merge($this->checkArray, ['id' => ['required' => true]]));
if (method_exists($this, 'beforeUpdate') && !$this->beforeUpdate($this->postData)) {
self::returnJson(['success' => false, 'message' => 'Ein Fehler ist aufgetreten.']);
}
$affectedRows = $this->model::update($this->postData);
if (method_exists($this, 'afterUpdate')) {
$this->afterUpdate($this->postData);
}
self::returnJson(['success' => $affectedRows > 0,
'message' => $affectedRows > 0 ? $this->infoMessages['update'] : $this->infoMessages['noChanges']]);
}
protected function deleteAction() {
Helper::validateArray($this->postData, ['id' => ['required' => true]]);
if (method_exists($this, 'beforeDelete') && !$this->beforeDelete($this->postData)) {
self::returnJson(['success' => false, 'message' => 'Ein Fehler ist aufgetreten.']);
}
$affectedRows = $this->model::delete($this->postData['id']);
self::returnJson(['success' => $affectedRows > 0,
'message' => $affectedRows > 0 ? $this->infoMessages['delete'] : $this->infoMessages['noChanges']]);
}
protected function autocompleteAction() {
$searchedID = $this->request->searchedID;
$textKey = property_exists($this->model, 'name') ? 'name' : 'title';
if (strlen($searchedID) > 0) {
$filter = ['id' => $searchedID];
$data = $this->model::getAll($filter, 10);
} else {
$filter = [$textKey => $this->request->q . '%'];
$data = $this->model::getAll($filter, 10);
if (count($data) < 11) {
$filter = [$textKey => $this->request->q];
$lazyData = $this->model::getAll($filter, 10);
$data = array_merge($data, $lazyData);
$data = array_unique($data, SORT_REGULAR);
$data = array_slice($data, 0, 10);
}
}
self::returnJson(array_map(function ($item) use ($textKey) {
return ['value' => $item->id, 'text' => $item->$textKey];
}, $data));
}
protected function getByIdAction() {
$id = $_GET['id'] ?? null;
if (!$id || !is_numeric($id)) {
http_response_code(500);
self::returnJson(['success' => false, 'message' => 'No ID provided.']);
die();
}
$data = (array) $this->model::get($id);
self::returnJson($data);
}
}
?>