refactor languages module to domain/controller and release 0.254 update package

This commit is contained in:
2026-02-12 22:10:37 +01:00
parent c1284ef06c
commit 95c5fda989
22 changed files with 1190 additions and 490 deletions

View File

@@ -0,0 +1,560 @@
<?php
namespace admin\Controllers;
use Domain\Languages\LanguagesRepository;
use admin\ViewModels\Forms\FormAction;
use admin\ViewModels\Forms\FormEditViewModel;
use admin\ViewModels\Forms\FormField;
use admin\Support\Forms\FormRequestHandler;
class LanguagesController
{
private LanguagesRepository $repository;
private FormRequestHandler $formHandler;
public function __construct(LanguagesRepository $repository)
{
$this->repository = $repository;
$this->formHandler = new FormRequestHandler();
}
public function list(): string
{
$sortableColumns = ['o', 'name', 'status', 'start'];
$filterDefinitions = [
[
'key' => 'name',
'label' => 'Jezyk',
'type' => 'text',
],
[
'key' => 'status',
'label' => 'Aktywny',
'type' => 'select',
'options' => [
'' => '- aktywny -',
'1' => 'tak',
'0' => 'nie',
],
],
[
'key' => 'start',
'label' => 'Domyslny',
'type' => 'select',
'options' => [
'' => '- domyslny -',
'1' => 'tak',
'0' => 'nie',
],
],
];
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
$filterDefinitions,
$sortableColumns,
'o'
);
$sortDir = $listRequest['sortDir'];
if (trim((string)\S::get('sort')) === '') {
$sortDir = 'ASC';
}
$result = $this->repository->listForAdmin(
$listRequest['filters'],
$listRequest['sortColumn'],
$sortDir,
$listRequest['page'],
$listRequest['perPage']
);
$rows = [];
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
foreach ($result['items'] as $item) {
$id = (string)($item['id'] ?? '');
$name = trim((string)($item['name'] ?? ''));
$rows[] = [
'lp' => $lp++ . '.',
'start' => ((int)($item['start'] ?? 0) === 1) ? '<span class="text-system">tak</span>' : 'nie',
'status' => ((int)($item['status'] ?? 0) === 1) ? 'tak' : '<span style="color: #FF0000;">nie</span>',
'name' => '<a href="/admin/languages/language_edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
'_actions' => [
[
'label' => 'Edytuj',
'url' => '/admin/languages/language_edit/id=' . $id,
'class' => 'btn btn-xs btn-primary',
],
[
'label' => 'Usun',
'url' => '/admin/languages/language_delete/id=' . $id,
'class' => 'btn btn-xs btn-danger',
'confirm' => 'Na pewno chcesz usunac wybrany jezyk?',
],
],
];
}
$total = (int)$result['total'];
$totalPages = max(1, (int)ceil($total / $listRequest['perPage']));
$viewModel = new \admin\ViewModels\Common\PaginatedTableViewModel(
[
['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
['key' => 'start', 'sort_key' => 'start', 'label' => 'Domyslny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
['key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
['key' => 'name', 'sort_key' => 'name', 'label' => 'Jezyk', 'sortable' => true, 'raw' => true],
],
$rows,
$listRequest['viewFilters'],
[
'column' => $listRequest['sortColumn'],
'dir' => $sortDir,
],
[
'page' => $listRequest['page'],
'per_page' => $listRequest['perPage'],
'total' => $total,
'total_pages' => $totalPages,
],
array_merge($listRequest['queryFilters'], [
'sort' => $listRequest['sortColumn'],
'dir' => $sortDir,
'per_page' => $listRequest['perPage'],
]),
$listRequest['perPageOptions'],
$sortableColumns,
'/admin/languages/view_list/',
'Brak danych w tabeli.',
'/admin/languages/language_edit/',
'Dodaj jezyk'
);
return \Tpl::view('languages/languages-list', [
'viewModel' => $viewModel,
]);
}
public function view_list(): string
{
return $this->list();
}
public function language_edit(): string
{
$languageId = trim((string)\S::get('id'));
$language = $this->repository->languageDetails($languageId) ?? [];
$validationErrors = $_SESSION['form_errors'][$this->getLanguageFormId()] ?? null;
if ($validationErrors) {
unset($_SESSION['form_errors'][$this->getLanguageFormId()]);
}
return \Tpl::view('languages/language-edit', [
'form' => $this->buildLanguageFormViewModel($language, $this->repository->maxOrder(), $validationErrors),
]);
}
public function language_save(): void
{
$legacyValues = \S::get('values');
if ($legacyValues) {
$values = json_decode((string)$legacyValues, true);
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania jezyka wystapil blad.'];
if (is_array($values)) {
$savedId = $this->repository->saveLanguage(
(string)($values['id'] ?? ''),
(string)($values['name'] ?? ''),
$values['status'] ?? 0,
$values['start'] ?? 0,
(int)($values['o'] ?? 0)
);
if ($savedId) {
$response = ['status' => 'ok', 'msg' => 'Jezyk zostal zapisany.', 'id' => $savedId];
}
}
echo json_encode($response);
exit;
}
$languageId = trim((string)\S::get('id'));
$language = $this->repository->languageDetails($languageId) ?? [];
$viewModel = $this->buildLanguageFormViewModel($language, $this->repository->maxOrder());
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
if (!$result['success']) {
$_SESSION['form_errors'][$this->getLanguageFormId()] = $result['errors'];
echo json_encode(['success' => false, 'errors' => $result['errors']]);
exit;
}
$data = $result['data'];
$requestId = strtolower(trim((string)\S::get('id')));
$idFromData = strtolower(trim((string)($data['id'] ?? '')));
$id = $idFromData !== '' ? $idFromData : $requestId;
if (!preg_match('/^[a-z]{2}$/', $id)) {
echo json_encode([
'success' => false,
'errors' => ['id' => 'ID jezyka musi miec 2 litery (np. pl, en).'],
]);
exit;
}
$savedId = $this->repository->saveLanguage(
$id,
trim((string)($data['name'] ?? '')),
$data['status'] ?? 0,
$data['start'] ?? 0,
(int)($data['o'] ?? 0)
);
if ($savedId) {
echo json_encode([
'success' => true,
'id' => $savedId,
'message' => 'Jezyk zostal zapisany.',
]);
exit;
}
echo json_encode([
'success' => false,
'errors' => ['general' => 'Podczas zapisywania jezyka wystapil blad.'],
]);
exit;
}
public function language_delete(): void
{
if ($this->repository->deleteLanguage((string)\S::get('id'))) {
\S::alert('Jezyk zostal usuniety.');
}
header('Location: /admin/languages/view_list/');
exit;
}
public function translation_list(): string
{
$sortableColumns = ['text', 'id'];
$filterDefinitions = [
[
'key' => 'text',
'label' => 'Tekst',
'type' => 'text',
],
];
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
$filterDefinitions,
$sortableColumns,
'text'
);
$sortDir = $listRequest['sortDir'];
if (trim((string)\S::get('sort')) === '') {
$sortDir = 'ASC';
}
$result = $this->repository->listTranslationsForAdmin(
$listRequest['filters'],
$listRequest['sortColumn'],
$sortDir,
$listRequest['page'],
$listRequest['perPage']
);
$rows = [];
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
foreach ($result['items'] as $item) {
$id = (int)($item['id'] ?? 0);
$text = trim((string)($item['text'] ?? ''));
$rows[] = [
'lp' => $lp++ . '.',
'text' => '<a href="/admin/languages/translation_edit/id=' . $id . '">' . htmlspecialchars($text, ENT_QUOTES, 'UTF-8') . '</a>',
'_actions' => [
[
'label' => 'Edytuj',
'url' => '/admin/languages/translation_edit/id=' . $id,
'class' => 'btn btn-xs btn-primary',
],
[
'label' => 'Usun',
'url' => '/admin/languages/translation_delete/id=' . $id,
'class' => 'btn btn-xs btn-danger',
'confirm' => 'Na pewno chcesz usunac wybrane tlumaczenie?',
],
],
];
}
$total = (int)$result['total'];
$totalPages = max(1, (int)ceil($total / $listRequest['perPage']));
$viewModel = new \admin\ViewModels\Common\PaginatedTableViewModel(
[
['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
['key' => 'text', 'sort_key' => 'text', 'label' => 'Tekst', 'sortable' => true, 'raw' => true],
],
$rows,
$listRequest['viewFilters'],
[
'column' => $listRequest['sortColumn'],
'dir' => $sortDir,
],
[
'page' => $listRequest['page'],
'per_page' => $listRequest['perPage'],
'total' => $total,
'total_pages' => $totalPages,
],
array_merge($listRequest['queryFilters'], [
'sort' => $listRequest['sortColumn'],
'dir' => $sortDir,
'per_page' => $listRequest['perPage'],
]),
$listRequest['perPageOptions'],
$sortableColumns,
'/admin/languages/translation_list/',
'Brak danych w tabeli.',
'/admin/languages/translation_edit/',
'Dodaj tlumaczenie'
);
return \Tpl::view('languages/translations-list', [
'viewModel' => $viewModel,
]);
}
public function translation_edit(): string
{
$translationId = (int)\S::get('id');
$translation = $this->repository->translationDetails($translationId) ?? [];
$languages = $this->repository->languagesList();
$validationErrors = $_SESSION['form_errors'][$this->getTranslationFormId()] ?? null;
if ($validationErrors) {
unset($_SESSION['form_errors'][$this->getTranslationFormId()]);
}
return \Tpl::view('languages/translation-edit', [
'form' => $this->buildTranslationFormViewModel($translation, $languages, $validationErrors),
]);
}
public function translation_save(): void
{
$legacyValues = \S::get('values');
if ($legacyValues) {
$values = json_decode((string)$legacyValues, true);
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania tlumaczenia wystapil blad.'];
if (is_array($values)) {
$languagesMap = $this->extractLegacyTranslations($values, $this->repository->languagesList());
$savedId = $this->repository->saveTranslation(
(int)($values['id'] ?? 0),
(string)($values['text'] ?? ''),
$languagesMap
);
if ($savedId) {
$this->clearLanguageSessions($this->repository->languagesList());
$response = ['status' => 'ok', 'msg' => 'Tlumaczenie zostalo zapisane.', 'id' => $savedId];
}
}
echo json_encode($response);
exit;
}
$translationId = (int)\S::get('id');
$translation = $this->repository->translationDetails($translationId) ?? [];
$languages = $this->repository->languagesList();
$viewModel = $this->buildTranslationFormViewModel($translation, $languages);
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
if (!$result['success']) {
$_SESSION['form_errors'][$this->getTranslationFormId()] = $result['errors'];
echo json_encode(['success' => false, 'errors' => $result['errors']]);
exit;
}
$data = $result['data'];
$languagesMap = [];
foreach ($languages as $language) {
$langId = (string)($language['id'] ?? '');
$key = 'lang_' . $langId;
$languagesMap[$langId] = (string)($data[$key] ?? '');
}
$savedId = $this->repository->saveTranslation(
$translationId,
(string)($data['text'] ?? ''),
$languagesMap
);
if ($savedId) {
$this->clearLanguageSessions($languages);
echo json_encode([
'success' => true,
'id' => $savedId,
'message' => 'Tlumaczenie zostalo zapisane.',
]);
exit;
}
echo json_encode([
'success' => false,
'errors' => ['general' => 'Podczas zapisywania tlumaczenia wystapil blad.'],
]);
exit;
}
public function translation_delete(): void
{
if ($this->repository->deleteTranslation((int)\S::get('id'))) {
\S::alert('Tlumaczenie zostalo usuniete.');
}
header('Location: /admin/languages/translation_list/');
exit;
}
private function buildLanguageFormViewModel(array $language, int $maxOrder, ?array $errors = null): FormEditViewModel
{
$languageId = strtolower(trim((string)($language['id'] ?? '')));
$isNew = $languageId === '';
$data = [
'id' => $languageId,
'name' => (string)($language['name'] ?? ''),
'status' => (int)($language['status'] ?? 0),
'start' => (int)($language['start'] ?? 0),
'o' => (int)($language['o'] ?? ($maxOrder + 1)),
];
$fields = [];
if ($isNew) {
$fields[] = FormField::text('id', [
'label' => 'ID (2 znaki)',
'required' => true,
'attributes' => ['maxlength' => 2],
]);
}
$fields[] = FormField::text('name', [
'label' => 'Jezyk',
'required' => true,
]);
$fields[] = FormField::switch('status', [
'label' => 'Aktywny',
]);
$fields[] = FormField::switch('start', [
'label' => 'Domyslny',
]);
$fields[] = FormField::hidden('o', $data['o']);
$actionUrl = '/admin/languages/language_save/' . ($isNew ? '' : ('id=' . $languageId));
$actions = [
FormAction::save($actionUrl, '/admin/languages/view_list/'),
FormAction::cancel('/admin/languages/view_list/'),
];
return new FormEditViewModel(
$this->getLanguageFormId(),
$isNew ? 'Nowy jezyk' : 'Edycja jezyka',
$data,
$fields,
[],
$actions,
'POST',
$actionUrl,
'/admin/languages/view_list/',
true,
$isNew ? [] : ['id' => $languageId],
null,
$errors
);
}
private function buildTranslationFormViewModel(array $translation, array $languages, ?array $errors = null): FormEditViewModel
{
$translationId = (int)($translation['id'] ?? 0);
$isNew = $translationId <= 0;
$data = [
'id' => $translationId,
'text' => (string)($translation['text'] ?? ''),
];
$fields = [
FormField::text('text', [
'label' => 'Tekst',
'required' => true,
]),
];
foreach ($languages as $language) {
$langId = (string)($language['id'] ?? '');
$fieldName = 'lang_' . $langId;
$data[$fieldName] = (string)($translation[$langId] ?? '');
$fields[] = FormField::text($fieldName, [
'label' => (string)($language['name'] ?? $langId),
]);
}
$actionUrl = '/admin/languages/translation_save/' . ($isNew ? '' : ('id=' . $translationId));
$actions = [
FormAction::save($actionUrl, '/admin/languages/translation_list/'),
FormAction::cancel('/admin/languages/translation_list/'),
];
return new FormEditViewModel(
$this->getTranslationFormId(),
$isNew ? 'Nowe tlumaczenie' : 'Edycja tlumaczenia',
$data,
$fields,
[],
$actions,
'POST',
$actionUrl,
'/admin/languages/translation_list/',
true,
$isNew ? [] : ['id' => $translationId],
null,
$errors
);
}
private function extractLegacyTranslations(array $values, array $languages): array
{
$result = [];
foreach ($languages as $language) {
$langId = (string)($language['id'] ?? '');
$result[$langId] = (string)($values[$langId] ?? '');
}
return $result;
}
private function clearLanguageSessions(array $languages): void
{
foreach ($languages as $language) {
if (!isset($language['id'])) {
continue;
}
\S::delete_session('lang-' . (string)$language['id']);
}
}
private function getLanguageFormId(): string
{
return 'languages-language-edit';
}
private function getTranslationFormId(): string
{
return 'languages-translation-edit';
}
}

View File

@@ -255,6 +255,13 @@ class Site
new \Domain\User\UserRepository( $mdb )
);
},
'Languages' => function() {
global $mdb;
return new \admin\Controllers\LanguagesController(
new \Domain\Languages\LanguagesRepository( $mdb )
);
},
];
return self::$newControllers;

View File

@@ -1,82 +0,0 @@
<?
namespace admin\controls;
class Languages
{
public static function language_delete()
{
if ( \admin\factory\Languages::language_delete( \S::get( 'id' ) ) )
\S::alert( 'Język został usunięty.' );
header( 'Location: /admin/languages/view_list/' );
exit;
}
public static function language_save()
{
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania języka wystąpił błąd. Proszę spróbować ponownie.' ];
$values = json_decode( \S::get( 'values' ), true );
if ( \admin\factory\Languages::language_save(
$values['id'], $values['name'], $values['status'],
$values['start'], $values['o'] ) )
$response = [ 'status' => 'ok', 'msg' => 'Język został zapisany.', 'id' => $id ];
echo json_encode( $response );
exit;
}
public static function language_edit()
{
return \admin\view\Languages::language_edit(
\admin\factory\Languages::language_details(
\S::get( 'id' )
), \admin\factory\Languages::max_order()
);
}
public static function view_list()
{
return \admin\view\Languages::languages_list();
}
public static function translation_delete()
{
if ( \admin\factory\Languages::translation_delete( \S::get( 'id' ) ) )
\S::alert( 'Tłumaczenie zostało usunięte.' );
header( 'Location: /admin/languages/translation_list/' );
exit;
}
public static function translation_save()
{
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania tłumaczenia wystąpił błąd. Proszę spróbować ponownie.' ];
$values = json_decode( \S::get( 'values' ), true );
$languages_list = \admin\factory\Languages::languages_list();
if ( is_array( $languages_list ) and !empty( $languages_list ) ) foreach ( $languages_list as $language )
{
\S::delete_session( 'lang-' . $language['id'] );
$languages[ $language['id'] ] = $values[ $language['id'] ];
}
if ( $id = \admin\factory\Languages::translation_save( $values['id'], $values['text'], $languages ) )
$response = [ 'status' => 'ok', 'msg' => 'Tłumaczenie zostało zapisane.', 'id' => $id ];
echo json_encode( $response );
exit;
}
public static function translation_edit()
{
return \admin\view\Languages::translation_edit(
\admin\factory\Languages::translation_details( \S::get( 'id' ) ),
\admin\factory\Languages::languages_list()
);
}
public static function translation_list()
{
return \admin\view\Languages::translations_list();
}
}
?>

View File

@@ -1,141 +1,53 @@
<?
namespace admin\factory;
class Languages
{
public static function translation_delete( $translation_id )
private static function repository(): \Domain\Languages\LanguagesRepository
{
global $mdb;
return $mdb -> delete( 'pp_langs_translations', [ 'id' => $translation_id ] );
return new \Domain\Languages\LanguagesRepository($mdb);
}
public static function translation_save( $translation_id, $text, $languages )
public static function translation_delete($translation_id)
{
global $mdb;
if ( $translation_id )
{
$mdb -> update( 'pp_langs_translations', [ 'text' => $text ], [ 'id' => $translation_id ] );
if ( is_array( $languages ) and !empty( $languages ) ): foreach ( $languages as $key => $val ):
$mdb -> update( 'pp_langs_translations', [ $key => $val ], [ 'id' => $translation_id ] );
endforeach; endif;
\S::htacces();
\S::delete_dir( '../temp/' );
return $translation_id;
}
else
{
$mdb -> insert( 'pp_langs_translations', [ 'text' => $text ] );
if ( $translation_id = $mdb -> id() )
{
if ( is_array( $languages ) and !empty( $languages ) ): foreach ( $languages as $key => $val ):
$mdb -> update( 'pp_langs_translations', [ $key => $val ], [ 'id' => $translation_id ] );
endforeach; endif;
}
\S::htacces();
\S::delete_dir( '../temp/' );
return $translation_id;
}
return self::repository()->deleteTranslation((int)$translation_id);
}
public static function translation_details( $translation_id )
public static function translation_save($translation_id, $text, $languages)
{
global $mdb;
return $mdb -> get( 'pp_langs_translations', '*', [ 'id' => $translation_id ] );
return self::repository()->saveTranslation((int)$translation_id, (string)$text, is_array($languages) ? $languages : []);
}
public static function language_delete( $language_id )
public static function translation_details($translation_id)
{
global $mdb;
return self::repository()->translationDetails((int)$translation_id);
}
if ( $mdb -> count( 'pp_langs' ) > 1 )
{
if ( $mdb -> query( 'ALTER TABLE pp_langs_translations DROP ' . $language_id )
and
$mdb -> delete( 'pp_langs', [ 'id' => $language_id ] )
)
return true;
}
return false;
public static function language_delete($language_id)
{
return self::repository()->deleteLanguage((string)$language_id);
}
public static function max_order()
{
global $mdb;
return $mdb -> max( 'pp_langs', 'o' );
return self::repository()->maxOrder();
}
public static function language_save( $language_id, $name, $status, $start, $o )
public static function language_save($language_id, $name, $status, $start, $o)
{
global $mdb;
if ( $start == 'on' )
$mdb -> update( 'pp_langs', [
'start' => 0
], [
'id[!]' => $language_id
] );
if ( $mdb -> count( 'pp_langs', [ 'id' => $language_id ] ) )
{
$mdb -> update( 'pp_langs',
[
'status' => $status == 'on' ? 1 : 0,
'start' => $start == 'on' ? 1 : 0,
'name' => $name,
'o' => $o
], [
'id' => $language_id
] );
if ( !$mdb -> count( 'pp_langs', [ 'start' => 1 ] ) )
{
$id_tmp = $mdb -> get( 'pp_langs', 'id', [ 'ORDER' => [ 'o' => 'ASC' ] ] );
$mdb -> update( 'pp_langs', [ 'start' => 1 ], [ 'id' => $id_tmp ] );
}
\S::htacces();
\S::delete_dir( '../temp/' );
return $language_id;
}
else
{
if ( $mdb -> query( 'ALTER TABLE pp_langs_translations ADD ' . $language_id . ' TEXT NULL DEFAULT NULL' ) )
{
$mdb -> insert( 'pp_langs',
[
'id' => $language_id,
'name' => $name,
'status' => $status == 'on' ? 1 : 0,
'start' => $start == 'on' ? 1 : 0,
'o' => $o
] );
\S::htacces();
\S::delete_dir( '../temp/' );
return $language_id;
}
}
return faslse;
return self::repository()->saveLanguage((string)$language_id, (string)$name, $status, $start, (int)$o);
}
public static function language_details( $language_id )
public static function language_details($language_id)
{
global $mdb;
return $mdb -> get( 'pp_langs', '*', [ 'id' => $language_id ] );
return self::repository()->languageDetails((string)$language_id);
}
public static function languages_list( $only_active = false )
public static function languages_list($only_active = false)
{
global $mdb;
$where = [];
if ( $only_active )
$where['status'] = 1;
return $mdb -> select( 'pp_langs', '*', array_merge( [ 'ORDER' => [ 'o' => 'ASC' ] ], $where ) );
return self::repository()->languagesList((bool)$only_active);
}
}
?>
?>

View File

@@ -1,34 +0,0 @@
<?
namespace admin\view;
class Languages
{
public static function translation_edit( $translation, $languages )
{
$tpl = new \Tpl;
$tpl -> languages = $languages;
$tpl -> translation = $translation;
return $tpl -> render( 'languages/translation-edit' );
}
public static function language_edit( $language, $order )
{
$tpl = new \Tpl;
$tpl -> language = $language;
$tpl -> order = $order;
return $tpl -> render( 'languages/language-edit' );
}
public static function translations_list()
{
$tpl = new \Tpl;
return $tpl -> render( 'languages/translations-list' );
}
public static function languages_list()
{
$tpl = new \Tpl;
return $tpl -> render( 'languages/languages-list' );
}
}
?>