Refactor Scontainers management

- Removed legacy Scontainers controller and view files, transitioning to a new controller structure.
- Introduced ScontainersController to handle CRUD operations with improved dependency injection.
- Created ScontainersRepository for database interactions, encapsulating logic for container management.
- Updated container edit and list views to utilize new templating system.
- Added unit tests for ScontainersRepository and ScontainersController to ensure functionality.
- Enhanced form handling for container editing, including validation and error management.
This commit is contained in:
2026-02-12 23:54:56 +01:00
parent 36fe8412e7
commit 42e4396064
15 changed files with 816 additions and 353 deletions

File diff suppressed because one or more lines are too long

View File

@@ -24,3 +24,8 @@ Przed rozpoczęciem implementacji sprawdź aktualną zawartość:
- `TESTING.md`
To ma pomóc zachować spójność zmian i dokumentacji.
## INNE
Przejdźmy teraz do refaktoringu wszystkiego co związane z https://shoppro.project-dc.pl/admin/articles_archive/, nowe widoki, klasy (usuwanie starych), poprawa routingu, przeszukanie innych klas pod względem zależności. Zapisz plan a później realizuj krok po kroku.

View File

@@ -1,123 +1 @@
<script type="text/javascript" src="/libraries/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="/libraries/ckeditor/adapters/jquery.js"></script>
<?
global $db;
ob_start();
?>
<div id="settings-tabs">
<ul class="resp-tabs-list settings-tabs">
<li><i class="fa fa-file"></i>Treść</li>
<li><i class="fa fa-wrench"></i>Ustawienia</li>
</ul>
<div class="resp-tabs-container settings-tabs">
<div>
<div id="languages-main">
<ul class="resp-tabs-list languages-main htabs">
<? if ( is_array( $this -> languages ) ): foreach ( $this -> languages as $lg ):?>
<? if ( $lg['status'] ):?>
<li><?= $lg['name'];?></a></li>
<? endif;?>
<? endforeach; endif;?>
</ul>
<div class="resp-tabs-container languages-main">
<? if ( is_array( $this -> languages ) ): foreach ( $this -> languages as $lg ):?>
<? if ( $lg['status'] ):?>
<div>
<?= \Html::input(
array(
'label' => 'Tytuł',
'name' => 'title[' . $lg['id'] . ']',
'id' => 'title_' . $lg['id'],
'value' => $this -> container['languages'][ $lg['id'] ]['title'],
'inline' => true
)
);?>
<?= \Html::textarea(
array(
'label' => 'Treść',
'name' => 'text[' . $lg['id'] . ']',
'id' => 'text_' . $lg['id'],
'value' => $this -> container['languages'][ $lg['id'] ]['text'],
'inline' => true
)
);?>
<script type="text/javascript">
$( function() {
$( '#text_<?= $lg['id'];?>' ).ckeditor( {
toolbar : 'MyToolbar',
height:'300'
});
});
</script>
</div>
<? endif;?>
<? endforeach; endif;?>
</div>
<div class="clear"></div>
</div>
</div>
<div>
<?= \Html::input_switch(
array(
'label' => 'Aktywny',
'name' => 'status',
'checked' => $this -> container['status'] == 1 or !$this -> container['id'] ? true : false
)
);?>
<?= \Html::input_switch(
array(
'label' => 'Pokaż tytuł',
'name' => 'show_title',
'checked' => $this -> container['show_title'] == 1 ? true : false
)
);?>
</div>
</div>
</div>
<?
$out = ob_get_clean();
$grid = new \gridEdit;
$grid -> id = 'container-edit';
$grid -> gdb_opt = $gdb;
$grid -> include_plugins = true;
$grid -> title = 'Edycja kontenera statycznego';
$grid -> fields = [
[
'db' => 'id',
'type' => 'hidden',
'value' => $this -> container['id']
]
];
$grid -> actions = [
'save' => [ 'url' => '/admin/scontainers/container_save/', 'back_url' => '/admin/scontainers/view_list/' ],
'cancel' => [ 'url' => '/admin/scontainers/view_list/' ]
];
$grid -> external_code = $out;
$grid -> persist_edit = true;
$grid -> id_param = 'id';
echo $grid -> draw();
?>
<script type="text/javascript">
$( function()
{
disable_menu();
$( '#settings-tabs' ).easyResponsiveTabs({
width: 'auto',
fit: true,
tabidentify: 'settings-tabs',
type: 'vertical'
});
$( '#languages-main' ).easyResponsiveTabs({
width: 'auto',
fit: true,
tabidentify: 'languages-main'
});
});
</script>
<script>CKEDITOR.dtd.$removeEmpty['span'] = false;</script>
<?= \Tpl::view('components/form-edit', ['form' => $this->form]); ?>

View File

@@ -1,79 +1 @@
<?php
global $gdb;
$grid = new \grid( 'pp_scontainers' );
$grid -> gdb_opt = $gdb;
$grid -> sql = 'SELECT *'
. 'FROM ( '
. 'SELECT '
. 'id, status, '
. '( SELECT title FROM pp_scontainers_langs AS psl, pp_langs AS pl WHERE lang_id = pl.id AND container_id = ps.id AND title != \'\' ORDER BY o ASC LIMIT 1 ) AS title '
. 'FROM '
. 'pp_scontainers AS ps '
. ') AS q1 '
. 'WHERE '
. '1=1 [where] '
. 'ORDER BY '
. '[order_p1] [order_p2]';
$grid -> sql_count = 'SELECT '
. 'COUNT(0) FROM ( '
. 'SELECT '
. 'id, status, '
. '( SELECT title FROM pp_scontainers_langs AS psl, pp_langs AS pl WHERE lang_id = pl.id AND container_id = ps.id AND title != \'\' ORDER BY o ASC LIMIT 1 ) AS title '
. 'FROM '
. 'pp_scontainers AS ps '
. ') AS q1 '
. 'WHERE '
. '1=1 [where] ';
$grid -> debug = true;
$grid -> order = [ 'column' => 'id', 'type' => 'DESC' ];
$grid -> search = [
[ 'name' => 'Tytuł', 'db' => 'title', 'type' => 'text' ],
[ 'name' => 'Aktywny', 'db' => 'status', 'type' => 'select', 'replace' => [ 'array' => [ 0 => 'nie', 1 => 'tak' ] ] ]
];
$grid -> columns_view = [
[
'name' => 'Lp.',
'th' => [ 'class' => 'g-lp' ],
'td' => [ 'class' => 'g-center' ],
'autoincrement' => true
],
[
'name' => 'Tytuł',
'db' => 'title',
'php' => 'echo "<a href=\'/admin/scontainers/container_edit/id=[id]\'>[title]</a>";',
'sort' => true
],
[
'name' => 'Kod',
'php' => 'echo "[KONTENER:[id]]";'
],
[
'name' => 'Aktywny',
'db' => 'status',
'replace' => [ 'array' => [ 0 => '<span style="color: #FF0000;">nie</span>', 1 => 'tak' ] ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 150px;' ],
'td' => [ 'class' => 'g-center' ]
],
[
'name' => 'Edytuj',
'action' => [ 'type' => 'edit', 'url' => '/admin/scontainers/container_edit/id=[id]' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
'td' => [ 'class' => 'g-center' ]
],
[
'name' => 'Usuń',
'action' => [ 'type' => 'delete', 'url' => '/admin/scontainers/container_delete/id=[id]' ],
'th' => [ 'class' => 'g-center', 'style' => 'width: 70px;' ],
'td' => [ 'class' => 'g-center' ]
]
];
$grid -> buttons = [
[
'label' => 'Dodaj kontener',
'url' => '/admin/scontainers/container_edit/',
'icon' => 'fa-plus-circle',
'class' => 'btn-success'
]
];
echo $grid -> draw();
<?= \Tpl::view('components/table-list', ['list' => $this->viewModel]); ?>

View File

@@ -0,0 +1,311 @@
<?php
namespace Domain\Scontainers;
class ScontainersRepository
{
private const MAX_PER_PAGE = 100;
private $db;
public function __construct($db)
{
$this->db = $db;
}
/**
* @return array{items: array<int, array<string, mixed>>, total: int}
*/
public function listForAdmin(
array $filters,
string $sortColumn = 'id',
string $sortDir = 'DESC',
int $page = 1,
int $perPage = 15
): array {
$allowedSortColumns = [
'id' => 'q1.id',
'title' => 'q1.title',
'status' => 'q1.status',
];
$sortSql = $allowedSortColumns[$sortColumn] ?? 'q1.id';
$sortDir = strtoupper(trim($sortDir)) === 'ASC' ? 'ASC' : 'DESC';
$page = max(1, $page);
$perPage = min(self::MAX_PER_PAGE, max(1, $perPage));
$offset = ($page - 1) * $perPage;
$where = ['1 = 1'];
$params = [];
$title = trim((string)($filters['title'] ?? ''));
if ($title !== '') {
if (strlen($title) > 255) {
$title = substr($title, 0, 255);
}
$where[] = 'q1.title LIKE :title';
$params[':title'] = '%' . $title . '%';
}
$status = trim((string)($filters['status'] ?? ''));
if ($status === '0' || $status === '1') {
$where[] = 'q1.status = :status';
$params[':status'] = (int)$status;
}
$whereSql = implode(' AND ', $where);
$baseSelect = $this->baseListSelect();
$sqlCount = "
SELECT COUNT(0)
FROM ({$baseSelect}) AS q1
WHERE {$whereSql}
";
$stmtCount = $this->db->query($sqlCount, $params);
$countRows = $stmtCount ? $stmtCount->fetchAll() : [];
$total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0;
$sql = "
SELECT q1.*
FROM ({$baseSelect}) AS q1
WHERE {$whereSql}
ORDER BY {$sortSql} {$sortDir}, q1.id DESC
LIMIT {$perPage} OFFSET {$offset}
";
$stmt = $this->db->query($sql, $params);
$items = $stmt ? $stmt->fetchAll() : [];
return [
'items' => is_array($items) ? $items : [],
'total' => $total,
];
}
public function find(int $containerId): array
{
if ($containerId <= 0) {
return $this->defaultContainer();
}
$container = $this->db->get('pp_scontainers', '*', ['id' => $containerId]);
if (!is_array($container)) {
return $this->defaultContainer();
}
$container['languages'] = $this->translationsMap($containerId);
return $container;
}
public function detailsForLanguage(int $containerId, string $langId): ?array
{
if ($containerId <= 0 || trim($langId) === '') {
return null;
}
$container = $this->db->get('pp_scontainers', '*', ['id' => $containerId]);
if (!is_array($container)) {
return null;
}
$translation = $this->db->get('pp_scontainers_langs', '*', [
'AND' => [
'container_id' => $containerId,
'lang_id' => $langId,
],
]);
$container['languages'] = is_array($translation) ? $translation : [
'lang_id' => $langId,
'title' => '',
'text' => '',
];
return $container;
}
public function save(array $data): ?int
{
$containerId = (int)($data['id'] ?? 0);
$status = $this->toSwitchValue($data['status'] ?? 0);
$showTitle = $this->toSwitchValue($data['show_title'] ?? 0);
$translations = $this->extractTranslations($data);
if ($containerId <= 0) {
$this->db->insert('pp_scontainers', [
'status' => $status,
'show_title' => $showTitle,
]);
$containerId = (int)$this->db->id();
if ($containerId <= 0) {
return null;
}
} else {
$this->db->update('pp_scontainers', [
'status' => $status,
'show_title' => $showTitle,
], [
'id' => $containerId,
]);
}
foreach ($translations as $langId => $row) {
$translationId = $this->db->get('pp_scontainers_langs', 'id', [
'AND' => [
'container_id' => $containerId,
'lang_id' => $langId,
],
]);
if ($translationId) {
$this->db->update('pp_scontainers_langs', [
'title' => (string)($row['title'] ?? ''),
'text' => (string)($row['text'] ?? ''),
], [
'id' => (int)$translationId,
]);
} else {
$this->db->insert('pp_scontainers_langs', [
'container_id' => $containerId,
'lang_id' => $langId,
'title' => (string)($row['title'] ?? ''),
'text' => (string)($row['text'] ?? ''),
]);
}
}
\S::delete_dir('../temp/');
$this->clearFrontCache($containerId);
return $containerId;
}
public function delete(int $containerId): bool
{
if ($containerId <= 0) {
return false;
}
$result = (bool)$this->db->delete('pp_scontainers', ['id' => $containerId]);
if ($result) {
$this->clearFrontCache($containerId);
}
return $result;
}
private function baseListSelect(): string
{
return "
SELECT
ps.id,
ps.status,
(
SELECT psl.title
FROM pp_scontainers_langs AS psl
JOIN pp_langs AS pl ON psl.lang_id = pl.id
WHERE psl.container_id = ps.id
AND psl.title <> ''
ORDER BY pl.o ASC
LIMIT 1
) AS title
FROM pp_scontainers AS ps
";
}
private function clearFrontCache(int $containerId): void
{
if ($containerId <= 0 || !class_exists('\CacheHandler')) {
return;
}
$cacheHandler = new \CacheHandler();
$cacheKey = '\front\factory\Scontainers::scontainer_details:' . $containerId;
$cacheHandler->delete($cacheKey);
}
/**
* @return array<string, array<string, mixed>>
*/
private function translationsMap(int $containerId): array
{
$rows = $this->db->select('pp_scontainers_langs', '*', ['container_id' => $containerId]);
if (!is_array($rows)) {
return [];
}
$result = [];
foreach ($rows as $row) {
$langId = (string)($row['lang_id'] ?? '');
if ($langId !== '') {
$result[$langId] = $row;
}
}
return $result;
}
/**
* @return array<string, array<string, string>>
*/
private function extractTranslations(array $data): array
{
$translations = [];
if (isset($data['translations']) && is_array($data['translations'])) {
foreach ($data['translations'] as $langId => $row) {
if (!is_array($row)) {
continue;
}
$safeLangId = trim((string)$langId);
if ($safeLangId === '') {
continue;
}
$translations[$safeLangId] = [
'title' => (string)($row['title'] ?? ''),
'text' => (string)($row['text'] ?? ''),
];
}
}
$legacyTitles = isset($data['title']) && is_array($data['title']) ? $data['title'] : [];
$legacyTexts = isset($data['text']) && is_array($data['text']) ? $data['text'] : [];
foreach ($legacyTitles as $langId => $title) {
$safeLangId = trim((string)$langId);
if ($safeLangId === '') {
continue;
}
if (!isset($translations[$safeLangId])) {
$translations[$safeLangId] = [
'title' => '',
'text' => '',
];
}
$translations[$safeLangId]['title'] = (string)$title;
$translations[$safeLangId]['text'] = (string)($legacyTexts[$safeLangId] ?? '');
}
return $translations;
}
private function toSwitchValue($value): int
{
return ($value === 'on' || $value === 1 || $value === '1' || $value === true) ? 1 : 0;
}
private function defaultContainer(): array
{
return [
'id' => 0,
'status' => 1,
'show_title' => 0,
'languages' => [],
];
}
}

View File

@@ -0,0 +1,297 @@
<?php
namespace admin\Controllers;
use Domain\Languages\LanguagesRepository;
use Domain\Scontainers\ScontainersRepository;
use admin\ViewModels\Common\PaginatedTableViewModel;
use admin\ViewModels\Forms\FormAction;
use admin\ViewModels\Forms\FormEditViewModel;
use admin\ViewModels\Forms\FormField;
use admin\ViewModels\Forms\FormTab;
use admin\Support\Forms\FormRequestHandler;
class ScontainersController
{
private ScontainersRepository $repository;
private LanguagesRepository $languagesRepository;
private FormRequestHandler $formHandler;
public function __construct(ScontainersRepository $repository, LanguagesRepository $languagesRepository)
{
$this->repository = $repository;
$this->languagesRepository = $languagesRepository;
$this->formHandler = new FormRequestHandler();
}
public function list(): string
{
$sortableColumns = ['id', 'title', 'status'];
$filterDefinitions = [
[
'key' => 'title',
'label' => 'Tytul',
'type' => 'text',
],
[
'key' => 'status',
'label' => 'Aktywny',
'type' => 'select',
'options' => [
'' => '- aktywny -',
'1' => 'tak',
'0' => 'nie',
],
],
];
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
$filterDefinitions,
$sortableColumns,
'id'
);
$sortDir = $listRequest['sortDir'];
if (trim((string)\S::get('sort')) === '') {
$sortDir = 'DESC';
}
$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 = (int)($item['id'] ?? 0);
$title = trim((string)($item['title'] ?? ''));
$rows[] = [
'lp' => $lp++ . '.',
'title' => '<a href="/admin/scontainers/container_edit/id=' . $id . '">' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '</a>',
'code' => '[KONTENER:' . $id . ']',
'status' => ((int)($item['status'] ?? 0) === 1) ? 'tak' : '<span style="color: #FF0000;">nie</span>',
'_actions' => [
[
'label' => 'Edytuj',
'url' => '/admin/scontainers/container_edit/id=' . $id,
'class' => 'btn btn-xs btn-primary',
],
[
'label' => 'Usun',
'url' => '/admin/scontainers/container_delete/id=' . $id,
'class' => 'btn btn-xs btn-danger',
'confirm' => 'Na pewno chcesz usunac wybrany kontener?',
],
],
];
}
$total = (int)$result['total'];
$totalPages = max(1, (int)ceil($total / $listRequest['perPage']));
$viewModel = new PaginatedTableViewModel(
[
['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
['key' => 'title', 'sort_key' => 'title', 'label' => 'Tytul', 'sortable' => true, 'raw' => true],
['key' => 'code', 'label' => 'Kod', 'sortable' => false],
['key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', '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/scontainers/view_list/',
'Brak danych w tabeli.',
'/admin/scontainers/container_edit/',
'Dodaj kontener'
);
return \Tpl::view('scontainers/containers-list', [
'viewModel' => $viewModel,
]);
}
public function view_list(): string
{
return $this->list();
}
public function edit(): string
{
$container = $this->repository->find((int)\S::get('id'));
$languages = $this->languagesRepository->languagesList();
$validationErrors = $_SESSION['form_errors'][$this->formId()] ?? null;
if ($validationErrors) {
unset($_SESSION['form_errors'][$this->formId()]);
}
return \Tpl::view('scontainers/container-edit', [
'form' => $this->buildFormViewModel($container, $languages, $validationErrors),
]);
}
public function container_edit(): string
{
return $this->edit();
}
public function save(): void
{
$legacyValues = \S::get('values');
if ($legacyValues) {
$values = json_decode((string)$legacyValues, true);
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania kontenera wystapil blad.'];
if (is_array($values)) {
$savedId = $this->repository->save($values);
if (!empty($savedId)) {
$response = ['status' => 'ok', 'msg' => 'Kontener zostal zapisany.', 'id' => $savedId];
}
}
echo json_encode($response);
exit;
}
$container = $this->repository->find((int)\S::get('id'));
$languages = $this->languagesRepository->languagesList();
$form = $this->buildFormViewModel($container, $languages);
$result = $this->formHandler->handleSubmit($form, $_POST);
if (!$result['success']) {
$_SESSION['form_errors'][$this->formId()] = $result['errors'];
echo json_encode(['success' => false, 'errors' => $result['errors']]);
exit;
}
$data = $result['data'];
$savedId = $this->repository->save([
'id' => (int)($data['id'] ?? 0),
'status' => $data['status'] ?? 0,
'show_title' => $data['show_title'] ?? 0,
'translations' => $data['translations'] ?? [],
]);
if ($savedId) {
echo json_encode([
'success' => true,
'id' => $savedId,
'message' => 'Kontener zostal zapisany.',
]);
exit;
}
echo json_encode([
'success' => false,
'errors' => ['general' => 'Podczas zapisywania kontenera wystapil blad.'],
]);
exit;
}
public function container_save(): void
{
$this->save();
}
public function delete(): void
{
if ($this->repository->delete((int)\S::get('id'))) {
\S::alert('Kontener zostal usuniety.');
}
header('Location: /admin/scontainers/view_list/');
exit;
}
public function container_delete(): void
{
$this->delete();
}
private function buildFormViewModel(array $container, array $languages, ?array $errors = null): FormEditViewModel
{
$id = (int)($container['id'] ?? 0);
$isNew = $id <= 0;
$data = [
'id' => $id,
'status' => (int)($container['status'] ?? 1),
'show_title' => (int)($container['show_title'] ?? 0),
'languages' => is_array($container['languages'] ?? null) ? $container['languages'] : [],
];
$fields = [
FormField::hidden('id', $id),
FormField::langSection('translations', 'content', [
FormField::text('title', [
'label' => 'Tytul',
]),
FormField::editor('text', [
'label' => 'Tresc',
'height' => 300,
]),
]),
FormField::switch('status', [
'label' => 'Aktywny',
'tab' => 'settings',
'value' => true,
]),
FormField::switch('show_title', [
'label' => 'Pokaz tytul',
'tab' => 'settings',
]),
];
$tabs = [
new FormTab('content', 'Tresc', 'fa-file'),
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
];
$actionUrl = '/admin/scontainers/container_save/' . ($isNew ? '' : ('id=' . $id));
$actions = [
FormAction::save($actionUrl, '/admin/scontainers/view_list/'),
FormAction::cancel('/admin/scontainers/view_list/'),
];
return new FormEditViewModel(
$this->formId(),
'Edycja kontenera statycznego',
$data,
$fields,
$tabs,
$actions,
'POST',
$actionUrl,
'/admin/scontainers/view_list/',
true,
[],
$languages,
$errors
);
}
private function formId(): string
{
return 'scontainers-container-edit';
}
}

View File

@@ -66,11 +66,28 @@ class Pages
'parent_id' => \S::get( 'pid' ),
'menu_id' => \S::get( 'menu_id' ),
'menus' => \admin\factory\Pages::menu_lists(),
'layouts' => \admin\factory\Layouts::layouts_list(),
'layouts' => self::layouts_for_page_edit( $GLOBALS['mdb'] ),
'languages' => ( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->languagesList()
] );
}
private static function layouts_for_page_edit( $db )
{
if ( class_exists( '\Domain\Layouts\LayoutsRepository' ) )
{
$rows = ( new \Domain\Layouts\LayoutsRepository( $db ) ) -> listAll();
return is_array( $rows ) ? $rows : [];
}
if ( class_exists( '\admin\factory\Layouts' ) )
{
$rows = \admin\factory\Layouts::layouts_list();
return is_array( $rows ) ? $rows : [];
}
return [];
}
public static function menu_save()
{
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania menu wystąpił błąd. Proszę spróbować ponownie.' ];

View File

@@ -1,40 +0,0 @@
<?php
namespace admin\controls;
class Scontainers
{
public static function container_delete()
{
if ( \admin\factory\Scontainers::container_delete( \S::get( 'id' ) ) )
\S::alert( 'Kontener został usunięty.' );
header( 'Location: /admin/scontainers/view_list/' );
exit;
}
public static function container_save()
{
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania kontenera wystąpił błąd. Proszę spróbować ponownie.' ];
$values = json_decode( \S::get( 'values' ), true );
if ( $id = \admin\factory\Scontainers::container_save( $values['id'], $values['title'], $values['text'], $values['status'], $values['show_title'] ) )
$response = [ 'status' => 'ok', 'msg' => 'Kontener został zapisany.', 'id' => $id ];
echo json_encode( $response );
exit;
}
public static function container_edit()
{
return \admin\view\Scontainers::container_edit(
\admin\factory\Scontainers::container_details(
\S::get( 'id' )
),
( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->languagesList()
);
}
public static function view_list()
{
return \admin\view\Scontainers::containers_list();
}
}

View File

@@ -244,7 +244,7 @@ class ShopProduct
'product' => \admin\factory\ShopProduct::product_details( (int) \S::get( 'id' ) ),
'languages' => ( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->languagesList(),
'categories' => \admin\factory\ShopCategory::subcategories( null ),
'layouts' => \admin\factory\Layouts::layouts_list(),
'layouts' => self::layouts_for_product_edit( $mdb ),
'products' => \admin\factory\ShopProduct::products_list(),
'dlang' => \front\factory\Languages::default_language(),
'sets' => \shop\ProductSet::sets_list(),
@@ -254,6 +254,23 @@ class ShopProduct
] );
}
private static function layouts_for_product_edit( $db )
{
if ( class_exists( '\Domain\Layouts\LayoutsRepository' ) )
{
$rows = ( new \Domain\Layouts\LayoutsRepository( $db ) ) -> listAll();
return is_array( $rows ) ? $rows : [];
}
if ( class_exists( '\admin\factory\Layouts' ) )
{
$rows = \admin\factory\Layouts::layouts_list();
return is_array( $rows ) ? $rows : [];
}
return [];
}
// ajax_load_products ARCHIVE
static public function ajax_load_products_archive()
{

View File

@@ -3,86 +3,30 @@ namespace admin\factory;
class Scontainers
{
public static function container_delete( $container_id )
private static function repository(): \Domain\Scontainers\ScontainersRepository
{
global $mdb;
return $mdb -> delete( 'pp_scontainers', [ 'id' => (int)$container_id ] );
return new \Domain\Scontainers\ScontainersRepository($mdb);
}
public static function container_save( $container_id, $title, $text, $status, $show_title )
public static function container_delete($container_id)
{
global $mdb;
if ( !$container_id )
{
$mdb -> insert( 'pp_scontainers', [
'status' => $status == 'on' ? 1 : 0,
'show_title' => $show_title == 'on' ? 1 : 0
] );
$id = $mdb -> id();
if ( $id )
{
foreach ( $title as $key => $val )
{
$mdb -> insert( 'pp_scontainers_langs', [
'container_id' => (int)$id,
'lang_id' => $key,
'title' => $title[$key],
'text' => $text[$key]
] );
}
\S::delete_dir( '../temp/' );
return $id;
}
}
else
{
$mdb -> update( 'pp_scontainers', [
'status' => $status == 'on' ? 1 : 0,
'show_title' => $show_title == 'on' ? 1 : 0
], [
'id' => (int)$container_id
] );
foreach ( $title as $key => $val )
{
if ( $translation_id = $mdb -> get( 'pp_scontainers_langs', 'id', [ 'AND' => [ 'container_id' => $container_id, 'lang_id' => $key ] ] ) )
$mdb -> update( 'pp_scontainers_langs', [
'lang_id' => $key,
'title' => $title[$key],
'text' => $text[$key]
], [
'id' => $translation_id
] );
else
$mdb -> insert( 'pp_scontainers_langs', [
'container_id' => (int)$container_id,
'lang_id' => $key,
'title' => $title[$key],
'text' => $text[$key]
] );
}
\S::delete_dir( '../temp/' );
return $container_id;
}
return self::repository()->delete((int)$container_id);
}
public static function container_details( $container_id )
public static function container_save($container_id, $title, $text, $status, $show_title)
{
global $mdb;
$container = $mdb -> get( 'pp_scontainers', '*', [ 'id' => (int)$container_id ] );
$results = $mdb -> select( 'pp_scontainers_langs', '*', [ 'container_id' => (int)$container_id ] );
if ( is_array( $results ) ) foreach ( $results as $row )
$container['languages'][ $row['lang_id'] ] = $row;
return $container;
return self::repository()->save([
'id' => (int)$container_id,
'title' => is_array($title) ? $title : [],
'text' => is_array($text) ? $text : [],
'status' => $status,
'show_title' => $show_title,
]);
}
}
public static function container_details($container_id)
{
return self::repository()->find((int)$container_id);
}
}

View File

@@ -1,20 +0,0 @@
<?php
namespace admin\view;
class Scontainers
{
public static function container_edit( $container, $languages )
{
$tpl = new \Tpl;
$tpl -> container = $container;
$tpl -> languages = $languages;
return $tpl -> render( 'scontainers/container-edit' );
}
public static function containers_list()
{
$tpl = new \Tpl;
return $tpl -> render( 'scontainers/containers-list' );
}
}

View File

@@ -3,7 +3,7 @@ namespace front\factory;
class Scontainers
{
public static function scontainer_details( $scontainer_id )
public static function scontainer_details($scontainer_id)
{
global $mdb, $lang;
@@ -11,21 +11,29 @@ class Scontainers
$cacheKey = "\front\factory\Scontainers::scontainer_details:$scontainer_id";
$objectData = $cacheHandler->get($cacheKey);
if ( !$objectData )
{
$scontainer = $mdb -> get( 'pp_scontainers', '*', [ 'id' => (int)$scontainer_id ] );
$results = $mdb -> select( 'pp_scontainers_langs', '*', [ 'AND' => [ 'container_id' => (int)$scontainer_id, 'lang_id' => $lang[0] ] ] );
if ( is_array( $results ) ) foreach ( $results as $row )
$scontainer['languages'] = $row;
$cacheHandler -> set( $cacheKey, $scontainer );
}
else
{
if ($objectData) {
return unserialize($objectData);
}
$repository = new \Domain\Scontainers\ScontainersRepository($mdb);
$langId = (string)($lang[0] ?? 'pl');
$scontainer = $repository->detailsForLanguage((int)$scontainer_id, $langId);
if (!is_array($scontainer)) {
$scontainer = [
'id' => (int)$scontainer_id,
'status' => 0,
'show_title' => 0,
'languages' => [
'lang_id' => $langId,
'title' => '',
'text' => '',
],
];
}
$cacheHandler->set($cacheKey, $scontainer);
return $scontainer;
}
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Tests\Unit\Domain\Scontainers;
use PHPUnit\Framework\TestCase;
use Domain\Scontainers\ScontainersRepository;
class ScontainersRepositoryTest extends TestCase
{
public function testFindReturnsDefaultContainerForInvalidId(): void
{
$mockDb = $this->createMock(\medoo::class);
$repository = new ScontainersRepository($mockDb);
$container = $repository->find(0);
$this->assertIsArray($container);
$this->assertSame(0, (int)$container['id']);
$this->assertSame(1, (int)$container['status']);
}
public function testDeleteReturnsFalseForInvalidId(): void
{
$mockDb = $this->createMock(\medoo::class);
$repository = new ScontainersRepository($mockDb);
$this->assertFalse($repository->delete(0));
}
public function testFindReturnsContainerWithTranslations(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('get')
->with('pp_scontainers', '*', ['id' => 7])
->willReturn(['id' => 7, 'status' => 1, 'show_title' => 1]);
$mockDb->expects($this->once())
->method('select')
->with('pp_scontainers_langs', '*', ['container_id' => 7])
->willReturn([
['lang_id' => 'pl', 'title' => 'Tytul PL', 'text' => 'Tekst PL'],
['lang_id' => 'en', 'title' => 'Title EN', 'text' => 'Text EN'],
]);
$repository = new ScontainersRepository($mockDb);
$container = $repository->find(7);
$this->assertSame(7, (int)$container['id']);
$this->assertArrayHasKey('languages', $container);
$this->assertArrayHasKey('pl', $container['languages']);
$this->assertArrayHasKey('en', $container['languages']);
}
public function testDetailsForLanguageReturnsNullForInvalidData(): void
{
$mockDb = $this->createMock(\medoo::class);
$repository = new ScontainersRepository($mockDb);
$this->assertNull($repository->detailsForLanguage(0, 'pl'));
$this->assertNull($repository->detailsForLanguage(1, ''));
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Tests\Unit\admin\Controllers;
use PHPUnit\Framework\TestCase;
use admin\Controllers\ScontainersController;
use Domain\Scontainers\ScontainersRepository;
use Domain\Languages\LanguagesRepository;
class ScontainersControllerTest extends TestCase
{
private $repository;
private $languagesRepository;
private $controller;
protected function setUp(): void
{
$this->repository = $this->createMock(ScontainersRepository::class);
$this->languagesRepository = $this->createMock(LanguagesRepository::class);
$this->controller = new ScontainersController($this->repository, $this->languagesRepository);
}
public function testConstructorAcceptsDependencies(): void
{
$controller = new ScontainersController($this->repository, $this->languagesRepository);
$this->assertInstanceOf(ScontainersController::class, $controller);
}
public function testHasMainActionMethods(): void
{
$this->assertTrue(method_exists($this->controller, 'list'));
$this->assertTrue(method_exists($this->controller, 'view_list'));
$this->assertTrue(method_exists($this->controller, 'edit'));
$this->assertTrue(method_exists($this->controller, 'save'));
$this->assertTrue(method_exists($this->controller, 'delete'));
}
public function testActionMethodReturnTypes(): void
{
$reflection = new \ReflectionClass($this->controller);
$this->assertEquals('string', (string)$reflection->getMethod('list')->getReturnType());
$this->assertEquals('string', (string)$reflection->getMethod('view_list')->getReturnType());
$this->assertEquals('string', (string)$reflection->getMethod('edit')->getReturnType());
$this->assertEquals('void', (string)$reflection->getMethod('save')->getReturnType());
$this->assertEquals('void', (string)$reflection->getMethod('delete')->getReturnType());
}
public function testConstructorRequiresRepositoryAndLanguagesRepository(): void
{
$reflection = new \ReflectionClass(ScontainersController::class);
$constructor = $reflection->getConstructor();
$params = $constructor->getParameters();
$this->assertCount(2, $params);
$this->assertEquals('Domain\Scontainers\ScontainersRepository', $params[0]->getType()->getName());
$this->assertEquals('Domain\Languages\LanguagesRepository', $params[1]->getType()->getName());
}
}

View File

@@ -0,0 +1,2 @@
F: ../autoload/admin/controls/class.Scontainers.php
F: ../autoload/admin/view/class.Scontainers.php