Add view classes for articles, banners, languages, menu, newsletter, containers, shop categories, clients, payment methods, products, and search
- Created Articles.php for rendering article views including full articles, miniature lists, and news sections. - Added Banners.php for handling banner displays. - Introduced Languages.php for rendering language options. - Implemented Menu.php for dynamic menu rendering. - Developed Newsletter.php for newsletter view rendering. - Created Scontainers.php for rendering specific containers. - Added ShopCategory.php for category descriptions and product listings. - Introduced ShopClient.php for managing client-related views such as address editing and order history. - Implemented ShopPaymentMethod.php for displaying payment methods in the basket. - Created ShopProduct.php for generating product URLs. - Added ShopSearch.php for rendering a simple search form. - Added .htaccess file to enhance security by restricting access to sensitive files and directories.
This commit is contained in:
147
autoload/admin/Controllers/ArticlesArchiveController.php
Normal file
147
autoload/admin/Controllers/ArticlesArchiveController.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Article\ArticleRepository;
|
||||
use admin\ViewModels\Common\PaginatedTableViewModel;
|
||||
|
||||
class ArticlesArchiveController
|
||||
{
|
||||
private ArticleRepository $repository;
|
||||
|
||||
public function __construct(ArticleRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['title', 'date_add', 'date_modify'];
|
||||
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'title',
|
||||
'label' => 'Tytul',
|
||||
'type' => 'text',
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'date_add'
|
||||
);
|
||||
|
||||
$result = $this->repository->listArchivedForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$listRequest['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/articles/edit/id=' . $id . '">' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'date_add' => !empty($item['date_add']) ? date('Y-m-d H:i', strtotime((string)$item['date_add'])) : '-',
|
||||
'date_modify' => !empty($item['date_modify']) ? date('Y-m-d H:i', strtotime((string)$item['date_modify'])) : '-',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Przywroc',
|
||||
'url' => '/admin/articles_archive/restore/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-success',
|
||||
'confirm' => 'Na pewno chcesz przywrocic wybrany artykul?',
|
||||
'confirm_ok' => 'Przywroc',
|
||||
'confirm_cancel' => 'Anuluj',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/articles_archive/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz trwale usunac wybrany artykul?',
|
||||
'confirm_ok' => 'Usun',
|
||||
'confirm_cancel' => 'Anuluj',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'date_add', 'sort_key' => 'date_add', 'label' => 'Data dodania', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'date_modify', 'sort_key' => 'date_modify', 'label' => 'Data modyfikacji', 'class' => 'text-center', 'sortable' => true],
|
||||
],
|
||||
$rows,
|
||||
$listRequest['viewFilters'],
|
||||
[
|
||||
'column' => $listRequest['sortColumn'],
|
||||
'dir' => $listRequest['sortDir'],
|
||||
],
|
||||
[
|
||||
'page' => $listRequest['page'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
'total' => $total,
|
||||
'total_pages' => $totalPages,
|
||||
],
|
||||
array_merge($listRequest['queryFilters'], [
|
||||
'sort' => $listRequest['sortColumn'],
|
||||
'dir' => $listRequest['sortDir'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
]),
|
||||
$listRequest['perPageOptions'],
|
||||
$sortableColumns,
|
||||
'/admin/articles_archive/list/',
|
||||
'Brak danych w tabeli.'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('articles/articles-archive-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function restore(): void
|
||||
{
|
||||
if ($this->repository->restore((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Artykul zostal przywrocony.');
|
||||
}
|
||||
|
||||
header('Location: /admin/articles_archive/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function article_restore(): void
|
||||
{
|
||||
$this->restore();
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->deletePermanently((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Artykul zostal trwale usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/articles_archive/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function article_delete(): void
|
||||
{
|
||||
$this->delete();
|
||||
}
|
||||
}
|
||||
509
autoload/admin/Controllers/ArticlesController.php
Normal file
509
autoload/admin/Controllers/ArticlesController.php
Normal file
@@ -0,0 +1,509 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Article\ArticleRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
use Domain\Layouts\LayoutsRepository;
|
||||
use Domain\Pages\PagesRepository;
|
||||
use admin\ViewModels\Forms\FormAction;
|
||||
use admin\ViewModels\Forms\FormEditViewModel;
|
||||
use admin\ViewModels\Forms\FormField;
|
||||
use admin\ViewModels\Forms\FormTab;
|
||||
|
||||
class ArticlesController
|
||||
{
|
||||
private ArticleRepository $repository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
private LayoutsRepository $layoutsRepository;
|
||||
private PagesRepository $pagesRepository;
|
||||
|
||||
public function __construct(
|
||||
ArticleRepository $repository,
|
||||
LanguagesRepository $languagesRepository,
|
||||
LayoutsRepository $layoutsRepository,
|
||||
PagesRepository $pagesRepository
|
||||
)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
$this->layoutsRepository = $layoutsRepository;
|
||||
$this->pagesRepository = $pagesRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista artykulow
|
||||
*/
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['title', 'status', 'date_add', 'date_modify'];
|
||||
|
||||
$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,
|
||||
'date_add'
|
||||
);
|
||||
|
||||
$result = $this->repository->listForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$listRequest['sortDir'],
|
||||
$listRequest['page'],
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$articleIds = [];
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)($item['id'] ?? 0);
|
||||
if ($id > 0) {
|
||||
$articleIds[] = $id;
|
||||
}
|
||||
}
|
||||
$pagesSummary = $this->repository->pagesSummaryForArticles($articleIds);
|
||||
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)$item['id'];
|
||||
$title = (string)($item['title'] ?? '');
|
||||
$pages = (string)($pagesSummary[$id] ?? '');
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'title' => '<a href="/admin/articles/edit/id=' . $id . '">' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '</a>'
|
||||
. '<small class="text-muted">' . htmlspecialchars($pages, ENT_QUOTES, 'UTF-8') . '</small>',
|
||||
'status' => ((int)$item['status'] === 1) ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'date_add' => !empty($item['date_add']) ? date('Y-m-d H:i', strtotime((string)$item['date_add'])) : '-',
|
||||
'date_modify' => !empty($item['date_modify']) ? date('Y-m-d H:i', strtotime((string)$item['date_modify'])) : '-',
|
||||
'user' => htmlspecialchars((string)($item['user'] ?? ''), ENT_QUOTES, 'UTF-8'),
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/articles/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/articles/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrany element?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'title', 'sort_key' => 'title', 'label' => 'Tytul', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'date_add', 'sort_key' => 'date_add', 'label' => 'Data dodania', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'date_modify', 'sort_key' => 'date_modify', 'label' => 'Data modyfikacji', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'user', 'sort_key' => 'user', 'label' => 'Modyfikowany przez', 'class' => 'text-center', 'sortable' => true],
|
||||
],
|
||||
$rows,
|
||||
$listRequest['viewFilters'],
|
||||
[
|
||||
'column' => $listRequest['sortColumn'],
|
||||
'dir' => $listRequest['sortDir'],
|
||||
],
|
||||
[
|
||||
'page' => $listRequest['page'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
'total' => $total,
|
||||
'total_pages' => $totalPages,
|
||||
],
|
||||
array_merge($listRequest['queryFilters'], [
|
||||
'sort' => $listRequest['sortColumn'],
|
||||
'dir' => $listRequest['sortDir'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
]),
|
||||
$listRequest['perPageOptions'],
|
||||
$sortableColumns,
|
||||
'/admin/articles/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/articles/edit/',
|
||||
'Dodaj artykul'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('articles/articles-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapis kolejnosci galerii (AJAX)
|
||||
*/
|
||||
public function galleryOrderSave(): void
|
||||
{
|
||||
if ($this->repository->saveGalleryOrder((int)\Shared\Helpers\Helpers::get('article_id'), (string)\Shared\Helpers\Helpers::get('order'))) {
|
||||
echo json_encode(['status' => 'ok', 'msg' => 'Artykul zostal zapisany.']);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapis kolejnosci zalacznikow (AJAX)
|
||||
*/
|
||||
public function filesOrderSave(): void
|
||||
{
|
||||
if ($this->repository->saveFilesOrder((int)\Shared\Helpers\Helpers::get('article_id'), (string)\Shared\Helpers\Helpers::get('order'))) {
|
||||
echo json_encode(['status' => 'ok', 'msg' => 'Artykul zostal zapisany.']);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapis artykulu (AJAX)
|
||||
*/
|
||||
public function save(): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
$values = $this->resolveSavePayload();
|
||||
$articleId = (int)($values['id'] ?? \Shared\Helpers\Helpers::get('id') ?? 0);
|
||||
$id = $this->repository->save($articleId, $values, (int)$user['id']);
|
||||
|
||||
if ($id) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'status' => 'ok',
|
||||
'message' => 'Artykul zostal zapisany.',
|
||||
'msg' => 'Artykul zostal zapisany.',
|
||||
'id' => (int)$id,
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'status' => 'error',
|
||||
'message' => 'Podczas zapisywania artykulu wystapil blad. Prosze sprobowac ponownie.',
|
||||
'msg' => 'Podczas zapisywania artykulu wystapil blad. Prosze sprobowac ponownie.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function imageAltChange(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zmiany atrybutu alt zdjecia wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->updateImageAlt((int)\Shared\Helpers\Helpers::get('image_id'), (string)\Shared\Helpers\Helpers::get('image_alt'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function fileNameChange(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zmiany nazwy zalacznika wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->updateFileName((int)\Shared\Helpers\Helpers::get('file_id'), (string)\Shared\Helpers\Helpers::get('file_name'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function imageDelete(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas usuwania zdjecia wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->markImageToDelete((int)\Shared\Helpers\Helpers::get('image_id'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function fileDelete(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas usuwania zalacznika wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->markFileToDelete((int)\Shared\Helpers\Helpers::get('file_id'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Archiwizacja artykulu (ustawia status = -1)
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->archive((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Artykul zostal przeniesiony do archiwum.');
|
||||
}
|
||||
|
||||
header('Location: /admin/articles/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edycja artykulu
|
||||
*/
|
||||
public function edit(): string
|
||||
{
|
||||
global $user;
|
||||
|
||||
if (!$user) {
|
||||
header('Location: /admin/');
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->repository->deleteNonassignedImages();
|
||||
$this->repository->deleteNonassignedFiles();
|
||||
|
||||
$article = $this->repository->find((int)\Shared\Helpers\Helpers::get('id')) ?: ['id' => 0, 'languages' => [], 'images' => [], 'files' => [], 'pages' => []];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
$menus = $this->pagesRepository->menusList();
|
||||
$layouts = $this->layoutsRepository->listAll();
|
||||
|
||||
$viewModel = $this->buildFormViewModel($article, $languages, $menus, $layouts);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('articles/article-edit', [
|
||||
'form' => $viewModel,
|
||||
'article' => $article,
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
|
||||
private function resolveSavePayload(): array
|
||||
{
|
||||
$legacyValuesRaw = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValuesRaw !== null && $legacyValuesRaw !== '') {
|
||||
$legacyValues = json_decode((string)$legacyValuesRaw, true);
|
||||
if (is_array($legacyValues)) {
|
||||
return $legacyValues;
|
||||
}
|
||||
}
|
||||
|
||||
$payload = $_POST;
|
||||
unset($payload['_form_id']);
|
||||
|
||||
return is_array($payload) ? $payload : [];
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $article, array $languages, array $menus, array $layouts): FormEditViewModel
|
||||
{
|
||||
$articleId = (int)($article['id'] ?? 0);
|
||||
$defaultLanguageId = (string)($this->languagesRepository->defaultLanguageId() ?? 'pl');
|
||||
$title = $articleId > 0
|
||||
? 'Edycja artykulu: <u>' . $this->escapeHtml((string)($article['languages'][$defaultLanguageId]['title'] ?? '')) . '</u>'
|
||||
: 'Edycja artykulu';
|
||||
|
||||
$layoutOptions = ['' => '---- szablon domyslny ----'];
|
||||
foreach ($layouts as $layout) {
|
||||
$layoutOptions[(string)$layout['id']] = (string)$layout['name'];
|
||||
}
|
||||
|
||||
$copyFromOptions = ['' => '---- wersja jezykowa ----'];
|
||||
foreach ($languages as $language) {
|
||||
if (!empty($language['id'])) {
|
||||
$copyFromOptions[(string)$language['id']] = (string)$language['name'];
|
||||
}
|
||||
}
|
||||
|
||||
$tabs = [
|
||||
new FormTab('content', 'Tresc', 'fa-file'),
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
new FormTab('seo', 'SEO', 'fa-globe'),
|
||||
new FormTab('display', 'Wyswietlanie', 'fa-share-alt'),
|
||||
new FormTab('gallery', 'Galeria', 'fa-file-image-o'),
|
||||
new FormTab('files', 'Zalaczniki', 'fa-file-archive-o'),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $articleId),
|
||||
FormField::langSection('article_content', 'content', [
|
||||
FormField::select('copy_from', [
|
||||
'label' => 'Wyswietlaj tresc z wersji',
|
||||
'options' => $copyFromOptions,
|
||||
]),
|
||||
FormField::text('title', [
|
||||
'label' => 'Tytul',
|
||||
'required' => true,
|
||||
'attributes' => ['id' => 'title'],
|
||||
]),
|
||||
FormField::image('main_image', [
|
||||
'label' => 'Zdjecie tytulowe',
|
||||
'filemanager' => true,
|
||||
'attributes' => ['id' => 'main_image'],
|
||||
]),
|
||||
FormField::editor('entry', [
|
||||
'label' => 'Wstep',
|
||||
'toolbar' => 'MyToolbar',
|
||||
'height' => 250,
|
||||
'attributes' => ['id' => 'entry'],
|
||||
]),
|
||||
FormField::editor('text', [
|
||||
'label' => 'Tresc',
|
||||
'toolbar' => 'MyToolbar',
|
||||
'height' => 250,
|
||||
'attributes' => ['id' => 'text'],
|
||||
]),
|
||||
FormField::editor('table_of_contents', [
|
||||
'label' => 'Spis tresci',
|
||||
'toolbar' => 'MyToolbar',
|
||||
'height' => 250,
|
||||
'attributes' => ['id' => 'table_of_contents'],
|
||||
]),
|
||||
]),
|
||||
FormField::switch('status', ['label' => 'Opublikowany', 'tab' => 'settings', 'value' => ((int)($article['status'] ?? 0) === 1) || $articleId === 0]),
|
||||
FormField::switch('show_title', ['label' => 'Pokaz tytul', 'tab' => 'settings', 'value' => (int)($article['show_title'] ?? 0) === 1]),
|
||||
FormField::switch('show_table_of_contents', ['label' => 'Pokaz spis tresci', 'tab' => 'settings', 'value' => (int)($article['show_table_of_contents'] ?? 0) === 1]),
|
||||
FormField::switch('show_date_add', ['label' => 'Pokaz date dodania', 'tab' => 'settings', 'value' => (int)($article['show_date_add'] ?? 0) === 1]),
|
||||
FormField::switch('show_date_modify', ['label' => 'Pokaz date modyfikacji', 'tab' => 'settings', 'value' => (int)($article['show_date_modify'] ?? 0) === 1]),
|
||||
FormField::switch('repeat_entry', ['label' => 'Powtorz wprowadzenie', 'tab' => 'settings', 'value' => (int)($article['repeat_entry'] ?? 0) === 1]),
|
||||
FormField::switch('social_icons', ['label' => 'Linki do portali spolecznosciowych', 'tab' => 'settings', 'value' => (int)($article['social_icons'] ?? 0) === 1]),
|
||||
FormField::langSection('article_seo', 'seo', [
|
||||
FormField::text('seo_link', ['label' => 'Link SEO', 'attributes' => ['id' => 'seo_link']]),
|
||||
FormField::text('meta_title', ['label' => 'Meta title']),
|
||||
FormField::textarea('meta_description', ['label' => 'Meta description', 'rows' => 4]),
|
||||
FormField::textarea('meta_keywords', ['label' => 'Meta keywords', 'rows' => 4]),
|
||||
FormField::switch('noindex', ['label' => 'Blokuj indeksacje']),
|
||||
FormField::switch('block_direct_access', ['label' => 'Blokuj bezposredni dostep']),
|
||||
]),
|
||||
FormField::select('layout_id', [
|
||||
'label' => 'Szablon',
|
||||
'tab' => 'display',
|
||||
'options' => $layoutOptions,
|
||||
'value' => $article['layout_id'] ?? '',
|
||||
]),
|
||||
FormField::custom('pages_tree', $this->renderPagesTree($menus, $article), ['tab' => 'display']),
|
||||
FormField::custom('images_box', $this->renderImagesBox($article), ['tab' => 'gallery']),
|
||||
FormField::custom('files_box', $this->renderFilesBox($article), ['tab' => 'files']),
|
||||
];
|
||||
|
||||
$actions = [
|
||||
FormAction::save('/admin/articles/save/' . ($articleId > 0 ? 'id=' . $articleId : ''), '/admin/articles/list/'),
|
||||
FormAction::cancel('/admin/articles/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'article-edit',
|
||||
$title,
|
||||
$article,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
'/admin/articles/save/' . ($articleId > 0 ? 'id=' . $articleId : ''),
|
||||
'/admin/articles/list/',
|
||||
true,
|
||||
['id' => $articleId],
|
||||
$languages
|
||||
);
|
||||
}
|
||||
|
||||
private function renderPagesTree(array $menus, array $article): string
|
||||
{
|
||||
$html = '<div class="form-group row">';
|
||||
$html .= '<label class="col-lg-4 control-label">Wyswietlaj na:</label>';
|
||||
$html .= '<div class="col-lg-8">';
|
||||
|
||||
foreach ($menus as $menu) {
|
||||
$menuId = (int)($menu['id'] ?? 0);
|
||||
$menuName = $this->escapeHtml((string)($menu['name'] ?? ''));
|
||||
$menuStatus = (int)($menu['status'] ?? 0);
|
||||
$menuPages = $this->pagesRepository->menuPages($menuId);
|
||||
|
||||
$html .= '<div class="menu_sortable">';
|
||||
$html .= '<ol class="sortable" id="sortable_' . $menuId . '">';
|
||||
$html .= '<li id="list_' . $menuId . '" class="menu_' . $menuId . '" menu="' . $menuId . '">';
|
||||
$html .= '<div class="context_0 content content_menu"' . ($menuStatus ? '' : ' style="color: #cc0000;"') . '>';
|
||||
$html .= '<button type="button" class="disclose layout-tree-toggle" aria-expanded="false" title="Rozwin / zwin">'
|
||||
. '<i class="fa fa-caret-right"></i>'
|
||||
. '</button>Menu: <b>' . $menuName . '</b>';
|
||||
$html .= '</div>';
|
||||
$html .= \Shared\Tpl\Tpl::view('articles/subpages-list', [
|
||||
'pages' => $menuPages,
|
||||
'article_pages' => $article['pages'] ?? [],
|
||||
'parent_id' => $menuId,
|
||||
'step' => 1,
|
||||
]);
|
||||
$html .= '</li></ol></div>';
|
||||
}
|
||||
|
||||
$html .= '</div><div class="clear"></div></div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function renderImagesBox(array $article): string
|
||||
{
|
||||
$html = '<ul id="images-list">';
|
||||
$images = is_array($article['images'] ?? null) ? $article['images'] : [];
|
||||
foreach ($images as $img) {
|
||||
$id = (int)($img['id'] ?? 0);
|
||||
$src = $this->escapeHtml((string)($img['src'] ?? ''));
|
||||
$alt = $this->escapeHtml((string)($img['alt'] ?? ''));
|
||||
|
||||
$html .= '<li id="image-' . $id . '">';
|
||||
$html .= '<img class="article-image lozad" data-src="/libraries/thumb.php?img=' . $src . '&w=300&h=300">';
|
||||
$html .= '<a href="#" class="input-group-addon btn btn-danger article_image_delete" image-id="' . $id . '"><i class="fa fa-trash"></i></a>';
|
||||
$html .= '<input type="text" class="form-control image-alt" value="' . $alt . '" image-id="' . $id . '" placeholder="atrybut alt...">';
|
||||
$html .= '</li>';
|
||||
}
|
||||
$html .= '</ul><div id="images-uploader">You browser doesn\'t have Flash installed.</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function renderFilesBox(array $article): string
|
||||
{
|
||||
$html = '<ul id="files-list">';
|
||||
$files = is_array($article['files'] ?? null) ? $article['files'] : [];
|
||||
foreach ($files as $file) {
|
||||
$id = (int)($file['id'] ?? 0);
|
||||
$src = (string)($file['src'] ?? '');
|
||||
$name = trim((string)($file['name'] ?? ''));
|
||||
if ($name === '') {
|
||||
$parts = explode('/', $src);
|
||||
$name = (string)end($parts);
|
||||
}
|
||||
$name = $this->escapeHtml($name);
|
||||
|
||||
$html .= '<li id="file-' . $id . '"><div class="input-group">';
|
||||
$html .= '<input type="text" class="article_file_edit form-control" file_id="' . $id . '" value="' . $name . '" />';
|
||||
$html .= '<a href="#" class="input-group-addon btn btn-info article_file_delete" file_id="' . $id . '"><i class="fa fa-trash"></i></a>';
|
||||
$html .= '</div></li>';
|
||||
}
|
||||
$html .= '</ul><div id="files-uploader">You browser doesn\'t have Flash installed.</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function escapeHtml(string $value): string
|
||||
{
|
||||
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
}
|
||||
339
autoload/admin/Controllers/BannerController.php
Normal file
339
autoload/admin/Controllers/BannerController.php
Normal file
@@ -0,0 +1,339 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Banner\BannerRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
use admin\ViewModels\Forms\FormEditViewModel;
|
||||
use admin\ViewModels\Forms\FormField;
|
||||
use admin\ViewModels\Forms\FormTab;
|
||||
use admin\ViewModels\Forms\FormAction;
|
||||
use admin\Support\Forms\FormRequestHandler;
|
||||
|
||||
class BannerController
|
||||
{
|
||||
private BannerRepository $repository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
private FormRequestHandler $formHandler;
|
||||
|
||||
public function __construct(BannerRepository $repository, LanguagesRepository $languagesRepository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
$this->formHandler = new FormRequestHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista banerow
|
||||
*/
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['name', 'status', 'home_page', 'date_start', 'date_end'];
|
||||
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Aktywny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- aktywny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'name'
|
||||
);
|
||||
|
||||
// Historycznie lista banerow domyslnie byla sortowana rosnaco po nazwie.
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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 = (int)$item['id'];
|
||||
$name = (string)($item['name'] ?? '');
|
||||
$homePage = (int)($item['home_page'] ?? 0);
|
||||
$isActive = (int)($item['status'] ?? 0) === 1;
|
||||
$thumbnailSrc = trim((string)($item['thumbnail_src'] ?? ''));
|
||||
if ($thumbnailSrc !== '' && !preg_match('#^(https?:)?//#i', $thumbnailSrc) && strpos($thumbnailSrc, '/') !== 0) {
|
||||
$thumbnailSrc = '/' . ltrim($thumbnailSrc, '/');
|
||||
}
|
||||
|
||||
$thumbnail = '<span class="text-muted">-</span>';
|
||||
if ($thumbnailSrc !== '') {
|
||||
$thumbnail = '<div class="banner-thumb-wrap">'
|
||||
. '<img src="' . htmlspecialchars($thumbnailSrc, ENT_QUOTES, 'UTF-8') . '" alt="" '
|
||||
. 'data-preview-src="' . htmlspecialchars($thumbnailSrc, ENT_QUOTES, 'UTF-8') . '" '
|
||||
. 'class="banner-thumb-image js-banner-thumb-preview" '
|
||||
. 'loading="lazy">'
|
||||
. '</div>';
|
||||
}
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'thumbnail' => $thumbnail,
|
||||
'name' => '<a href="/admin/banners/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'status' => $isActive ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'home_page' => $homePage === 1 ? '<span class="text-system">tak</span>' : 'nie',
|
||||
'slider' => $homePage === 1 ? 'nie' : '<span class="text-system">tak</span>',
|
||||
'date_start' => !empty($item['date_start']) ? date('Y-m-d', strtotime((string)$item['date_start'])) : '-',
|
||||
'date_end' => !empty($item['date_end']) ? date('Y-m-d', strtotime((string)$item['date_end'])) : '-',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/banners/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/banners/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrany element?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'thumbnail', 'label' => 'Miniatura', 'class' => 'text-center', 'sortable' => false, 'raw' => true],
|
||||
['key' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'home_page', 'sort_key' => 'home_page', 'label' => 'Strona glowna', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'slider', 'label' => 'Slajder', 'class' => 'text-center', 'sortable' => false, 'raw' => true],
|
||||
['key' => 'date_start', 'sort_key' => 'date_start', 'label' => 'Data rozpoczecia', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'date_end', 'sort_key' => 'date_end', 'label' => 'Data zakonczenia', 'class' => 'text-center', 'sortable' => 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/banners/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/banners/edit/',
|
||||
'Dodaj baner',
|
||||
'banners/banners-list-custom-script'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('banners/banners-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edycja banera
|
||||
*/
|
||||
public function edit(): string
|
||||
{
|
||||
$bannerId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
$banner = $this->repository->find($bannerId) ?: [];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
|
||||
// Sprawdź czy są błędy walidacji z poprzedniego requestu
|
||||
$validationErrors = $_SESSION['form_errors'][$this->getFormId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->getFormId()]);
|
||||
}
|
||||
|
||||
$viewModel = $this->buildFormViewModel($banner, $languages, $validationErrors);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('components/form-edit', ['form' => $viewModel]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapisanie banera (AJAX)
|
||||
*/
|
||||
public function save(): void
|
||||
{
|
||||
$response = ['success' => false, 'errors' => []];
|
||||
|
||||
$bannerId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
$banner = $this->repository->find($bannerId) ?: [];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
|
||||
$viewModel = $this->buildFormViewModel($banner, $languages);
|
||||
|
||||
// Przetwórz dane z POST
|
||||
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
|
||||
|
||||
if (!$result['success']) {
|
||||
// Zapisz błędy w sesji i zwróć jako JSON
|
||||
$_SESSION['form_errors'][$this->getFormId()] = $result['errors'];
|
||||
$response['errors'] = $result['errors'];
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Zapisz dane
|
||||
$data = $result['data'];
|
||||
$data['id'] = $bannerId ?: null;
|
||||
|
||||
$savedId = $this->repository->save($data);
|
||||
|
||||
if ($savedId) {
|
||||
$response = [
|
||||
'success' => true,
|
||||
'id' => $savedId,
|
||||
'message' => 'Baner został zapisany.'
|
||||
];
|
||||
} else {
|
||||
$response['errors'] = ['general' => 'Błąd podczas zapisywania do bazy.'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Usuniecie banera
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
$bannerId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
if ($this->repository->delete($bannerId)) {
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
\Shared\Helpers\Helpers::alert('Baner zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/banners/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buduje model widoku formularza
|
||||
*/
|
||||
private function buildFormViewModel(array $banner, array $languages, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$bannerId = $banner['id'] ?? 0;
|
||||
$isNew = empty($bannerId);
|
||||
|
||||
// Domyślne wartości dla nowego banera
|
||||
if ($isNew) {
|
||||
$banner['status'] = 1;
|
||||
$banner['home_page'] = 0;
|
||||
}
|
||||
|
||||
$tabs = [
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
new FormTab('content', 'Zawartość', 'fa-file'),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
// Zakładka Ustawienia
|
||||
FormField::text('name', [
|
||||
'label' => 'Nazwa',
|
||||
'tab' => 'settings',
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
'tab' => 'settings',
|
||||
'value' => ($banner['status'] ?? 1) == 1,
|
||||
]),
|
||||
FormField::date('date_start', [
|
||||
'label' => 'Data rozpoczęcia',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::date('date_end', [
|
||||
'label' => 'Data zakończenia',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::switch('home_page', [
|
||||
'label' => 'Slajder / Strona główna',
|
||||
'tab' => 'settings',
|
||||
'value' => ($banner['home_page'] ?? 0) == 1,
|
||||
]),
|
||||
|
||||
// Sekcja językowa w zakładce Zawartość
|
||||
FormField::langSection('translations', 'content', [
|
||||
FormField::image('src', [
|
||||
'label' => 'Obraz',
|
||||
'filemanager' => true,
|
||||
]),
|
||||
FormField::text('url', [
|
||||
'label' => 'Url',
|
||||
]),
|
||||
FormField::textarea('html', [
|
||||
'label' => 'Kod HTML',
|
||||
'rows' => 6,
|
||||
]),
|
||||
FormField::editor('text', [
|
||||
'label' => 'Treść',
|
||||
'toolbar' => 'MyTool',
|
||||
'height' => 300,
|
||||
]),
|
||||
]),
|
||||
];
|
||||
|
||||
$actions = [
|
||||
FormAction::save(
|
||||
'/admin/banners/save/' . ($isNew ? '' : 'id=' . $bannerId),
|
||||
'/admin/banners/list/'
|
||||
),
|
||||
FormAction::cancel('/admin/banners/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->getFormId(),
|
||||
$isNew ? 'Nowy baner' : 'Edycja banera',
|
||||
$banner,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
'/admin/banners/save/' . ($isNew ? '' : 'id=' . $bannerId),
|
||||
'/admin/banners/list/',
|
||||
true,
|
||||
['id' => $bannerId],
|
||||
$languages,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zwraca identyfikator formularza
|
||||
*/
|
||||
private function getFormId(): string
|
||||
{
|
||||
return 'banner-edit';
|
||||
}
|
||||
}
|
||||
31
autoload/admin/Controllers/DashboardController.php
Normal file
31
autoload/admin/Controllers/DashboardController.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Dashboard\DashboardRepository;
|
||||
use Domain\ShopStatus\ShopStatusRepository;
|
||||
|
||||
class DashboardController
|
||||
{
|
||||
private DashboardRepository $repository;
|
||||
private ShopStatusRepository $statusesRepository;
|
||||
|
||||
public function __construct( DashboardRepository $repository, ShopStatusRepository $statusesRepository )
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->statusesRepository = $statusesRepository;
|
||||
}
|
||||
|
||||
public function main_view(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view( 'dashboard/main-view', [
|
||||
'last_orders' => $this->repository->lastOrders(),
|
||||
'order_statuses' => $this->statusesRepository->allStatuses(),
|
||||
'sales' => $this->repository->last24MonthsSales(),
|
||||
'best_sales_products' => $this->repository->bestSalesProducts(),
|
||||
'most_view_products' => $this->repository->mostViewedProducts(),
|
||||
'sales_grid' => $this->repository->salesGrid(),
|
||||
'summary_sales' => $this->repository->summarySales(),
|
||||
'summary_orders' => $this->repository->summaryOrders(),
|
||||
] );
|
||||
}
|
||||
}
|
||||
256
autoload/admin/Controllers/DictionariesController.php
Normal file
256
autoload/admin/Controllers/DictionariesController.php
Normal file
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Dictionaries\DictionariesRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
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 DictionariesController
|
||||
{
|
||||
private DictionariesRepository $repository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
private FormRequestHandler $formHandler;
|
||||
|
||||
public function __construct(DictionariesRepository $repository, LanguagesRepository $languagesRepository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
$this->formHandler = new FormRequestHandler();
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'text'];
|
||||
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'text',
|
||||
'label' => 'Tekst',
|
||||
'type' => 'text',
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'id'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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 = (int)$item['id'];
|
||||
$text = trim((string)($item['text'] ?? ''));
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'text' => '<a href="/admin/dictionaries/edit/id=' . $id . '">' . htmlspecialchars($text, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/dictionaries/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/dictionaries/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrana jednostke miary?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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/dictionaries/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/dictionaries/edit/',
|
||||
'Dodaj jednostke miary'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('dictionaries/units-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$unitId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
$unit = $this->repository->find($unitId) ?? ['id' => 0, 'languages' => []];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
|
||||
$validationErrors = $_SESSION['form_errors'][$this->getFormId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->getFormId()]);
|
||||
}
|
||||
|
||||
$viewModel = $this->buildFormViewModel($unit, $languages, $validationErrors);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('dictionaries/unit-edit', ['form' => $viewModel]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode($legacyValues, true);
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania jednostki miary wystapil blad.'];
|
||||
|
||||
if (is_array($values)) {
|
||||
$savedId = $this->repository->save([
|
||||
'id' => (int)($values['id'] ?? 0),
|
||||
'text' => (array)($values['text'] ?? []),
|
||||
]);
|
||||
if ($savedId) {
|
||||
$response = ['status' => 'ok', 'msg' => 'Jednostka miary zostala zapisana.', 'id' => $savedId];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$unitId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
$unit = $this->repository->find($unitId) ?? ['id' => 0, 'languages' => []];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
$viewModel = $this->buildFormViewModel($unit, $languages);
|
||||
|
||||
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
|
||||
if (!$result['success']) {
|
||||
$_SESSION['form_errors'][$this->getFormId()] = $result['errors'];
|
||||
echo json_encode(['success' => false, 'errors' => $result['errors']]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = $result['data'];
|
||||
$data['id'] = $unitId ?: null;
|
||||
|
||||
$savedId = $this->repository->save($data);
|
||||
if ($savedId) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => $savedId,
|
||||
'message' => 'Jednostka miary zostala zapisana.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Blad podczas zapisywania do bazy.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
$unitId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
if ($this->repository->delete($unitId)) {
|
||||
\Shared\Helpers\Helpers::alert('Jednostka miary zostala usunieta.');
|
||||
}
|
||||
|
||||
header('Location: /admin/dictionaries/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $unit, array $languages, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$unitId = (int)($unit['id'] ?? 0);
|
||||
$isNew = $unitId <= 0;
|
||||
|
||||
$data = [
|
||||
'id' => $unitId,
|
||||
'languages' => [],
|
||||
];
|
||||
|
||||
if (isset($unit['languages']) && is_array($unit['languages'])) {
|
||||
foreach ($unit['languages'] as $langId => $translation) {
|
||||
$data['languages'][(string)$langId] = [
|
||||
'text' => (string)($translation['text'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$tabs = [
|
||||
new FormTab('content', 'Tresc', 'fa-file'),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::langSection('translations', 'content', [
|
||||
FormField::text('text', [
|
||||
'label' => 'Tekst',
|
||||
]),
|
||||
]),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/dictionaries/save/' . ($isNew ? '' : ('id=' . $unitId));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/dictionaries/list/'),
|
||||
FormAction::cancel('/admin/dictionaries/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->getFormId(),
|
||||
$isNew ? 'Nowa jednostka miary' : 'Edycja jednostki miary',
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/dictionaries/list/',
|
||||
true,
|
||||
['id' => $unitId],
|
||||
$languages,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function getFormId(): string
|
||||
{
|
||||
return 'dictionaries-unit-edit';
|
||||
}
|
||||
}
|
||||
46
autoload/admin/Controllers/FilemanagerController.php
Normal file
46
autoload/admin/Controllers/FilemanagerController.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
class FilemanagerController
|
||||
{
|
||||
private const RFM_KEY_TTL = 1200; // 20 min
|
||||
private const FILEMANAGER_DIALOG_PATH = '/libraries/filemanager-9.14.2/dialog.php';
|
||||
|
||||
public function draw(): string
|
||||
{
|
||||
$akey = $this->ensureFilemanagerAccessKey();
|
||||
$filemanagerUrl = $this->buildFilemanagerUrl($akey);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('filemanager/filemanager', [
|
||||
'filemanager_url' => $filemanagerUrl,
|
||||
]);
|
||||
}
|
||||
|
||||
private function ensureFilemanagerAccessKey(): string
|
||||
{
|
||||
$expiresAt = (int)($_SESSION['rfm_akey_expires'] ?? 0);
|
||||
$existingKey = trim((string)($_SESSION['rfm_akey'] ?? ''));
|
||||
|
||||
if ($existingKey !== '' && $expiresAt >= time()) {
|
||||
$_SESSION['rfm_akey_expires'] = time() + self::RFM_KEY_TTL;
|
||||
return $existingKey;
|
||||
}
|
||||
|
||||
try {
|
||||
$newKey = bin2hex(random_bytes(16));
|
||||
} catch (\Throwable $e) {
|
||||
$newKey = sha1(uniqid('rfm', true));
|
||||
}
|
||||
|
||||
$_SESSION['rfm_akey'] = $newKey;
|
||||
$_SESSION['rfm_akey_expires'] = time() + self::RFM_KEY_TTL;
|
||||
|
||||
return $newKey;
|
||||
}
|
||||
|
||||
private function buildFilemanagerUrl(string $akey): string
|
||||
{
|
||||
return self::FILEMANAGER_DIALOG_PATH . '?akey=' . rawurlencode($akey);
|
||||
}
|
||||
}
|
||||
|
||||
178
autoload/admin/Controllers/IntegrationsController.php
Normal file
178
autoload/admin/Controllers/IntegrationsController.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Integrations\IntegrationsRepository;
|
||||
|
||||
class IntegrationsController
|
||||
{
|
||||
private IntegrationsRepository $repository;
|
||||
|
||||
public function __construct( IntegrationsRepository $repository )
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function apilo_settings(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view( 'integrations/apilo-settings', [
|
||||
'settings' => $this->repository->getSettings( 'apilo' ),
|
||||
'apilo_status' => $this->repository->apiloIntegrationStatus(),
|
||||
] );
|
||||
}
|
||||
|
||||
public function apilo_settings_save(): void
|
||||
{
|
||||
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania ustawien wystapil blad. Prosze sprobowac ponownie.' ];
|
||||
$fieldId = \Shared\Helpers\Helpers::get( 'field_id' );
|
||||
$value = \Shared\Helpers\Helpers::get( 'value' );
|
||||
|
||||
if ( $this->repository->saveSetting( 'apilo', $fieldId, $value ) ) {
|
||||
$response = [ 'status' => 'ok', 'msg' => 'Ustawienia zostaly zapisane.', 'value' => $value ];
|
||||
}
|
||||
|
||||
echo json_encode( $response );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function apilo_authorization(): void
|
||||
{
|
||||
$settings = $this->repository->getSettings( 'apilo' );
|
||||
|
||||
if ( $this->repository->apiloAuthorize(
|
||||
(string)($settings['client-id'] ?? ''),
|
||||
(string)($settings['client-secret'] ?? ''),
|
||||
(string)($settings['authorization-code'] ?? '')
|
||||
) ) {
|
||||
echo json_encode( [ 'status' => 'ok', 'msg' => 'Autoryzacja przebiegla pomyslnie.' ] );
|
||||
exit;
|
||||
}
|
||||
|
||||
$status = $this->repository->apiloIntegrationStatus();
|
||||
$message = trim( (string)($status['message'] ?? '') );
|
||||
if ( $message === '' ) {
|
||||
$message = 'Podczas autoryzacji wystapil blad. Prosze sprawdzic dane i sprobowac ponownie.';
|
||||
} else {
|
||||
$message = 'Autoryzacja nieudana. ' . $message;
|
||||
}
|
||||
|
||||
echo json_encode( [ 'status' => 'error', 'msg' => $message ] );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function get_platform_list(): void
|
||||
{
|
||||
$this->fetchApiloListWithFeedback( 'platform', 'Liste platform' );
|
||||
}
|
||||
|
||||
public function get_status_types_list(): void
|
||||
{
|
||||
$this->fetchApiloListWithFeedback( 'status', 'Liste statusow' );
|
||||
}
|
||||
|
||||
public function get_carrier_account_list(): void
|
||||
{
|
||||
$this->fetchApiloListWithFeedback( 'carrier', 'Liste kont przewoznikow' );
|
||||
}
|
||||
|
||||
public function get_payment_types_list(): void
|
||||
{
|
||||
$this->fetchApiloListWithFeedback( 'payment', 'Liste metod platnosci' );
|
||||
}
|
||||
|
||||
public function apilo_create_product(): void
|
||||
{
|
||||
$productId = (int) \Shared\Helpers\Helpers::get( 'product_id' );
|
||||
$result = $this->repository->apiloCreateProduct( $productId );
|
||||
|
||||
\Shared\Helpers\Helpers::alert( (string)($result['message'] ?? 'Wystapil blad podczas tworzenia produktu w Apilo.') );
|
||||
header( 'Location: /admin/shop_product/view_list/' );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function apilo_product_search(): void
|
||||
{
|
||||
$productId = (int) \Shared\Helpers\Helpers::get( 'product_id' );
|
||||
$sku = $this->repository->getProductSku( $productId );
|
||||
|
||||
if ( !$sku ) {
|
||||
echo json_encode( [ 'status' => 'error', 'msg' => 'Podany produkt nie posiada kodu SKU.' ] );
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode( $this->repository->apiloProductSearch( $sku ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function apilo_product_select_save(): void
|
||||
{
|
||||
if ( $this->repository->linkProduct( (int) \Shared\Helpers\Helpers::get( 'product_id' ), \Shared\Helpers\Helpers::get( 'apilo_product_id' ), \Shared\Helpers\Helpers::get( 'apilo_product_name' ) ) ) {
|
||||
echo json_encode( [ 'status' => 'ok' ] );
|
||||
} else {
|
||||
echo json_encode( [ 'status' => 'error', 'msg' => 'Podczas zapisywania produktu wystapil blad. Prosze sprobowac ponownie.' ] );
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
public function apilo_product_select_delete(): void
|
||||
{
|
||||
if ( $this->repository->unlinkProduct( (int) \Shared\Helpers\Helpers::get( 'product_id' ) ) ) {
|
||||
echo json_encode( [ 'status' => 'ok' ] );
|
||||
} else {
|
||||
echo json_encode( [ 'status' => 'error', 'msg' => 'Podczas usuwania produktu wystapil blad. Prosze sprobowac ponownie.' ] );
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
public function shoppro_settings(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view( 'integrations/shoppro-settings', [
|
||||
'settings' => $this->repository->getSettings( 'shoppro' ),
|
||||
] );
|
||||
}
|
||||
|
||||
public function shoppro_settings_save(): void
|
||||
{
|
||||
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania ustawien wystapil blad. Prosze sprobowac ponownie.' ];
|
||||
$fieldId = \Shared\Helpers\Helpers::get( 'field_id' );
|
||||
$value = \Shared\Helpers\Helpers::get( 'value' );
|
||||
|
||||
if ( $this->repository->saveSetting( 'shoppro', $fieldId, $value ) ) {
|
||||
$response = [ 'status' => 'ok', 'msg' => 'Ustawienia zostaly zapisane.', 'value' => $value ];
|
||||
}
|
||||
|
||||
echo json_encode( $response );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function shoppro_product_import(): void
|
||||
{
|
||||
$productId = (int) \Shared\Helpers\Helpers::get( 'product_id' );
|
||||
$result = $this->repository->shopproImportProduct( $productId );
|
||||
|
||||
\Shared\Helpers\Helpers::alert( (string)($result['message'] ?? 'Wystapil blad podczas importu produktu.') );
|
||||
header( 'Location: /admin/shop_product/view_list/' );
|
||||
exit;
|
||||
}
|
||||
|
||||
private function fetchApiloListWithFeedback( string $type, string $label ): void
|
||||
{
|
||||
$result = $this->repository->apiloFetchListResult( $type );
|
||||
|
||||
if ( !empty( $result['success'] ) ) {
|
||||
$count = (int)($result['count'] ?? 0);
|
||||
\Shared\Helpers\Helpers::alert( $label . ' zostala pobrana. Liczba rekordow: ' . $count . '.' );
|
||||
} else {
|
||||
$details = trim( (string)($result['message'] ?? 'Nieznany blad.') );
|
||||
\Shared\Helpers\Helpers::alert(
|
||||
'Nie udalo sie pobrac ' . strtolower( $label ) . '. '
|
||||
. $details
|
||||
. ' Co zrobic: sprawdz konfiguracje Apilo, wykonaj autoryzacje i ponow pobranie listy.'
|
||||
);
|
||||
}
|
||||
|
||||
header( 'Location: /admin/integrations/apilo_settings/' );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
560
autoload/admin/Controllers/LanguagesController.php
Normal file
560
autoload/admin/Controllers/LanguagesController.php
Normal 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)\Shared\Helpers\Helpers::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 \Shared\Tpl\Tpl::view('languages/languages-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function language_edit(): string
|
||||
{
|
||||
$languageId = trim((string)\Shared\Helpers\Helpers::get('id'));
|
||||
$language = $this->repository->languageDetails($languageId) ?? [];
|
||||
$validationErrors = $_SESSION['form_errors'][$this->getLanguageFormId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->getLanguageFormId()]);
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('languages/language-edit', [
|
||||
'form' => $this->buildLanguageFormViewModel($language, $this->repository->maxOrder(), $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function language_save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::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)\Shared\Helpers\Helpers::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)\Shared\Helpers\Helpers::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)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::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)\Shared\Helpers\Helpers::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 \Shared\Tpl\Tpl::view('languages/translations-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function translation_edit(): string
|
||||
{
|
||||
$translationId = (int)\Shared\Helpers\Helpers::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 \Shared\Tpl\Tpl::view('languages/translation-edit', [
|
||||
'form' => $this->buildTranslationFormViewModel($translation, $languages, $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function translation_save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::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)\Shared\Helpers\Helpers::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)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::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;
|
||||
}
|
||||
\Shared\Helpers\Helpers::delete_session('lang-' . (string)$language['id']);
|
||||
}
|
||||
}
|
||||
|
||||
private function getLanguageFormId(): string
|
||||
{
|
||||
return 'languages-language-edit';
|
||||
}
|
||||
|
||||
private function getTranslationFormId(): string
|
||||
{
|
||||
return 'languages-translation-edit';
|
||||
}
|
||||
}
|
||||
172
autoload/admin/Controllers/LayoutsController.php
Normal file
172
autoload/admin/Controllers/LayoutsController.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Layouts\LayoutsRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
|
||||
class LayoutsController
|
||||
{
|
||||
private LayoutsRepository $repository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
|
||||
public function __construct(LayoutsRepository $repository, LanguagesRepository $languagesRepository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['name', 'status', 'categories_default'];
|
||||
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Szablon domyslny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- domyslny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'categories_default',
|
||||
'label' => 'Domyslny (kategorie)',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- kategorie -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'name'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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 = (int)($item['id'] ?? 0);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'name' => '<a href="/admin/layouts/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'status' => ((int)($item['status'] ?? 0) === 1) ? '<span class="text-system">tak</span>' : 'nie',
|
||||
'categories_default' => ((int)($item['categories_default'] ?? 0) === 1) ? '<span class="text-system">tak</span>' : 'nie',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/layouts/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/layouts/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrany szablon?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Szablon domyslny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'categories_default', 'sort_key' => 'categories_default', 'label' => 'Domyslny (kategorie)', '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/layouts/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/layouts/edit/',
|
||||
'Dodaj szablon'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('layouts/layouts-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view('layouts/layout-edit', [
|
||||
'layout' => $this->repository->find((int)\Shared\Helpers\Helpers::get('id')),
|
||||
'menus' => $this->repository->menusWithPages(),
|
||||
'categories' => $this->repository->categoriesTree(),
|
||||
'dlang' => $this->languagesRepository->defaultLanguageId(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania szablonu wystapil blad. Prosze sprobowac ponownie.'];
|
||||
$values = json_decode((string)\Shared\Helpers\Helpers::get('values'), true);
|
||||
|
||||
if (is_array($values)) {
|
||||
$id = $this->repository->save($values);
|
||||
if (!empty($id)) {
|
||||
$response = ['status' => 'ok', 'msg' => 'Szablon zostal zapisany.', 'id' => $id];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->delete((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Szablon zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/layouts/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
}
|
||||
514
autoload/admin/Controllers/NewsletterController.php
Normal file
514
autoload/admin/Controllers/NewsletterController.php
Normal file
@@ -0,0 +1,514 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Newsletter\NewsletterRepository;
|
||||
use Domain\Newsletter\NewsletterPreviewRenderer;
|
||||
use admin\ViewModels\Common\PaginatedTableViewModel;
|
||||
use admin\ViewModels\Forms\FormAction;
|
||||
use admin\ViewModels\Forms\FormEditViewModel;
|
||||
use admin\ViewModels\Forms\FormField;
|
||||
use admin\Support\Forms\FormRequestHandler;
|
||||
|
||||
class NewsletterController
|
||||
{
|
||||
private NewsletterRepository $repository;
|
||||
private NewsletterPreviewRenderer $previewRenderer;
|
||||
private FormRequestHandler $formHandler;
|
||||
|
||||
public function __construct(NewsletterRepository $repository, NewsletterPreviewRenderer $previewRenderer)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->previewRenderer = $previewRenderer;
|
||||
$this->formHandler = new FormRequestHandler();
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
return $this->emails_list();
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function emails_list(): string
|
||||
{
|
||||
$sortableColumns = ['email', 'status'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'email',
|
||||
'label' => 'Email',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Potwierdzony',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- potwierdzony -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'email'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::get('sort')) === '') {
|
||||
$sortDir = 'ASC';
|
||||
}
|
||||
|
||||
$result = $this->repository->listSubscribersForAdmin(
|
||||
$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);
|
||||
$email = trim((string)($item['email'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'email' => htmlspecialchars($email, ENT_QUOTES, 'UTF-8'),
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/newsletter/email_delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrany adres email?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'email', 'sort_key' => 'email', 'label' => 'Email', 'sortable' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Potwierdzony', '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/newsletter/emails_list/',
|
||||
'Brak danych w tabeli.'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('newsletter/emails-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function email_delete(): void
|
||||
{
|
||||
if ($this->repository->deleteSubscriber((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Adres email zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/newsletter/emails_list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
$this->email_delete();
|
||||
}
|
||||
|
||||
public function prepare(): string
|
||||
{
|
||||
\Shared\Helpers\Helpers::alert('Funkcjonalnosc "Wysylka - przygotowanie" jest tymczasowo wylaczona.');
|
||||
header('Location: /admin/newsletter/emails_list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function preview(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function send(): void
|
||||
{
|
||||
\Shared\Helpers\Helpers::alert('Funkcjonalnosc "Wysylka - przygotowanie" jest tymczasowo wylaczona.');
|
||||
header('Location: /admin/newsletter/emails_list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function settings(): string
|
||||
{
|
||||
$settings = $this->repository->getSettings();
|
||||
$validationErrors = $_SESSION['form_errors'][$this->settingsFormId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->settingsFormId()]);
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('newsletter/settings', [
|
||||
'form' => $this->buildSettingsFormViewModel($settings, $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function settings_save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
if (!is_array($values)) {
|
||||
echo json_encode(['status' => 'error', 'msg' => 'Nieprawidlowe dane formularza.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->repository->saveSettings($values);
|
||||
\Shared\Helpers\Helpers::alert('Ustawienia zostaly zapisane.');
|
||||
|
||||
echo json_encode(['status' => 'ok', 'msg' => 'Ustawienia zostaly zapisane.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$viewModel = $this->buildSettingsFormViewModel($this->repository->getSettings());
|
||||
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
|
||||
if (!$result['success']) {
|
||||
$_SESSION['form_errors'][$this->settingsFormId()] = $result['errors'];
|
||||
echo json_encode(['success' => false, 'errors' => $result['errors']]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->repository->saveSettings($result['data']);
|
||||
\Shared\Helpers\Helpers::alert('Ustawienia zostaly zapisane.');
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Ustawienia zostaly zapisane.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function email_templates_user(): string
|
||||
{
|
||||
\Shared\Helpers\Helpers::alert('Funkcjonalnosc "Szablony uzytkownika" jest tymczasowo wylaczona.');
|
||||
header('Location: /admin/newsletter/email_templates_admin/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function email_templates_admin(): string
|
||||
{
|
||||
$viewModel = $this->templatesListViewModel();
|
||||
return \Shared\Tpl\Tpl::view('newsletter/email-templates-admin', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function email_template_edit(): string
|
||||
{
|
||||
$template = $this->repository->templateDetails((int)\Shared\Helpers\Helpers::get('id'));
|
||||
if (!is_array($template) || (int)($template['is_admin'] ?? 0) !== 1) {
|
||||
\Shared\Helpers\Helpers::alert('Dostepne sa tylko szablony administracyjne.');
|
||||
header('Location: /admin/newsletter/email_templates_admin/');
|
||||
exit;
|
||||
}
|
||||
|
||||
$formId = $this->templateFormId((int)$template['id']);
|
||||
$validationErrors = $_SESSION['form_errors'][$formId] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$formId]);
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('newsletter/email-template-edit', [
|
||||
'form' => $this->buildTemplateFormViewModel($template, $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function template_save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania wystapil blad.'];
|
||||
|
||||
if (is_array($values)) {
|
||||
$templateId = (int)($values['id'] ?? 0);
|
||||
$template = $this->repository->templateDetails($templateId);
|
||||
|
||||
if (is_array($template) && (int)($template['is_admin'] ?? 0) === 1) {
|
||||
$id = $this->repository->saveTemplate(
|
||||
$templateId,
|
||||
(string)($values['name'] ?? ''),
|
||||
(string)($values['text'] ?? '')
|
||||
);
|
||||
if ($id) {
|
||||
$response = ['status' => 'ok', 'msg' => 'Zmiany zostaly zapisane.', 'id' => $id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$template = $this->repository->templateDetails((int)\Shared\Helpers\Helpers::get('id'));
|
||||
if (!is_array($template) || (int)($template['is_admin'] ?? 0) !== 1) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Dostepne sa tylko szablony administracyjne.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$form = $this->buildTemplateFormViewModel($template);
|
||||
$result = $this->formHandler->handleSubmit($form, $_POST);
|
||||
if (!$result['success']) {
|
||||
$_SESSION['form_errors'][$this->templateFormId((int)$template['id'])] = $result['errors'];
|
||||
echo json_encode(['success' => false, 'errors' => $result['errors']]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = $result['data'];
|
||||
$id = $this->repository->saveTemplate(
|
||||
(int)($template['id'] ?? 0),
|
||||
(string)($data['name'] ?? ''),
|
||||
(string)($data['text'] ?? '')
|
||||
);
|
||||
|
||||
if ($id) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => $id,
|
||||
'message' => 'Zmiany zostaly zapisane.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function email_template_delete(): void
|
||||
{
|
||||
\Shared\Helpers\Helpers::alert('Usuwanie szablonow uzytkownika jest tymczasowo wylaczone.');
|
||||
header('Location: /admin/newsletter/email_templates_admin/');
|
||||
exit;
|
||||
}
|
||||
|
||||
private function buildSettingsFormViewModel(array $settings, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$data = [
|
||||
'newsletter_header' => (string)($settings['newsletter_header'] ?? ''),
|
||||
'newsletter_footer' => (string)($settings['newsletter_footer'] ?? ''),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::editor('newsletter_header', [
|
||||
'label' => 'Naglowek',
|
||||
'height' => 150,
|
||||
]),
|
||||
FormField::editor('newsletter_footer', [
|
||||
'label' => 'Stopka',
|
||||
'height' => 150,
|
||||
]),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/newsletter/settings_save/';
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/newsletter/settings/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->settingsFormId(),
|
||||
'Edycja ustawien newslettera',
|
||||
$data,
|
||||
$fields,
|
||||
[],
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/newsletter/settings/',
|
||||
true,
|
||||
[],
|
||||
null,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function buildTemplateFormViewModel(array $template, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$templateId = (int)($template['id'] ?? 0);
|
||||
$isAdminTemplate = (int)($template['is_admin'] ?? 0) === 1;
|
||||
$isNew = $templateId <= 0;
|
||||
|
||||
$data = [
|
||||
'id' => $templateId,
|
||||
'name' => (string)($template['name'] ?? ''),
|
||||
'text' => (string)($template['text'] ?? ''),
|
||||
];
|
||||
|
||||
$nameAttrs = [];
|
||||
if ($isAdminTemplate) {
|
||||
$nameAttrs['readonly'] = 'readonly';
|
||||
}
|
||||
|
||||
$fields = [
|
||||
FormField::text('name', [
|
||||
'label' => 'Nazwa',
|
||||
'required' => true,
|
||||
'attributes' => $nameAttrs,
|
||||
]),
|
||||
FormField::editor('text', [
|
||||
'label' => 'Tresc',
|
||||
'required' => true,
|
||||
'height' => 350,
|
||||
]),
|
||||
];
|
||||
|
||||
$backUrl = '/admin/newsletter/email_templates_admin/';
|
||||
$actionUrl = '/admin/newsletter/template_save/' . ($isNew ? '' : ('id=' . $templateId));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, $backUrl),
|
||||
FormAction::cancel($backUrl),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->templateFormId($templateId),
|
||||
'Edycja szablonu newslettera',
|
||||
$data,
|
||||
$fields,
|
||||
[],
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
$backUrl,
|
||||
true,
|
||||
['id' => $templateId],
|
||||
null,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function templatesListViewModel(): PaginatedTableViewModel
|
||||
{
|
||||
$sortableColumns = ['name'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'type' => 'text',
|
||||
],
|
||||
];
|
||||
|
||||
$basePath = '/admin/newsletter/email_templates_admin/';
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'name'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::get('sort')) === '') {
|
||||
$sortDir = 'ASC';
|
||||
}
|
||||
|
||||
$result = $this->repository->listTemplatesForAdmin(
|
||||
true,
|
||||
$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);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
|
||||
$actions = [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/newsletter/email_template_edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
];
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'name' => '<a href="/admin/newsletter/email_template_edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'_actions' => $actions,
|
||||
];
|
||||
}
|
||||
|
||||
$total = (int)$result['total'];
|
||||
$totalPages = max(1, (int)ceil($total / $listRequest['perPage']));
|
||||
|
||||
return new PaginatedTableViewModel(
|
||||
[
|
||||
['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
|
||||
['key' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', '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,
|
||||
$basePath,
|
||||
'Brak danych w tabeli.'
|
||||
);
|
||||
}
|
||||
|
||||
private function settingsFormId(): string
|
||||
{
|
||||
return 'newsletter-settings-edit';
|
||||
}
|
||||
|
||||
private function templateFormId(int $templateId): string
|
||||
{
|
||||
return 'newsletter-template-edit-' . $templateId;
|
||||
}
|
||||
}
|
||||
660
autoload/admin/Controllers/PagesController.php
Normal file
660
autoload/admin/Controllers/PagesController.php
Normal file
@@ -0,0 +1,660 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Pages\PagesRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
use Domain\Layouts\LayoutsRepository;
|
||||
use admin\ViewModels\Forms\FormAction;
|
||||
use admin\ViewModels\Forms\FormEditViewModel;
|
||||
use admin\ViewModels\Forms\FormField;
|
||||
use admin\ViewModels\Forms\FormTab;
|
||||
|
||||
class PagesController
|
||||
{
|
||||
private PagesRepository $repository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
private LayoutsRepository $layoutsRepository;
|
||||
|
||||
public function __construct(
|
||||
PagesRepository $repository,
|
||||
LanguagesRepository $languagesRepository,
|
||||
LayoutsRepository $layoutsRepository
|
||||
) {
|
||||
$this->repository = $repository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
$this->layoutsRepository = $layoutsRepository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view('pages/pages-list', [
|
||||
'menus' => $this->repository->menusWithPages(),
|
||||
'cookie_pages' => $this->cookieState('cookie_pages'),
|
||||
'cookie_menus' => $this->cookieState('cookie_menus'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function browseList(): string
|
||||
{
|
||||
$menus = $this->repository->menusWithPages();
|
||||
$defaultLanguage = $this->languagesRepository->defaultLanguageId();
|
||||
|
||||
foreach ($menus as $index => $menu) {
|
||||
$menus[$index]['pages'] = $this->withPreviewUrls($menu['pages'] ?? [], $defaultLanguage);
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('pages/pages-browse-list', [
|
||||
'menus' => $menus,
|
||||
'modal' => \Shared\Helpers\Helpers::get('modal'),
|
||||
'cookie_pages' => $this->cookieState('cookie_pages'),
|
||||
'cookie_menus' => $this->cookieState('cookie_menus'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function pagesUrlBrowser(): string
|
||||
{
|
||||
return $this->browseList();
|
||||
}
|
||||
|
||||
public function menuEdit(): string
|
||||
{
|
||||
$menu = $this->repository->menuDetails((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
|
||||
return \Shared\Tpl\Tpl::view('pages/menu-edit', [
|
||||
'form' => $this->buildMenuFormViewModel($menu),
|
||||
]);
|
||||
}
|
||||
|
||||
public function menuSave(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania menu wystapil blad. Prosze sprobowac ponownie.'];
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
|
||||
if (is_array($values) && $this->repository->menuSave(
|
||||
(int)($values['id'] ?? 0),
|
||||
(string)($values['name'] ?? ''),
|
||||
$values['status'] ?? 0
|
||||
)) {
|
||||
$response = ['status' => 'ok', 'msg' => 'Menu zostalo zapisane.'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$menuId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
$name = trim((string)\Shared\Helpers\Helpers::get('name'));
|
||||
$status = \Shared\Helpers\Helpers::get('status');
|
||||
|
||||
if ($name === '') {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['name' => 'Pole "Nazwa" jest wymagane.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($this->repository->menuSave($menuId, $name, $status)) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Menu zostalo zapisane.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania menu wystapil blad. Prosze sprobowac ponownie.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $menu
|
||||
*/
|
||||
private function buildMenuFormViewModel(array $menu): FormEditViewModel
|
||||
{
|
||||
$menuId = (int)($menu['id'] ?? 0);
|
||||
$actionUrl = '/admin/pages/menuSave/' . ($menuId > 0 ? ('id=' . $menuId) : '');
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $menuId),
|
||||
FormField::text('name', [
|
||||
'label' => 'Nazwa',
|
||||
'required' => true,
|
||||
'attributes' => ['class' => 'require'],
|
||||
'value' => (string)($menu['name'] ?? ''),
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywne',
|
||||
'value' => (int)($menu['status'] ?? 0) === 1,
|
||||
]),
|
||||
];
|
||||
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/pages/list/'),
|
||||
FormAction::cancel('/admin/pages/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'pages-menu-edit',
|
||||
'Zapisz menu',
|
||||
$menu,
|
||||
$fields,
|
||||
[],
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/pages/list/',
|
||||
true,
|
||||
['id' => $menuId]
|
||||
);
|
||||
}
|
||||
|
||||
public function menuDelete(): void
|
||||
{
|
||||
if ($this->repository->menuDelete((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::set_message('Menu zostało usunięte.');
|
||||
} else {
|
||||
\Shared\Helpers\Helpers::alert('Podczas usuwania menu wystąpił błąd. Aby usunąć menu, nie może ono posiadać przypiętych stron.');
|
||||
}
|
||||
|
||||
header('Location: /admin/pages/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$page = $this->repository->pageDetails((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
$parentId = (int)\Shared\Helpers\Helpers::get('pid');
|
||||
$menuId = (int)\Shared\Helpers\Helpers::get('menu_id');
|
||||
$menus = $this->repository->menusList();
|
||||
$layouts = $this->layoutsRepository->listAll();
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
|
||||
return \Shared\Tpl\Tpl::view('pages/page-edit', [
|
||||
'form' => $this->buildPageFormViewModel(
|
||||
$page,
|
||||
$parentId,
|
||||
$menuId,
|
||||
$menus,
|
||||
$layouts,
|
||||
$languages
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania strony wystapil blad. Prosze sprobowac ponownie.'];
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
|
||||
if (is_array($values)) {
|
||||
$id = $this->repository->pageSave($values);
|
||||
if (!empty($id)) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Strona zostala zapisana.',
|
||||
'id' => (int)$id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = $_POST;
|
||||
if (!isset($data['id']) || $data['id'] === '') {
|
||||
$data['id'] = (int)\Shared\Helpers\Helpers::get('id');
|
||||
}
|
||||
if (!isset($data['parent_id']) || $data['parent_id'] === '') {
|
||||
$data['parent_id'] = (int)\Shared\Helpers\Helpers::get('pid');
|
||||
}
|
||||
if ((!isset($data['menu_id']) || $data['menu_id'] === '') && (int)\Shared\Helpers\Helpers::get('menu_id') > 0) {
|
||||
$data['menu_id'] = (int)\Shared\Helpers\Helpers::get('menu_id');
|
||||
}
|
||||
|
||||
$savedId = $this->repository->pageSave($data);
|
||||
if (!empty($savedId)) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Strona zostala zapisana.',
|
||||
'id' => (int)$savedId,
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania strony wystapil blad. Prosze sprobowac ponownie.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $page
|
||||
* @param array<int, array<string, mixed>> $menus
|
||||
* @param array<int, array<string, mixed>> $layouts
|
||||
* @param array<int, array<string, mixed>> $languages
|
||||
*/
|
||||
private function buildPageFormViewModel(
|
||||
array $page,
|
||||
int $parentId,
|
||||
int $menuId,
|
||||
array $menus,
|
||||
array $layouts,
|
||||
array $languages
|
||||
): FormEditViewModel {
|
||||
$pageId = (int)($page['id'] ?? 0);
|
||||
$isNew = $pageId <= 0;
|
||||
|
||||
$resolvedParentId = $pageId > 0 ? (int)($page['parent_id'] ?? 0) : $parentId;
|
||||
$resolvedMenuId = $pageId > 0 ? (int)($page['menu_id'] ?? 0) : $menuId;
|
||||
|
||||
$menuOptions = [];
|
||||
foreach ($menus as $menu) {
|
||||
$id = (int)($menu['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
continue;
|
||||
}
|
||||
$menuOptions[$id] = (string)($menu['name'] ?? '');
|
||||
}
|
||||
|
||||
$layoutOptions = ['' => '---- szablon ----'];
|
||||
foreach ($layouts as $layout) {
|
||||
$id = (int)($layout['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
continue;
|
||||
}
|
||||
$layoutOptions[$id] = (string)($layout['name'] ?? '');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $pageId,
|
||||
'parent_id' => $resolvedParentId > 0 ? $resolvedParentId : '',
|
||||
'menu_id' => $resolvedMenuId > 0 ? $resolvedMenuId : '',
|
||||
'page_type' => (int)($page['page_type'] ?? 0),
|
||||
'sort_type' => (int)($page['sort_type'] ?? 0),
|
||||
'layout_id' => (int)($page['layout_id'] ?? 0),
|
||||
'articles_limit' => (int)($page['articles_limit'] ?? 2),
|
||||
'show_title' => (int)($page['show_title'] ?? 1),
|
||||
'status' => (int)($page['status'] ?? 1),
|
||||
'start' => (int)($page['start'] ?? 0),
|
||||
'category_id' => (int)($page['category_id'] ?? 0),
|
||||
'languages' => [],
|
||||
];
|
||||
|
||||
foreach ($languages as $language) {
|
||||
$langId = (string)($language['id'] ?? '');
|
||||
if ($langId === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$translation = is_array($page['languages'][$langId] ?? null) ? $page['languages'][$langId] : [];
|
||||
$data['languages'][$langId] = [
|
||||
'title' => (string)($translation['title'] ?? ''),
|
||||
'link' => (string)($translation['link'] ?? ''),
|
||||
'seo_link' => (string)($translation['seo_link'] ?? ''),
|
||||
'page_title' => (string)($translation['page_title'] ?? ''),
|
||||
'meta_title' => (string)($translation['meta_title'] ?? ''),
|
||||
'meta_description' => (string)($translation['meta_description'] ?? ''),
|
||||
'meta_keywords' => (string)($translation['meta_keywords'] ?? ''),
|
||||
'noindex' => (int)($translation['noindex'] ?? 0),
|
||||
'canonical' => (string)($translation['canonical'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
$tabs = [
|
||||
new FormTab('content', 'Tresc', 'fa-file'),
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
new FormTab('seo', 'SEO', 'fa-globe'),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $pageId),
|
||||
FormField::hidden('parent_id', $resolvedParentId > 0 ? $resolvedParentId : ''),
|
||||
FormField::langSection('page_content', 'content', [
|
||||
FormField::text('title', [
|
||||
'label' => 'Nazwa strony',
|
||||
'required' => true,
|
||||
]),
|
||||
]),
|
||||
FormField::select('menu_id', [
|
||||
'label' => 'Menu',
|
||||
'tab' => 'settings',
|
||||
'options' => $menuOptions,
|
||||
'value' => $resolvedMenuId > 0 ? $resolvedMenuId : '',
|
||||
]),
|
||||
FormField::select('page_type', [
|
||||
'label' => 'Typ strony',
|
||||
'tab' => 'settings',
|
||||
'options' => $this->repository->pageTypes(),
|
||||
'attributes' => ['id' => 'page_type'],
|
||||
'value' => (int)($page['page_type'] ?? 0),
|
||||
]),
|
||||
FormField::langSection('page_links', 'settings', [
|
||||
FormField::text('link', [
|
||||
'label' => 'Link',
|
||||
]),
|
||||
]),
|
||||
FormField::text('category_id', [
|
||||
'label' => 'ID kategorii',
|
||||
'tab' => 'settings',
|
||||
'attributes' => ['id' => 'category_id'],
|
||||
'value' => (int)($page['category_id'] ?? 0),
|
||||
]),
|
||||
FormField::select('sort_type', [
|
||||
'label' => 'Sortowanie artykulow',
|
||||
'tab' => 'settings',
|
||||
'attributes' => ['id' => 'sort_type'],
|
||||
'options' => $this->repository->sortTypes(),
|
||||
'value' => (int)($page['sort_type'] ?? 0),
|
||||
]),
|
||||
FormField::select('layout_id', [
|
||||
'label' => 'Szablon',
|
||||
'tab' => 'settings',
|
||||
'attributes' => ['id' => 'layout_id'],
|
||||
'options' => $layoutOptions,
|
||||
'value' => (int)($page['layout_id'] ?? 0),
|
||||
]),
|
||||
FormField::text('articles_limit', [
|
||||
'label' => 'Liczba artykulow na stronie',
|
||||
'tab' => 'settings',
|
||||
'attributes' => ['id' => 'articles_limit'],
|
||||
'value' => (int)($page['articles_limit'] ?? 2),
|
||||
]),
|
||||
FormField::switch('show_title', [
|
||||
'label' => 'Pokaz tytul',
|
||||
'tab' => 'settings',
|
||||
'value' => (int)($page['show_title'] ?? 0) === 1 || $isNew,
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywna',
|
||||
'tab' => 'settings',
|
||||
'value' => (int)($page['status'] ?? 0) === 1 || $isNew,
|
||||
]),
|
||||
FormField::switch('start', [
|
||||
'label' => 'Strona startowa',
|
||||
'tab' => 'settings',
|
||||
'value' => (int)($page['start'] ?? 0) === 1,
|
||||
]),
|
||||
FormField::langSection('page_seo', 'seo', [
|
||||
FormField::text('seo_link', [
|
||||
'label' => 'Link SEO',
|
||||
'attributes' => [
|
||||
'icon_content' => 'generuj',
|
||||
'icon_js' => 'generateSeoLinkForButton(\'{lang}\')',
|
||||
],
|
||||
]),
|
||||
FormField::text('page_title', [
|
||||
'label' => 'Tytul strony (h1)',
|
||||
]),
|
||||
FormField::text('meta_title', [
|
||||
'label' => 'Meta title',
|
||||
]),
|
||||
FormField::textarea('meta_description', [
|
||||
'label' => 'Meta description',
|
||||
]),
|
||||
FormField::textarea('meta_keywords', [
|
||||
'label' => 'Meta keywords',
|
||||
]),
|
||||
FormField::select('noindex', [
|
||||
'label' => 'Blokuj indeksacje',
|
||||
'options' => [0 => 'nie', 1 => 'tak'],
|
||||
]),
|
||||
FormField::text('canonical', [
|
||||
'label' => 'Rel canonical',
|
||||
]),
|
||||
]),
|
||||
FormField::custom('page_edit_script', '
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
function toggleByType() {
|
||||
var pageType = String($(\'#page_type\').val() || \'\');
|
||||
var $links = $(\'#languages-page_links\');
|
||||
var $category = $(\'#category_id\').closest(\'.form-group\');
|
||||
var $articlesLimit = $(\'#articles_limit\').closest(\'.form-group\');
|
||||
var $sortType = $(\'#sort_type\').closest(\'.form-group\');
|
||||
|
||||
if (pageType === \'0\' || pageType === \'1\' || pageType === \'2\') {
|
||||
$articlesLimit.show();
|
||||
$sortType.show();
|
||||
$links.addClass(\'hide\');
|
||||
$category.hide();
|
||||
} else if (pageType === \'3\') {
|
||||
$links.removeClass(\'hide\');
|
||||
$articlesLimit.hide();
|
||||
$sortType.hide();
|
||||
$category.hide();
|
||||
} else if (pageType === \'5\') {
|
||||
$category.show();
|
||||
$links.addClass(\'hide\');
|
||||
$articlesLimit.hide();
|
||||
$sortType.hide();
|
||||
} else {
|
||||
$links.addClass(\'hide\');
|
||||
$category.hide();
|
||||
$articlesLimit.hide();
|
||||
$sortType.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function generateSeoLink(langId, title) {
|
||||
if (!title) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: \'POST\',
|
||||
cache: false,
|
||||
url: \'/admin/pages/generateSeoLink/\',
|
||||
data: {
|
||||
title: title,
|
||||
page_id: ' . $pageId . '
|
||||
},
|
||||
success: function (data) {
|
||||
var response = data;
|
||||
if (typeof data === \'string\') {
|
||||
try { response = JSON.parse(data); } catch (e) { response = null; }
|
||||
}
|
||||
if (response && response.status === \'ok\') {
|
||||
$(\'#seo_link_\' + langId).val(response.seo_link || \'\');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.generateSeoLinkForButton = function (langId) {
|
||||
var title = $(\'#title_\' + langId).val() || \'\';
|
||||
generateSeoLink(langId, title);
|
||||
};
|
||||
|
||||
$(function () {
|
||||
$(\'#page_type\').on(\'change\', toggleByType);
|
||||
toggleByType();
|
||||
|
||||
$(\'[id^=title_]\').on(\'blur\', function () {
|
||||
var fieldId = $(this).attr(\'id\') || \'\';
|
||||
var langId = fieldId.replace(/^title_/, \'\');
|
||||
if (!langId) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $seo = $(\'#seo_link_\' + langId);
|
||||
if ($seo.length && !$seo.val()) {
|
||||
generateSeoLink(langId, $(this).val());
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>', [
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/pages/save/' . ($pageId > 0 ? ('id=' . $pageId) : '');
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/pages/list/'),
|
||||
FormAction::cancel('/admin/pages/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'pages-page-edit',
|
||||
'Edycja strony',
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/pages/list/',
|
||||
true,
|
||||
[
|
||||
'id' => $pageId,
|
||||
'parent_id' => $resolvedParentId > 0 ? $resolvedParentId : '',
|
||||
],
|
||||
$languages
|
||||
);
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->pageDelete((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::set_message('Strona zostala usunieta.');
|
||||
} else {
|
||||
\Shared\Helpers\Helpers::alert('Podczas usuwania strony wystapil blad. Aby usunac strone nie moze ona posiadac przypietych podstron.');
|
||||
}
|
||||
|
||||
header('Location: /admin/pages/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function pageArticles(): string
|
||||
{
|
||||
$pageId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
return \Shared\Tpl\Tpl::view('pages/page-articles', [
|
||||
'page_id' => $pageId,
|
||||
'articles' => $this->repository->pageArticles($pageId),
|
||||
]);
|
||||
}
|
||||
|
||||
public function savePagesOrder(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania kolejnosci stron wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->savePagesOrder((int)\Shared\Helpers\Helpers::get('menu_id'), \Shared\Helpers\Helpers::get('pages'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function saveArticlesOrder(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania kolejnosci wyswietlania artykulow wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
if ($this->repository->saveArticlesOrder((int)\Shared\Helpers\Helpers::get('page_id'), \Shared\Helpers\Helpers::get('articles'))) {
|
||||
$response = ['status' => 'ok'];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function generateSeoLink(): void
|
||||
{
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas generowania pola "seo link" wystapil blad. Prosze sprobowac ponownie.'];
|
||||
|
||||
$seoLink = $this->repository->generateSeoLink(
|
||||
(string)\Shared\Helpers\Helpers::get('title'),
|
||||
(int)\Shared\Helpers\Helpers::get('page_id'),
|
||||
(int)\Shared\Helpers\Helpers::get('article_id'),
|
||||
(int)\Shared\Helpers\Helpers::get('category_id')
|
||||
);
|
||||
|
||||
if ($seoLink !== '') {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'seo_link' => $seoLink,
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function cookieMenus(): void
|
||||
{
|
||||
$this->repository->toggleCookieValue('cookie_menus', (int)\Shared\Helpers\Helpers::get('menu_id'));
|
||||
exit;
|
||||
}
|
||||
|
||||
public function cookiePages(): void
|
||||
{
|
||||
$this->repository->toggleCookieValue('cookie_pages', (int)\Shared\Helpers\Helpers::get('page_id'));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $pages
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
private function withPreviewUrls(array $pages, string $defaultLanguage): array
|
||||
{
|
||||
foreach ($pages as $index => $page) {
|
||||
$pageId = (int)($page['id'] ?? 0);
|
||||
$languages = is_array($page['languages'] ?? null) ? $page['languages'] : [];
|
||||
|
||||
$previewUrls = [];
|
||||
foreach ($languages as $languageRow) {
|
||||
$langId = (string)($languageRow['lang_id'] ?? '');
|
||||
if ($langId === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$previewUrls[$langId] = $this->repository->pageUrlPreview(
|
||||
$pageId,
|
||||
$langId,
|
||||
(string)($languageRow['title'] ?? ''),
|
||||
(string)($languageRow['seo_link'] ?? ''),
|
||||
$defaultLanguage
|
||||
);
|
||||
}
|
||||
|
||||
$page['preview_urls'] = $previewUrls;
|
||||
$page['subpages'] = $this->withPreviewUrls($page['subpages'] ?? [], $defaultLanguage);
|
||||
$pages[$index] = $page;
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, int>
|
||||
*/
|
||||
private function cookieState(string $cookieName): array
|
||||
{
|
||||
if (empty($_COOKIE[$cookieName])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$decoded = @unserialize((string)$_COOKIE[$cookieName], ['allowed_classes' => false]);
|
||||
if (!is_array($decoded)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$state = [];
|
||||
foreach ($decoded as $key => $value) {
|
||||
$state[(int)$key] = (int)$value;
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
}
|
||||
|
||||
165
autoload/admin/Controllers/ProductArchiveController.php
Normal file
165
autoload/admin/Controllers/ProductArchiveController.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Product\ProductRepository;
|
||||
|
||||
class ProductArchiveController
|
||||
{
|
||||
private ProductRepository $productRepository;
|
||||
|
||||
public function __construct(ProductRepository $productRepository)
|
||||
{
|
||||
$this->productRepository = $productRepository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'name', 'price_brutto', 'price_brutto_promo', 'quantity'];
|
||||
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'phrase',
|
||||
'label' => 'Nazwa / EAN / SKU',
|
||||
'type' => 'text',
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'id',
|
||||
[10, 15, 25, 50, 100],
|
||||
10
|
||||
);
|
||||
|
||||
$result = $this->productRepository->listArchivedForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$listRequest['sortDir'],
|
||||
$listRequest['page'],
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)($item['id'] ?? 0);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$sku = trim((string)($item['sku'] ?? ''));
|
||||
$ean = trim((string)($item['ean'] ?? ''));
|
||||
$imageSrc = trim((string)($item['image_src'] ?? ''));
|
||||
$imageAlt = trim((string)($item['image_alt'] ?? ''));
|
||||
$priceBrutto = (string)($item['price_brutto'] ?? '');
|
||||
$priceBruttoPromo = (string)($item['price_brutto_promo'] ?? '');
|
||||
$quantity = (int)($item['quantity'] ?? 0);
|
||||
$combinations = (int)($item['combinations'] ?? 0);
|
||||
|
||||
if ($imageSrc === '') {
|
||||
$imageSrc = '/admin/layout/images/no-image.png';
|
||||
} elseif (!preg_match('#^(https?:)?//#i', $imageSrc) && strpos($imageSrc, '/') !== 0) {
|
||||
$imageSrc = '/' . ltrim($imageSrc, '/');
|
||||
}
|
||||
|
||||
$categories = trim((string)$this->productRepository->productCategoriesText($id));
|
||||
$categoriesHtml = '';
|
||||
if ($categories !== '') {
|
||||
$categoriesHtml = '<small class="text-muted product-categories">'
|
||||
. htmlspecialchars($categories, ENT_QUOTES, 'UTF-8')
|
||||
. '</small>';
|
||||
}
|
||||
|
||||
$skuEanParts = [];
|
||||
if ($sku !== '') {
|
||||
$skuEanParts[] = 'SKU: ' . htmlspecialchars($sku, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
if ($ean !== '') {
|
||||
$skuEanParts[] = 'EAN: ' . htmlspecialchars($ean, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$skuEanHtml = '';
|
||||
if (!empty($skuEanParts)) {
|
||||
$skuEanHtml = '<small class="text-muted product-categories">' . implode(', ', $skuEanParts) . '</small>';
|
||||
}
|
||||
|
||||
$productCell = '<div class="product-image product-archive-thumb-wrap">'
|
||||
. '<img src="' . htmlspecialchars($imageSrc, ENT_QUOTES, 'UTF-8') . '" alt="' . htmlspecialchars($imageAlt, ENT_QUOTES, 'UTF-8') . '" '
|
||||
. 'data-preview-src="' . htmlspecialchars($imageSrc, ENT_QUOTES, 'UTF-8') . '" '
|
||||
. 'class="img-responsive product-archive-thumb-image js-product-archive-thumb-preview" loading="lazy">'
|
||||
. '</div>'
|
||||
. '<div class="product-name">'
|
||||
. '<a href="/admin/shop_product/product_edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>'
|
||||
. '</div>'
|
||||
. $categoriesHtml
|
||||
. $skuEanHtml;
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'product' => $productCell,
|
||||
'price_brutto' => $priceBrutto !== '' ? $priceBrutto : '-',
|
||||
'price_brutto_promo' => $priceBruttoPromo !== '' ? $priceBruttoPromo : '-',
|
||||
'quantity' => (string)$quantity,
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Przywroc',
|
||||
'url' => '/admin/product_archive/unarchive/product_id=' . $id,
|
||||
'class' => 'btn btn-xs btn-success',
|
||||
'confirm' => 'Na pewno chcesz przywrocic wybrany produkt z archiwum?',
|
||||
'confirm_ok' => 'Przywroc',
|
||||
'confirm_cancel' => 'Anuluj',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'product', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'price_brutto', 'sort_key' => 'price_brutto', 'label' => 'Cena', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'price_brutto_promo', 'sort_key' => 'price_brutto_promo', 'label' => 'Cena promocyjna', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'quantity', 'sort_key' => 'quantity', 'label' => 'Stan MG', 'class' => 'text-center', 'sortable' => true]
|
||||
],
|
||||
$rows,
|
||||
$listRequest['viewFilters'],
|
||||
[
|
||||
'column' => $listRequest['sortColumn'],
|
||||
'dir' => $listRequest['sortDir'],
|
||||
],
|
||||
[
|
||||
'page' => $listRequest['page'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
'total' => $total,
|
||||
'total_pages' => $totalPages,
|
||||
],
|
||||
array_merge($listRequest['queryFilters'], [
|
||||
'sort' => $listRequest['sortColumn'],
|
||||
'dir' => $listRequest['sortDir'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
]),
|
||||
$listRequest['perPageOptions'],
|
||||
$sortableColumns,
|
||||
'/admin/product_archive/list/',
|
||||
'Brak danych w tabeli.',
|
||||
null,
|
||||
null,
|
||||
'product-archive/products-list-custom-script'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('product-archive/products-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function unarchive(): void
|
||||
{
|
||||
if ( $this->productRepository->unarchive( (int) \Shared\Helpers\Helpers::get( 'product_id' ) ) )
|
||||
\Shared\Helpers\Helpers::alert( 'Produkt został przywrócony z archiwum.' );
|
||||
else
|
||||
\Shared\Helpers\Helpers::alert( 'Podczas przywracania produktu z archiwum wystąpił błąd. Proszę spróbować ponownie' );
|
||||
|
||||
header( 'Location: /admin/product_archive/list/' );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
297
autoload/admin/Controllers/ScontainersController.php
Normal file
297
autoload/admin/Controllers/ScontainersController.php
Normal 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)\Shared\Helpers\Helpers::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/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/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/scontainers/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/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/scontainers/edit/',
|
||||
'Dodaj kontener'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('scontainers/containers-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$container = $this->repository->find((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
$validationErrors = $_SESSION['form_errors'][$this->formId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->formId()]);
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('scontainers/container-edit', [
|
||||
'form' => $this->buildFormViewModel($container, $languages, $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function container_edit(): string
|
||||
{
|
||||
return $this->edit();
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::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)\Shared\Helpers\Helpers::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)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Kontener zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/scontainers/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/save/' . ($isNew ? '' : ('id=' . $id));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/scontainers/list/'),
|
||||
FormAction::cancel('/admin/scontainers/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->formId(),
|
||||
'Edycja kontenera statycznego',
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/scontainers/list/',
|
||||
true,
|
||||
[],
|
||||
$languages,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function formId(): string
|
||||
{
|
||||
return 'scontainers-container-edit';
|
||||
}
|
||||
}
|
||||
|
||||
536
autoload/admin/Controllers/SettingsController.php
Normal file
536
autoload/admin/Controllers/SettingsController.php
Normal file
@@ -0,0 +1,536 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
use Domain\Settings\SettingsRepository;
|
||||
use admin\ViewModels\Forms\FormEditViewModel;
|
||||
use admin\ViewModels\Forms\FormField;
|
||||
use admin\ViewModels\Forms\FormTab;
|
||||
use admin\ViewModels\Forms\FormAction;
|
||||
use admin\Support\Forms\FormRequestHandler;
|
||||
|
||||
/**
|
||||
* Kontroler ustawien w panelu administratora.
|
||||
*/
|
||||
class SettingsController
|
||||
{
|
||||
private SettingsRepository $settingsRepository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
private FormRequestHandler $formHandler;
|
||||
|
||||
public function __construct(SettingsRepository $settingsRepository, LanguagesRepository $languagesRepository)
|
||||
{
|
||||
$this->settingsRepository = $settingsRepository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
$this->formHandler = new FormRequestHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Czyszczenie cache.
|
||||
*/
|
||||
public function clearCache(): void
|
||||
{
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
\Shared\Helpers\Helpers::delete_dir('../thumbs/');
|
||||
|
||||
$redis = \Shared\Cache\RedisConnection::getInstance()->getConnection();
|
||||
if ($redis) {
|
||||
$redis->flushAll();
|
||||
}
|
||||
|
||||
\Shared\Helpers\Helpers::alert('Cache został wyczyszczony.');
|
||||
\Shared\Helpers\Helpers::htacces();
|
||||
|
||||
header('Location: /admin/dashboard/main_view/');
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Czyszczenie cache (AJAX).
|
||||
*/
|
||||
public function clearCacheAjax(): void
|
||||
{
|
||||
try {
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
\Shared\Helpers\Helpers::delete_dir('../thumbs/');
|
||||
|
||||
$redis = \Shared\Cache\RedisConnection::getInstance()->getConnection();
|
||||
if ($redis) {
|
||||
$redis->flushAll();
|
||||
}
|
||||
|
||||
\Shared\Helpers\Helpers::htacces();
|
||||
|
||||
echo json_encode(['status' => 'success', 'message' => 'Cache został wyczyszczony.']);
|
||||
} catch (\Exception $e) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Błąd podczas czyszczenia cache: ' . $e->getMessage()]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Globalna wyszukiwarka admin (produkty + zamowienia) - AJAX.
|
||||
*/
|
||||
public function globalSearchAjax(): void
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
$phrase = trim((string)\Shared\Helpers\Helpers::get('q'));
|
||||
if ($phrase === '' || mb_strlen($phrase) < 2) {
|
||||
echo json_encode([
|
||||
'status' => 'ok',
|
||||
'items' => [],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$phrase = mb_substr($phrase, 0, 120);
|
||||
$phraseNormalized = preg_replace('/\s+/', ' ', $phrase);
|
||||
$phraseNormalized = trim((string)$phraseNormalized);
|
||||
$like = '%' . $phrase . '%';
|
||||
$likeNormalized = '%' . $phraseNormalized . '%';
|
||||
|
||||
$items = [];
|
||||
$defaultLang = (string)$this->languagesRepository->defaultLanguage();
|
||||
|
||||
try {
|
||||
$productStmt = $mdb->query(
|
||||
'SELECT '
|
||||
. 'p.id, p.ean, p.sku, p.parent_id, psl.name '
|
||||
. 'FROM pp_shop_products AS p '
|
||||
. 'LEFT JOIN pp_shop_products_langs AS psl ON psl.product_id = p.id AND psl.lang_id = :lang_id '
|
||||
. 'WHERE '
|
||||
. '(p.ean LIKE :q1 OR p.sku LIKE :q2 OR psl.name LIKE :q3) '
|
||||
. 'AND p.archive != 1 '
|
||||
. 'ORDER BY p.id DESC '
|
||||
. 'LIMIT 15',
|
||||
[
|
||||
':lang_id' => $defaultLang,
|
||||
':q1' => $like,
|
||||
':q2' => $like,
|
||||
':q3' => $like,
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$productStmt = false;
|
||||
}
|
||||
|
||||
$productRows = $productStmt ? $productStmt->fetchAll() : [];
|
||||
if (is_array($productRows)) {
|
||||
foreach ($productRows as $row) {
|
||||
$productId = (int)($row['id'] ?? 0);
|
||||
if ($productId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = trim((string)($row['name'] ?? ''));
|
||||
if ($name === '') {
|
||||
$name = 'Produkt #' . $productId;
|
||||
}
|
||||
|
||||
$meta = [];
|
||||
$sku = trim((string)($row['sku'] ?? ''));
|
||||
$ean = trim((string)($row['ean'] ?? ''));
|
||||
if ($sku !== '') {
|
||||
$meta[] = 'SKU: ' . $sku;
|
||||
}
|
||||
if ($ean !== '') {
|
||||
$meta[] = 'EAN: ' . $ean;
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'type' => 'product',
|
||||
'title' => $name,
|
||||
'subtitle' => implode(' | ', $meta),
|
||||
'url' => '/admin/shop_product/product_edit/id=' . $productId,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$orderStmt = $mdb->query(
|
||||
'SELECT '
|
||||
. 'id, number, client_name, client_surname, client_email, client_phone '
|
||||
. 'FROM pp_shop_orders '
|
||||
. 'WHERE '
|
||||
. '('
|
||||
. 'number LIKE :q1 '
|
||||
. 'OR client_email LIKE :q2 '
|
||||
. 'OR client_name LIKE :q3 '
|
||||
. 'OR client_surname LIKE :q4 '
|
||||
. 'OR client_phone LIKE :q5 '
|
||||
. "OR CONCAT_WS(' ', TRIM(client_name), TRIM(client_surname)) LIKE :q6 "
|
||||
. "OR CONCAT_WS(' ', TRIM(client_surname), TRIM(client_name)) LIKE :q7 "
|
||||
. ') '
|
||||
. 'ORDER BY id DESC '
|
||||
. 'LIMIT 15',
|
||||
[
|
||||
':q1' => $like,
|
||||
':q2' => $like,
|
||||
':q3' => $like,
|
||||
':q4' => $like,
|
||||
':q5' => $like,
|
||||
':q6' => $likeNormalized,
|
||||
':q7' => $likeNormalized,
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$orderStmt = false;
|
||||
}
|
||||
|
||||
$orderRows = $orderStmt ? $orderStmt->fetchAll() : [];
|
||||
if (is_array($orderRows)) {
|
||||
foreach ($orderRows as $row) {
|
||||
$orderId = (int)($row['id'] ?? 0);
|
||||
if ($orderId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$orderNumber = trim((string)($row['number'] ?? ''));
|
||||
$clientName = trim((string)($row['client_name'] ?? ''));
|
||||
$clientSurname = trim((string)($row['client_surname'] ?? ''));
|
||||
$clientEmail = trim((string)($row['client_email'] ?? ''));
|
||||
$clientPhone = trim((string)($row['client_phone'] ?? ''));
|
||||
|
||||
$title = $orderNumber !== '' ? 'Zamówienie ' . $orderNumber : 'Zamówienie #' . $orderId;
|
||||
$subtitleParts = [];
|
||||
$fullName = trim($clientName . ' ' . $clientSurname);
|
||||
if ($fullName !== '') {
|
||||
$subtitleParts[] = $fullName;
|
||||
}
|
||||
if ($clientEmail !== '') {
|
||||
$subtitleParts[] = $clientEmail;
|
||||
}
|
||||
if ($clientPhone !== '') {
|
||||
$subtitleParts[] = $clientPhone;
|
||||
}
|
||||
|
||||
$items[] = [
|
||||
'type' => 'order',
|
||||
'title' => $title,
|
||||
'subtitle' => implode(' | ', $subtitleParts),
|
||||
'url' => '/admin/shop_order/order_details/order_id=' . $orderId,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'ok',
|
||||
'items' => array_slice($items, 0, 20),
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapis ustawien (AJAX).
|
||||
*/
|
||||
public function save(): void
|
||||
{
|
||||
// Kompatybilnosc wsteczna dla legacy gridEdit (values jako JSON).
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode($legacyValues, true);
|
||||
$result = $this->settingsRepository->saveSettings(is_array($values) ? $values : []);
|
||||
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
\Shared\Helpers\Helpers::htacces();
|
||||
|
||||
echo json_encode($result);
|
||||
exit;
|
||||
}
|
||||
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
$settings = $this->settingsRepository->getSettings();
|
||||
$viewModel = $this->buildFormViewModel($settings, $languages);
|
||||
|
||||
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
|
||||
if (!$result['success']) {
|
||||
$_SESSION['form_errors'][$this->getFormId()] = $result['errors'];
|
||||
echo json_encode(['success' => false, 'errors' => $result['errors']]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$values = $this->transformFormDataToSettings($result['data']);
|
||||
$saveResult = $this->settingsRepository->saveSettings($values);
|
||||
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
\Shared\Helpers\Helpers::htacces();
|
||||
|
||||
echo json_encode([
|
||||
'success' => ($saveResult['status'] ?? '') === 'ok',
|
||||
'message' => $saveResult['msg'] ?? 'Ustawienia zostały zapisane.',
|
||||
'errors' => (($saveResult['status'] ?? '') === 'ok') ? [] : ['general' => ($saveResult['msg'] ?? 'Błąd zapisu.')],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Widok ustawien.
|
||||
*/
|
||||
public function view(): string
|
||||
{
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
$settings = $this->settingsRepository->getSettings();
|
||||
|
||||
$validationErrors = $_SESSION['form_errors'][$this->getFormId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->getFormId()]);
|
||||
}
|
||||
|
||||
$viewModel = $this->buildFormViewModel($settings, $languages, $validationErrors);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('components/form-edit', ['form' => $viewModel]);
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $settings, array $languages, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$data = $this->transformSettingsToFormData($settings, $languages);
|
||||
|
||||
$tabs = [
|
||||
new FormTab('contact', 'Dane kontaktowe', 'fa-paper-plane'),
|
||||
new FormTab('shop', 'Sklep', 'fa-dollar'),
|
||||
new FormTab('products', 'Produkty', 'fa-shopping-cart'),
|
||||
new FormTab('mail', 'Poczta', 'fa-envelope'),
|
||||
new FormTab('other', 'Pozostałe', 'fa-bars'),
|
||||
new FormTab('system', 'System', 'fa-cog'),
|
||||
new FormTab('conversions', 'Konwersje', 'fa-line-chart'),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::text('firm_name', [
|
||||
'label' => 'Nazwa firmy',
|
||||
'tab' => 'contact',
|
||||
]),
|
||||
FormField::editor('additional_info', [
|
||||
'label' => 'Dodatkowe informacje',
|
||||
'tab' => 'contact',
|
||||
'height' => 150,
|
||||
]),
|
||||
FormField::switch('google_maps', [
|
||||
'label' => 'Mapa',
|
||||
'tab' => 'contact',
|
||||
]),
|
||||
FormField::textarea('firm_adress', [
|
||||
'label' => 'Mapa - adres',
|
||||
'tab' => 'contact',
|
||||
]),
|
||||
|
||||
FormField::editor('shop_bank_account_info', [
|
||||
'label' => 'Dane do przelewu',
|
||||
'tab' => 'shop',
|
||||
'height' => 200,
|
||||
]),
|
||||
FormField::text('hotpay_api', [
|
||||
'label' => 'Klucz API HotPay',
|
||||
'tab' => 'shop',
|
||||
]),
|
||||
FormField::switch('tpay_sandbox', [
|
||||
'label' => 'Tpay.com - tryb sandbox',
|
||||
'tab' => 'shop',
|
||||
]),
|
||||
FormField::text('tpay_id', [
|
||||
'label' => 'Tpay.com ID',
|
||||
'tab' => 'shop',
|
||||
]),
|
||||
FormField::text('tpay_security_code', [
|
||||
'label' => 'Tpay.com - kod bezpieczeństwa',
|
||||
'tab' => 'shop',
|
||||
]),
|
||||
FormField::switch('przelewy24_sandbox', [
|
||||
'label' => 'Przelewy24.pl - tryb sandbox',
|
||||
'tab' => 'shop',
|
||||
]),
|
||||
FormField::text('przelewy24_merchant_id', [
|
||||
'label' => 'Przelewy24.pl - merchant ID',
|
||||
'tab' => 'shop',
|
||||
]),
|
||||
FormField::text('przelewy24_crc_key', [
|
||||
'label' => 'Przelewy24.pl - klucz CRC',
|
||||
'tab' => 'shop',
|
||||
]),
|
||||
FormField::text('free_delivery', [
|
||||
'label' => 'Darmowa dostawa od',
|
||||
'tab' => 'shop',
|
||||
'attributes' => ['class' => 'number-format'],
|
||||
]),
|
||||
FormField::text('orlen_paczka_map_token', [
|
||||
'label' => 'Orlen Paczka map token',
|
||||
'tab' => 'shop',
|
||||
]),
|
||||
|
||||
FormField::langSection('warehouse_messages', 'products', [
|
||||
FormField::text('warehouse_message_zero', [
|
||||
'label' => 'Komunikat gdy stan magazynowy równy 0',
|
||||
]),
|
||||
FormField::text('warehouse_message_nonzero', [
|
||||
'label' => 'Komunikat gdy stan magazynowy większy niż 0',
|
||||
]),
|
||||
]),
|
||||
|
||||
FormField::switch('contact_form', [
|
||||
'label' => 'Formularz kontaktowy',
|
||||
'tab' => 'mail',
|
||||
]),
|
||||
FormField::text('contact_email', [
|
||||
'label' => 'Email kontaktowy',
|
||||
'tab' => 'mail',
|
||||
]),
|
||||
FormField::text('email_host', [
|
||||
'label' => 'Email - host',
|
||||
'tab' => 'mail',
|
||||
]),
|
||||
FormField::text('email_port', [
|
||||
'label' => 'Email - port',
|
||||
'tab' => 'mail',
|
||||
]),
|
||||
FormField::text('email_login', [
|
||||
'label' => 'Email - login',
|
||||
'tab' => 'mail',
|
||||
]),
|
||||
FormField::text('email_password', [
|
||||
'label' => 'Email - hasło',
|
||||
'tab' => 'mail',
|
||||
]),
|
||||
|
||||
FormField::text('facebook_link', [
|
||||
'label' => 'Facebook link',
|
||||
'tab' => 'other',
|
||||
]),
|
||||
FormField::text('piksel', [
|
||||
'label' => 'Piksel Facebook',
|
||||
'tab' => 'other',
|
||||
]),
|
||||
FormField::textarea('statistic_code', [
|
||||
'label' => 'Kod statystyk',
|
||||
'tab' => 'other',
|
||||
'rows' => 10,
|
||||
]),
|
||||
FormField::textarea('htaccess', [
|
||||
'label' => 'Własne reguły htacess',
|
||||
'tab' => 'other',
|
||||
'rows' => 10,
|
||||
]),
|
||||
FormField::textarea('robots', [
|
||||
'label' => 'Własne reguły robots.txt',
|
||||
'tab' => 'other',
|
||||
'rows' => 10,
|
||||
]),
|
||||
|
||||
FormField::switch('update', [
|
||||
'label' => 'Aktualizacja',
|
||||
'tab' => 'system',
|
||||
]),
|
||||
FormField::text('update_key', [
|
||||
'label' => 'Numer licencji',
|
||||
'tab' => 'system',
|
||||
]),
|
||||
FormField::switch('devel', [
|
||||
'label' => 'Strona konstrukcyjna',
|
||||
'tab' => 'system',
|
||||
]),
|
||||
FormField::switch('lazy_loading', [
|
||||
'label' => 'Lazy loading obrazów',
|
||||
'tab' => 'system',
|
||||
]),
|
||||
FormField::switch('generate_webp', [
|
||||
'label' => 'Generowanie obrazków WEBP',
|
||||
'tab' => 'system',
|
||||
]),
|
||||
FormField::switch('infinitescroll', [
|
||||
'label' => 'Infinitescroll',
|
||||
'tab' => 'system',
|
||||
]),
|
||||
FormField::switch('htaccess_cache', [
|
||||
'label' => 'Htaccess cache',
|
||||
'tab' => 'system',
|
||||
]),
|
||||
FormField::text('api_key', [
|
||||
'label' => 'Klucz API (ordersPRO)',
|
||||
'tab' => 'system',
|
||||
]),
|
||||
|
||||
FormField::text('google_tag_manager_id', [
|
||||
'label' => 'Google Tag Manager - ID',
|
||||
'tab' => 'conversions',
|
||||
]),
|
||||
FormField::textarea('own_gtm_js', [
|
||||
'label' => 'Własny kod GTM JS (bez tagu script)',
|
||||
'tab' => 'conversions',
|
||||
'rows' => 10,
|
||||
]),
|
||||
FormField::textarea('own_gtm_html', [
|
||||
'label' => 'Własny kod GTM HTML',
|
||||
'tab' => 'conversions',
|
||||
'rows' => 10,
|
||||
]),
|
||||
];
|
||||
|
||||
$actions = [
|
||||
FormAction::save('/admin/settings/save/', ''),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->getFormId(),
|
||||
'Edycja ustawień',
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
'/admin/settings/save/',
|
||||
null,
|
||||
false,
|
||||
[],
|
||||
$languages,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function getFormId(): string
|
||||
{
|
||||
return 'settings-edit';
|
||||
}
|
||||
|
||||
private function transformSettingsToFormData(array $settings, array $languages): array
|
||||
{
|
||||
$data = $settings;
|
||||
$data['languages'] = [];
|
||||
|
||||
foreach ($languages as $lang) {
|
||||
if (!($lang['status'] ?? false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$langId = (string)$lang['id'];
|
||||
$data['languages'][$langId] = [
|
||||
'warehouse_message_zero' => $settings['warehouse_message_zero_' . $langId] ?? '',
|
||||
'warehouse_message_nonzero' => $settings['warehouse_message_nonzero_' . $langId] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function transformFormDataToSettings(array $data): array
|
||||
{
|
||||
if (!isset($data['warehouse_messages']) || !is_array($data['warehouse_messages'])) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data['warehouse_message_zero'] = [];
|
||||
$data['warehouse_message_nonzero'] = [];
|
||||
|
||||
foreach ($data['warehouse_messages'] as $langId => $langValues) {
|
||||
if (!is_array($langValues)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data['warehouse_message_zero'][$langId] = $langValues['warehouse_message_zero'] ?? '';
|
||||
$data['warehouse_message_nonzero'][$langId] = $langValues['warehouse_message_nonzero'] ?? '';
|
||||
}
|
||||
|
||||
unset($data['warehouse_messages']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
451
autoload/admin/Controllers/ShopAttributeController.php
Normal file
451
autoload/admin/Controllers/ShopAttributeController.php
Normal file
@@ -0,0 +1,451 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Attribute\AttributeRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
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;
|
||||
|
||||
class ShopAttributeController
|
||||
{
|
||||
private AttributeRepository $repository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
|
||||
public function __construct(
|
||||
AttributeRepository $repository,
|
||||
LanguagesRepository $languagesRepository
|
||||
) {
|
||||
$this->repository = $repository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'o', 'name', 'type', 'status', 'values_count'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Aktywny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- aktywny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'o'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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 = (int)($item['id'] ?? 0);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
$type = (int)($item['type'] ?? 0);
|
||||
$order = (int)($item['o'] ?? 0);
|
||||
$valuesCount = (int)($item['values_count'] ?? 0);
|
||||
|
||||
$typeLabel = '-';
|
||||
if ($type === 0) {
|
||||
$typeLabel = 'tekst';
|
||||
} elseif ($type === 1) {
|
||||
$typeLabel = 'kolor';
|
||||
} elseif ($type === 2) {
|
||||
$typeLabel = 'wzor';
|
||||
}
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'o' => $order,
|
||||
'name' => '<a href="/admin/shop_attribute/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'type' => htmlspecialchars($typeLabel, ENT_QUOTES, 'UTF-8'),
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'values' => '<a href="/admin/shop_attribute/values/id=' . $id . '">edytuj wartosci</a>',
|
||||
'values_count' => $valuesCount,
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/shop_attribute/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/shop_attribute/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrana ceche?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'o', 'sort_key' => 'o', 'label' => 'Kolejnosc', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'type', 'sort_key' => 'type', 'label' => 'Typ', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'values_count', 'sort_key' => 'values_count', 'label' => 'Ilosc wartosci', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'values', 'label' => 'Wartosci', 'class' => 'text-center', 'sortable' => false, '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/shop_attribute/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/shop_attribute/edit/',
|
||||
'Dodaj ceche'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-attribute/attributes-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$attribute = $this->repository->findAttribute((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-attribute/attribute-edit', [
|
||||
'form' => $this->buildFormViewModel($attribute, $languages),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania atrybutu wystapil blad. Prosze sprobowac ponownie.',
|
||||
];
|
||||
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
if (is_array($values)) {
|
||||
$id = $this->repository->saveAttribute($values);
|
||||
if (!empty($id)) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Atrybut zostal zapisany.',
|
||||
'id' => (int)$id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$payload = $_POST;
|
||||
if (empty($payload['id'])) {
|
||||
$routeId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
if ($routeId > 0) {
|
||||
$payload['id'] = $routeId;
|
||||
}
|
||||
}
|
||||
|
||||
$id = $this->repository->saveAttribute($payload);
|
||||
if (!empty($id)) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => (int)$id,
|
||||
'message' => 'Atrybut zostal zapisany.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania atrybutu wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->deleteAttribute((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Atrybut zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_attribute/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function values(): string
|
||||
{
|
||||
$attributeId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
if ($attributeId <= 0) {
|
||||
\Shared\Helpers\Helpers::alert('Nieprawidlowy identyfikator cechy.');
|
||||
header('Location: /admin/shop_attribute/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
$attribute = $this->repository->findAttribute($attributeId);
|
||||
if ((int)($attribute['id'] ?? 0) <= 0) {
|
||||
\Shared\Helpers\Helpers::alert('Wybrana cecha nie zostala znaleziona.');
|
||||
header('Location: /admin/shop_attribute/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-attribute/values-edit', [
|
||||
'attribute' => $attribute,
|
||||
'values' => $this->repository->findValues($attributeId),
|
||||
'languages' => $languages,
|
||||
'defaultLanguageId' => $this->languagesRepository->defaultLanguageId(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function values_save(): void
|
||||
{
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania wartosci atrybutu wystapil blad. Prosze sprobowac ponownie.',
|
||||
];
|
||||
|
||||
$attributeId = (int)\Shared\Helpers\Helpers::get('attribute_id');
|
||||
if ($attributeId <= 0) {
|
||||
$attributeId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
}
|
||||
|
||||
$payloadRaw = \Shared\Helpers\Helpers::get('payload');
|
||||
$payload = json_decode((string)$payloadRaw, true);
|
||||
if (is_array($payload) && is_array($payload['rows'] ?? null) && $attributeId > 0) {
|
||||
$validationErrors = $this->validateValuesRows(
|
||||
$payload['rows'],
|
||||
$this->languagesRepository->defaultLanguageId()
|
||||
);
|
||||
|
||||
if (!empty($validationErrors)) {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'msg' => $validationErrors[0],
|
||||
'errors' => $validationErrors,
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$saved = $this->repository->saveValues($attributeId, ['rows' => $payload['rows']]);
|
||||
if ($saved) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Wartosci atrybutu zostaly zapisane.',
|
||||
'id' => (int)$attributeId,
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$valuesRaw = \Shared\Helpers\Helpers::get('values');
|
||||
$values = json_decode((string)$valuesRaw, true);
|
||||
if (is_array($values) && $attributeId > 0) {
|
||||
$savedId = $this->repository->saveLegacyValues(
|
||||
$attributeId,
|
||||
is_array($values['name'] ?? null) ? $values['name'] : [],
|
||||
is_array($values['value'] ?? null) ? $values['value'] : [],
|
||||
is_array($values['ids'] ?? null) ? $values['ids'] : [],
|
||||
$values['default_value'] ?? '',
|
||||
is_array($values['impact_on_the_price'] ?? null) ? $values['impact_on_the_price'] : []
|
||||
);
|
||||
|
||||
if (!empty($savedId)) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Wartosci atrybutu zostaly zapisane.',
|
||||
'id' => (int)$savedId,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function value_row_tpl(): void
|
||||
{
|
||||
$rowKey = trim((string)\Shared\Helpers\Helpers::get('row_key'));
|
||||
if ($rowKey === '') {
|
||||
$rowKey = 'new-' . time();
|
||||
}
|
||||
|
||||
$html = \Shared\Tpl\Tpl::view('shop-attribute/_partials/value-row', [
|
||||
'rowKey' => $rowKey,
|
||||
'value' => ['id' => 0, 'is_default' => 0, 'impact_on_the_price' => null, 'languages' => []],
|
||||
'languages' => $this->languagesRepository->languagesList(),
|
||||
'defaultLanguageId' => $this->languagesRepository->defaultLanguageId(),
|
||||
]);
|
||||
|
||||
echo $html;
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $rows
|
||||
* @return array<int, string>
|
||||
*/
|
||||
private function validateValuesRows(array $rows, string $defaultLanguageId): array
|
||||
{
|
||||
$errors = [];
|
||||
if (empty($rows)) {
|
||||
return ['Dodaj co najmniej jedna wartosc cechy.'];
|
||||
}
|
||||
|
||||
$defaultCount = 0;
|
||||
foreach ($rows as $index => $row) {
|
||||
$rowNumber = $index + 1;
|
||||
if (!is_array($row)) {
|
||||
$errors[] = 'Nieprawidlowe dane wiersza nr ' . $rowNumber . '.';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($row['is_default'])) {
|
||||
++$defaultCount;
|
||||
}
|
||||
|
||||
$translations = is_array($row['translations'] ?? null) ? $row['translations'] : [];
|
||||
$defaultLangData = is_array($translations[$defaultLanguageId] ?? null)
|
||||
? $translations[$defaultLanguageId]
|
||||
: [];
|
||||
$defaultName = trim((string)($defaultLangData['name'] ?? ''));
|
||||
if ($defaultName === '') {
|
||||
$errors[] = 'Wiersz nr ' . $rowNumber . ': nazwa w jezyku domyslnym jest wymagana.';
|
||||
}
|
||||
|
||||
$impact = trim((string)($row['impact_on_the_price'] ?? ''));
|
||||
if ($impact !== '' && !preg_match('/^-?[0-9]+([.,][0-9]{1,4})?$/', $impact)) {
|
||||
$errors[] = 'Wiersz nr ' . $rowNumber . ': nieprawidlowy format "wplyw na cene".';
|
||||
}
|
||||
}
|
||||
|
||||
if ($defaultCount !== 1) {
|
||||
$errors[] = 'Wybierz dokladnie jedna wartosc domyslna.';
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $attribute, array $languages): FormEditViewModel
|
||||
{
|
||||
$id = (int)($attribute['id'] ?? 0);
|
||||
$isNew = $id <= 0;
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'status' => (int)($attribute['status'] ?? 1),
|
||||
'type' => (int)($attribute['type'] ?? 0),
|
||||
'o' => (int)($attribute['o'] ?? 0),
|
||||
'languages' => [],
|
||||
];
|
||||
|
||||
if (is_array($attribute['languages'] ?? null)) {
|
||||
foreach ($attribute['languages'] as $langId => $translation) {
|
||||
$data['languages'][(string)$langId] = [
|
||||
'name' => (string)($translation['name'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $id),
|
||||
FormField::langSection('attribute_content', 'content', [
|
||||
FormField::text('name', [
|
||||
'label' => 'Tytul',
|
||||
]),
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
'tab' => 'settings',
|
||||
'value' => true,
|
||||
]),
|
||||
FormField::select('type', [
|
||||
'label' => 'Typ',
|
||||
'tab' => 'settings',
|
||||
'options' => [
|
||||
0 => 'tekst',
|
||||
1 => 'kolor',
|
||||
2 => 'wzor',
|
||||
],
|
||||
]),
|
||||
FormField::number('o', [
|
||||
'label' => 'Kolejnosc',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
];
|
||||
|
||||
$tabs = [
|
||||
new FormTab('content', 'Tresc', 'fa-file'),
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/shop_attribute/save/' . ($isNew ? '' : ('id=' . $id));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/shop_attribute/list/'),
|
||||
FormAction::cancel('/admin/shop_attribute/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'shop-attribute-edit',
|
||||
$isNew ? 'Nowa cecha' : 'Edycja cechy',
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/shop_attribute/list/',
|
||||
true,
|
||||
['id' => $id],
|
||||
$languages
|
||||
);
|
||||
}
|
||||
}
|
||||
164
autoload/admin/Controllers/ShopCategoryController.php
Normal file
164
autoload/admin/Controllers/ShopCategoryController.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Category\CategoryRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
|
||||
class ShopCategoryController
|
||||
{
|
||||
private CategoryRepository $repository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
|
||||
public function __construct(CategoryRepository $repository, LanguagesRepository $languagesRepository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view('shop-category/categories-list', [
|
||||
'categories' => $this->repository->subcategories(null),
|
||||
'level' => 0,
|
||||
'dlang' => $this->languagesRepository->defaultLanguage(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
return $this->view_list();
|
||||
}
|
||||
|
||||
public function category_edit(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view('shop-category/category-edit', [
|
||||
'category' => $this->repository->categoryDetails(\Shared\Helpers\Helpers::get('id')),
|
||||
'pid' => \Shared\Helpers\Helpers::get('pid'),
|
||||
'languages' => $this->languagesRepository->languagesList(),
|
||||
'sort_types' => $this->repository->sortTypes(),
|
||||
'dlang' => $this->languagesRepository->defaultLanguage(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
return $this->category_edit();
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania kategorii wystąpił błąd. Proszę spróbować ponownie.',
|
||||
];
|
||||
|
||||
$values = json_decode((string)\Shared\Helpers\Helpers::get('values'), true);
|
||||
if (is_array($values)) {
|
||||
$savedId = $this->repository->save($values);
|
||||
if (!empty($savedId)) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Kategoria została zapisana.',
|
||||
'id' => (int)$savedId,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function category_delete(): void
|
||||
{
|
||||
if ($this->repository->categoryDelete(\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::set_message('Kategoria została usunięta.');
|
||||
} else {
|
||||
\Shared\Helpers\Helpers::alert('Podczas usuwania kategorii wystąpił błąd. Aby usunąć kategorię nie może ona posiadać przypiętych podkategorii.');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_category/view_list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
$this->category_delete();
|
||||
}
|
||||
|
||||
public function category_products(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view('shop-category/category-products', [
|
||||
'category_id' => \Shared\Helpers\Helpers::get('id'),
|
||||
'products' => $this->repository->categoryProducts((int)\Shared\Helpers\Helpers::get('id')),
|
||||
]);
|
||||
}
|
||||
|
||||
public function products(): string
|
||||
{
|
||||
return $this->category_products();
|
||||
}
|
||||
|
||||
public function category_url_browser(): void
|
||||
{
|
||||
echo \Shared\Tpl\Tpl::view('shop-category/category-browse-list', [
|
||||
'categories' => $this->repository->subcategories(null),
|
||||
'level' => 0,
|
||||
'dlang' => $this->languagesRepository->defaultLanguage(),
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function save_categories_order(): void
|
||||
{
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania kolejności kategorii wystąpił błąd. Proszę spróbować ponownie.',
|
||||
];
|
||||
|
||||
if ( $this->repository->saveCategoriesOrder( \Shared\Helpers\Helpers::get( 'categories' ) ) ) {
|
||||
$response = [ 'status' => 'ok' ];
|
||||
}
|
||||
|
||||
echo json_encode( $response );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function save_products_order(): void
|
||||
{
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania kolejności wyświetlania produktów wystąpił błąd. Proszę spróbować ponownie.',
|
||||
];
|
||||
|
||||
if ( $this->repository->saveProductOrder( \Shared\Helpers\Helpers::get( 'category_id' ), \Shared\Helpers\Helpers::get( 'products' ) ) ) {
|
||||
$response = [ 'status' => 'ok' ];
|
||||
}
|
||||
|
||||
echo json_encode( $response );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function cookie_categories(): void
|
||||
{
|
||||
$categoryId = (string) \Shared\Helpers\Helpers::get( 'category_id' );
|
||||
if ( $categoryId === '' ) {
|
||||
echo json_encode( [ 'status' => 'error' ] );
|
||||
exit;
|
||||
}
|
||||
|
||||
$array = [];
|
||||
if ( isset( $_COOKIE['cookie_categories'] ) ) {
|
||||
$tmp = @unserialize( (string) $_COOKIE['cookie_categories'] );
|
||||
if ( is_array( $tmp ) ) {
|
||||
$array = $tmp;
|
||||
}
|
||||
}
|
||||
|
||||
$array[$categoryId] = isset( $array[$categoryId] ) && (int) $array[$categoryId] === 1 ? 0 : 1;
|
||||
|
||||
setcookie( 'cookie_categories', serialize( $array ), time() + 3600 * 24 * 365, '/' );
|
||||
|
||||
echo json_encode( [ 'status' => 'ok' ] );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
222
autoload/admin/Controllers/ShopClientsController.php
Normal file
222
autoload/admin/Controllers/ShopClientsController.php
Normal file
@@ -0,0 +1,222 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Client\ClientRepository;
|
||||
use admin\ViewModels\Common\PaginatedTableViewModel;
|
||||
|
||||
class ShopClientsController
|
||||
{
|
||||
private ClientRepository $repository;
|
||||
|
||||
public function __construct(ClientRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = [
|
||||
'client_name',
|
||||
'client_surname',
|
||||
'client_email',
|
||||
'client_phone',
|
||||
'client_city',
|
||||
'total_orders',
|
||||
'total_spent',
|
||||
'client_type',
|
||||
];
|
||||
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Imie',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'surname',
|
||||
'label' => 'Nazwisko',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'email',
|
||||
'label' => 'E-mail',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'client_type',
|
||||
'label' => 'Typ klienta',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- typ klienta -',
|
||||
'registered' => 'Zarejestrowany',
|
||||
'guest' => 'Gosc',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'client_surname'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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) {
|
||||
$name = trim((string)($item['client_name'] ?? ''));
|
||||
$surname = trim((string)($item['client_surname'] ?? ''));
|
||||
$email = trim((string)($item['client_email'] ?? ''));
|
||||
$params = [
|
||||
'name' => $name,
|
||||
'surname' => $surname,
|
||||
'email' => $email,
|
||||
];
|
||||
$detailsUrl = '/admin/shop_clients/details/?' . http_build_query($params);
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'client_type' => ((int)($item['is_registered'] ?? 0) === 1) ? 'Zarejestrowany' : 'Gosc',
|
||||
'full_name' => htmlspecialchars($surname, ENT_QUOTES, 'UTF-8') . ' ' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8'),
|
||||
'client_email' => $email,
|
||||
'client_phone' => (string)($item['client_phone'] ?? ''),
|
||||
'client_city' => (string)($item['client_city'] ?? ''),
|
||||
'total_spent' => number_format((float)($item['total_spent'] ?? 0), 2, '.', ' ') . ' zl',
|
||||
'total_orders' => '<a href="' . htmlspecialchars($detailsUrl, ENT_QUOTES, 'UTF-8') . '">' . (int)($item['total_orders'] ?? 0) . '</a>',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Zobacz zamowienia',
|
||||
'url' => $detailsUrl,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'client_type', 'sort_key' => 'client_type', 'label' => 'Typ klienta', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'full_name', 'label' => 'Nazwisko, imie', 'sortable' => false, 'raw' => true],
|
||||
['key' => 'client_email', 'sort_key' => 'client_email', 'label' => 'Email', 'sortable' => true],
|
||||
['key' => 'client_phone', 'sort_key' => 'client_phone', 'label' => 'Telefon', 'sortable' => true],
|
||||
['key' => 'client_city', 'sort_key' => 'client_city', 'label' => 'Miasto', 'sortable' => true],
|
||||
['key' => 'total_spent', 'sort_key' => 'total_spent', 'label' => 'Wartosc zamowien', 'class' => 'text-right', 'sortable' => true],
|
||||
['key' => 'total_orders', 'sort_key' => 'total_orders', 'label' => 'Ilosc zamowien', '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/shop_clients/list/',
|
||||
'Brak danych w tabeli.'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-clients/view-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function details(): string
|
||||
{
|
||||
$name = (string)\Shared\Helpers\Helpers::get('name');
|
||||
$surname = (string)\Shared\Helpers\Helpers::get('surname');
|
||||
$email = (string)\Shared\Helpers\Helpers::get('email');
|
||||
|
||||
$ordersInfo = $this->repository->ordersForClient($name, $surname, $email);
|
||||
$totals = $this->repository->totalsForClient($name, $surname, $email);
|
||||
|
||||
$rows = [];
|
||||
$lp = 1;
|
||||
foreach ($ordersInfo as $order) {
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'date_order' => (string)($order['date_order'] ?? ''),
|
||||
'summary' => number_format((float)($order['summary'] ?? 0), 2, '.', ' ') . ' zl',
|
||||
'payment_method' => (string)($order['payment_method'] ?? ''),
|
||||
'transport' => (string)($order['transport'] ?? ''),
|
||||
'message' => (string)($order['message'] ?? ''),
|
||||
'_actions' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$ordersTable = new PaginatedTableViewModel(
|
||||
[
|
||||
['key' => 'lp', 'label' => 'Lp.', 'class' => 'text-center', 'sortable' => false],
|
||||
['key' => 'date_order', 'label' => 'Data zamowienia', 'class' => 'text-center', 'sortable' => false],
|
||||
['key' => 'summary', 'label' => 'Wartosc', 'class' => 'text-right', 'sortable' => false],
|
||||
['key' => 'payment_method', 'label' => 'Typ platnosci', 'sortable' => false],
|
||||
['key' => 'transport', 'label' => 'Rodzaj transportu', 'sortable' => false],
|
||||
['key' => 'message', 'label' => 'Wiadomosc', 'sortable' => false],
|
||||
],
|
||||
$rows,
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'page' => 1,
|
||||
'per_page' => max(1, count($rows)),
|
||||
'total' => count($rows),
|
||||
'total_pages' => 1,
|
||||
],
|
||||
[],
|
||||
[count($rows) > 0 ? count($rows) : 1],
|
||||
[],
|
||||
'/admin/shop_clients/details/?' . http_build_query([
|
||||
'name' => $name,
|
||||
'surname' => $surname,
|
||||
'email' => $email,
|
||||
]),
|
||||
'Brak zamowien klienta.'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-clients/clients-details', [
|
||||
'name' => $name,
|
||||
'surname' => $surname,
|
||||
'email' => $email,
|
||||
'total_spent' => $totals['total_spent'],
|
||||
'ordersTable' => $ordersTable,
|
||||
'total_orders' => $totals['total_orders'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function clients_details(): string
|
||||
{
|
||||
return $this->details();
|
||||
}
|
||||
}
|
||||
353
autoload/admin/Controllers/ShopCouponController.php
Normal file
353
autoload/admin/Controllers/ShopCouponController.php
Normal file
@@ -0,0 +1,353 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Coupon\CouponRepository;
|
||||
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;
|
||||
|
||||
class ShopCouponController
|
||||
{
|
||||
private CouponRepository $repository;
|
||||
|
||||
public function __construct(CouponRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'status', 'used_count', 'name', 'type', 'amount', 'one_time', 'send', 'used', 'date_used'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Aktywny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- aktywny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'used',
|
||||
'label' => 'Uzyty',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- uzyty -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'send',
|
||||
'label' => 'Wyslany',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- wyslany -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'name'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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 = (int)($item['id'] ?? 0);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
$used = (int)($item['used'] ?? 0);
|
||||
$send = (int)($item['send'] ?? 0);
|
||||
$oneTime = (int)($item['one_time'] ?? 0);
|
||||
$type = (int)($item['type'] ?? 0);
|
||||
$amount = (string)($item['amount'] ?? '');
|
||||
$dateUsed = trim((string)($item['date_used'] ?? ''));
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'used_count' => (int)($item['used_count'] ?? 0),
|
||||
'name' => '<a href="/admin/shop_coupon/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'type' => htmlspecialchars((string)($type === 1 ? 'Rabat procentowy na koszyk' : '-'), ENT_QUOTES, 'UTF-8'),
|
||||
'amount' => $type === 1 && $amount !== '' ? htmlspecialchars($amount, ENT_QUOTES, 'UTF-8') . '%' : '-',
|
||||
'one_time' => $oneTime === 1 ? 'tak' : 'nie',
|
||||
'send' => $send === 1 ? 'tak' : 'nie',
|
||||
'used' => $used === 1 ? 'tak' : 'nie',
|
||||
'date_used' => $dateUsed !== '' ? htmlspecialchars($dateUsed, ENT_QUOTES, 'UTF-8') : '-',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/shop_coupon/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/shop_coupon/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrany kupon?',
|
||||
'confirm_ok' => 'Usun',
|
||||
'confirm_cancel' => 'Anuluj',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'used_count', 'sort_key' => 'used_count', 'label' => 'Uzyto X razy', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'type', 'sort_key' => 'type', 'label' => 'Typ kuponu', 'sortable' => true],
|
||||
['key' => 'amount', 'sort_key' => 'amount', 'label' => 'Wartosc', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'one_time', 'sort_key' => 'one_time', 'label' => 'Kupon jednorazowy', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'send', 'sort_key' => 'send', 'label' => 'Wyslany', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'used', 'sort_key' => 'used', 'label' => 'Uzyty', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'date_used', 'sort_key' => 'date_used', 'label' => 'Data uzycia', '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/shop_coupon/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/shop_coupon/edit/',
|
||||
'Dodaj kupon'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-coupon/coupons-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$coupon = $this->repository->find((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
$categories = $this->repository->categoriesTree(null);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-coupon/coupon-edit-new', [
|
||||
'form' => $this->buildFormViewModel($coupon, $categories),
|
||||
]);
|
||||
}
|
||||
|
||||
public function coupon_edit(): string
|
||||
{
|
||||
return $this->edit();
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania kuponu wystapil blad. Prosze sprobowac ponownie.',
|
||||
];
|
||||
|
||||
if (is_array($values)) {
|
||||
$id = $this->repository->save($values);
|
||||
if (!empty($id)) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Kupon zostal zapisany.',
|
||||
'id' => (int)$id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$payload = $_POST;
|
||||
if (empty($payload['id'])) {
|
||||
$routeId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
if ($routeId > 0) {
|
||||
$payload['id'] = $routeId;
|
||||
}
|
||||
}
|
||||
|
||||
$id = $this->repository->save($payload);
|
||||
if (!empty($id)) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => (int)$id,
|
||||
'message' => 'Kupon zostal zapisany.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania kuponu wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function coupon_save(): void
|
||||
{
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->delete((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Kupon zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_coupon/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function coupon_delete(): void
|
||||
{
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $coupon, array $categories): FormEditViewModel
|
||||
{
|
||||
$id = (int)($coupon['id'] ?? 0);
|
||||
$isNew = $id <= 0;
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'name' => (string)($coupon['name'] ?? ''),
|
||||
'send' => (int)($coupon['send'] ?? 0),
|
||||
'status' => (int)($coupon['status'] ?? 1),
|
||||
'used' => (int)($coupon['used'] ?? 0),
|
||||
'type' => (int)($coupon['type'] ?? 1),
|
||||
'amount' => (string)($coupon['amount'] ?? ''),
|
||||
'one_time' => (int)($coupon['one_time'] ?? 1),
|
||||
'include_discounted_product' => (int)($coupon['include_discounted_product'] ?? 0),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $id),
|
||||
FormField::text('name', [
|
||||
'label' => 'Nazwa',
|
||||
'tab' => 'settings',
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::switch('send', [
|
||||
'label' => 'Wyslany',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
'tab' => 'settings',
|
||||
'value' => true,
|
||||
]),
|
||||
FormField::switch('used', [
|
||||
'label' => 'Uzyty',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::select('type', [
|
||||
'label' => 'Typ kuponu',
|
||||
'tab' => 'settings',
|
||||
'options' => [
|
||||
1 => 'Rabat procentowy na koszyk',
|
||||
],
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::text('amount', [
|
||||
'label' => 'Wartosc',
|
||||
'tab' => 'settings',
|
||||
'attributes' => ['class' => 'number-format'],
|
||||
]),
|
||||
FormField::switch('one_time', [
|
||||
'label' => 'Kupon jednorazowy',
|
||||
'tab' => 'settings',
|
||||
'value' => true,
|
||||
]),
|
||||
FormField::switch('include_discounted_product', [
|
||||
'label' => 'Dotyczy rowniez produktow przecenionych',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::custom('coupon_categories', \Shared\Tpl\Tpl::view('shop-coupon/coupon-categories-selector', [
|
||||
'label' => 'Ogranicz promocje do wybranych kategorii',
|
||||
'inputName' => 'categories[]',
|
||||
'categories' => $categories,
|
||||
'selectedIds' => is_array($coupon['categories'] ?? null) ? $coupon['categories'] : [],
|
||||
]), [
|
||||
'tab' => 'categories',
|
||||
]),
|
||||
];
|
||||
|
||||
$tabs = [
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
new FormTab('categories', 'Kategorie', 'fa-folder-open'),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/shop_coupon/save/' . ($isNew ? '' : ('id=' . $id));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/shop_coupon/list/'),
|
||||
FormAction::cancel('/admin/shop_coupon/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'shop-coupon-edit',
|
||||
$isNew ? 'Nowy kupon' : ('Edycja kuponu: ' . (string)($coupon['name'] ?? '')),
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/shop_coupon/list/',
|
||||
true,
|
||||
['id' => $id]
|
||||
);
|
||||
}
|
||||
}
|
||||
364
autoload/admin/Controllers/ShopOrderController.php
Normal file
364
autoload/admin/Controllers/ShopOrderController.php
Normal file
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Order\OrderAdminService;
|
||||
use Domain\Product\ProductRepository;
|
||||
use admin\ViewModels\Common\PaginatedTableViewModel;
|
||||
|
||||
class ShopOrderController
|
||||
{
|
||||
private OrderAdminService $service;
|
||||
private $productRepo;
|
||||
|
||||
public function __construct(OrderAdminService $service, ProductRepository $productRepo = null)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->productRepo = $productRepo;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
return $this->view_list();
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
$sortableColumns = [
|
||||
'number',
|
||||
'date_order',
|
||||
'status',
|
||||
'summary',
|
||||
'client',
|
||||
'order_email',
|
||||
'client_phone',
|
||||
'transport',
|
||||
'payment_method',
|
||||
'total_orders',
|
||||
'paid',
|
||||
];
|
||||
|
||||
$statusOptions = ['' => '- status -'];
|
||||
foreach ($this->service->statuses() as $statusId => $statusName) {
|
||||
$statusOptions[(string)$statusId] = (string)$statusName;
|
||||
}
|
||||
|
||||
$filterDefinitions = [
|
||||
['key' => 'number', 'label' => 'Nr zamówienia', 'type' => 'text'],
|
||||
['key' => 'date_from', 'label' => 'Data od', 'type' => 'date'],
|
||||
['key' => 'date_to', 'label' => 'Data do', 'type' => 'date'],
|
||||
['key' => 'status', 'label' => 'Status', 'type' => 'select', 'options' => $statusOptions],
|
||||
['key' => 'client', 'label' => 'Klient', 'type' => 'text'],
|
||||
['key' => 'address', 'label' => 'Adres', 'type' => 'text'],
|
||||
['key' => 'order_email', 'label' => 'Email', 'type' => 'text'],
|
||||
['key' => 'client_phone', 'label' => 'Telefon', 'type' => 'text'],
|
||||
['key' => 'transport', 'label' => 'Dostawa', 'type' => 'text'],
|
||||
['key' => 'payment_method', 'label' => 'Płatność', 'type' => 'text'],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'date_order'
|
||||
);
|
||||
|
||||
$result = $this->service->listForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$listRequest['sortDir'],
|
||||
$listRequest['page'],
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$statusesMap = $this->service->statuses();
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
|
||||
foreach ($result['items'] as $item) {
|
||||
$orderId = (int)($item['id'] ?? 0);
|
||||
$orderNumber = (string)($item['number'] ?? '');
|
||||
$statusId = (int)($item['status'] ?? 0);
|
||||
$statusLabel = (string)($statusesMap[$statusId] ?? ('Status #' . $statusId));
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'date_order' => $this->formatDateTime((string)($item['date_order'] ?? '')),
|
||||
'number' => '<a href="/admin/shop_order/order_details/order_id=' . $orderId . '">' . htmlspecialchars($orderNumber, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'paid' => ((int)($item['paid'] ?? 0) === 1)
|
||||
? '<i class="fa fa-check text-success"></i>'
|
||||
: '<i class="fa fa-times text-dark"></i>',
|
||||
'status' => htmlspecialchars($statusLabel, ENT_QUOTES, 'UTF-8'),
|
||||
'summary' => number_format((float)($item['summary'] ?? 0), 2, '.', ' ') . ' zł',
|
||||
'client' => htmlspecialchars((string)($item['client'] ?? ''), ENT_QUOTES, 'UTF-8') . ' | zamówienia: <strong>' . (int)($item['total_orders'] ?? 0) . '</strong>',
|
||||
'address' => (string)($item['address'] ?? ''),
|
||||
'order_email' => (string)($item['order_email'] ?? ''),
|
||||
'client_phone' => (string)($item['client_phone'] ?? ''),
|
||||
'transport' => (string)($item['transport'] ?? ''),
|
||||
'payment_method' => (string)($item['payment_method'] ?? ''),
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Szczegóły',
|
||||
'url' => '/admin/shop_order/order_details/order_id=' . $orderId,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usuń',
|
||||
'url' => '/admin/shop_order/order_delete/id=' . $orderId,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunąć wybrane zamówienie?',
|
||||
'confirm_ok' => 'Usuń',
|
||||
'confirm_cancel' => 'Anuluj',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'date_order', 'sort_key' => 'date_order', 'label' => 'Data dodania', 'class' => 'text-center', 'sortable' => true],
|
||||
['key' => 'number', 'sort_key' => 'number', 'label' => 'Nr zamówienia', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'paid', 'sort_key' => 'paid', 'label' => '', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Status', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'summary', 'sort_key' => 'summary', 'label' => 'Wartość', 'class' => 'text-right align-middle', 'sortable' => true],
|
||||
['key' => 'client', 'sort_key' => 'client', 'label' => 'Klient', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'address', 'label' => 'Adres', 'sortable' => false],
|
||||
['key' => 'order_email', 'sort_key' => 'order_email', 'label' => 'Email', 'sortable' => true],
|
||||
['key' => 'client_phone', 'sort_key' => 'client_phone', 'label' => 'Telefon', 'sortable' => true],
|
||||
['key' => 'transport', 'sort_key' => 'transport', 'label' => 'Dostawa', 'sortable' => true],
|
||||
['key' => 'payment_method', 'sort_key' => 'payment_method', 'label' => 'Płatność', 'sortable' => true],
|
||||
],
|
||||
$rows,
|
||||
$listRequest['viewFilters'],
|
||||
[
|
||||
'column' => $listRequest['sortColumn'],
|
||||
'dir' => $listRequest['sortDir'],
|
||||
],
|
||||
[
|
||||
'page' => $listRequest['page'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
'total' => $total,
|
||||
'total_pages' => $totalPages,
|
||||
],
|
||||
array_merge($listRequest['queryFilters'], [
|
||||
'sort' => $listRequest['sortColumn'],
|
||||
'dir' => $listRequest['sortDir'],
|
||||
'per_page' => $listRequest['perPage'],
|
||||
]),
|
||||
$listRequest['perPageOptions'],
|
||||
$sortableColumns,
|
||||
'/admin/shop_order/list/',
|
||||
'Brak danych w tabeli.'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-order/orders-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function details(): string
|
||||
{
|
||||
return $this->order_details();
|
||||
}
|
||||
|
||||
public function order_details(): string
|
||||
{
|
||||
$orderId = (int)\Shared\Helpers\Helpers::get('order_id');
|
||||
$order = $this->service->details($orderId);
|
||||
|
||||
$coupon = null;
|
||||
if (!empty($order) && !empty($order['coupon_id'])) {
|
||||
$coupon = ( new \Domain\Coupon\CouponRepository( $GLOBALS['mdb'] ) )->find((int)$order['coupon_id']);
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-order/order-details', [
|
||||
'order' => $order,
|
||||
'coupon' => $coupon,
|
||||
'order_statuses' => $this->service->statuses(),
|
||||
'next_order_id' => $this->service->nextOrderId($orderId),
|
||||
'prev_order_id' => $this->service->prevOrderId($orderId),
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
return $this->order_edit();
|
||||
}
|
||||
|
||||
public function order_edit(): string
|
||||
{
|
||||
$orderId = (int)\Shared\Helpers\Helpers::get('order_id');
|
||||
$transports = ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->allActive();
|
||||
|
||||
// Dane transportów do JS (id, cost, delivery_free)
|
||||
$transportsJson = [];
|
||||
if (is_array($transports)) {
|
||||
foreach ($transports as $t) {
|
||||
$transportsJson[] = [
|
||||
'id' => (int)$t['id'],
|
||||
'cost' => (float)$t['cost'],
|
||||
'delivery_free' => (int)($t['delivery_free'] ?? 0),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-order/order-edit', [
|
||||
'order' => $this->service->details($orderId),
|
||||
'order_statuses' => $this->service->statuses(),
|
||||
'transport' => $transports,
|
||||
'payment_methods' => ( new \Domain\PaymentMethod\PaymentMethodRepository( $GLOBALS['mdb'] ) )->allActive(),
|
||||
'free_delivery' => $this->service->getFreeDeliveryThreshold(),
|
||||
'transports_json' => json_encode($transportsJson),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$this->order_save();
|
||||
}
|
||||
|
||||
public function order_save(): void
|
||||
{
|
||||
$orderId = (int)\Shared\Helpers\Helpers::get('order_id');
|
||||
|
||||
// Zapisz produkty PRZED zapisem zamówienia (bo saveOrderByAdmin przelicza summary)
|
||||
$productsData = \Shared\Helpers\Helpers::get('products');
|
||||
if (is_array($productsData)) {
|
||||
$this->service->saveOrderProducts($orderId, $productsData);
|
||||
}
|
||||
|
||||
$saved = $this->service->saveOrderByAdmin([
|
||||
'order_id' => $orderId,
|
||||
'client_name' => (string)\Shared\Helpers\Helpers::get('client_name'),
|
||||
'client_surname' => (string)\Shared\Helpers\Helpers::get('client_surname'),
|
||||
'client_street' => (string)\Shared\Helpers\Helpers::get('client_street'),
|
||||
'client_postal_code' => (string)\Shared\Helpers\Helpers::get('client_postal_code'),
|
||||
'client_city' => (string)\Shared\Helpers\Helpers::get('client_city'),
|
||||
'client_email' => (string)\Shared\Helpers\Helpers::get('client_email'),
|
||||
'firm_name' => (string)\Shared\Helpers\Helpers::get('firm_name'),
|
||||
'firm_street' => (string)\Shared\Helpers\Helpers::get('firm_street'),
|
||||
'firm_postal_code' => (string)\Shared\Helpers\Helpers::get('firm_postal_code'),
|
||||
'firm_city' => (string)\Shared\Helpers\Helpers::get('firm_city'),
|
||||
'firm_nip' => (string)\Shared\Helpers\Helpers::get('firm_nip'),
|
||||
'transport_id' => (int)\Shared\Helpers\Helpers::get('transport_id'),
|
||||
'inpost_paczkomat' => (string)\Shared\Helpers\Helpers::get('inpost_paczkomat'),
|
||||
'payment_method_id' => (int)\Shared\Helpers\Helpers::get('payment_method_id'),
|
||||
]);
|
||||
|
||||
if ($saved) {
|
||||
\Shared\Helpers\Helpers::alert('Zamówienie zostało zapisane.');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_order/order_details/order_id=' . $orderId);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function search_products_ajax(): void
|
||||
{
|
||||
$query = trim((string)\Shared\Helpers\Helpers::get('query'));
|
||||
$langId = trim((string)\Shared\Helpers\Helpers::get('lang_id'));
|
||||
if ($langId === '') {
|
||||
$langId = isset($_SESSION['lang_id']) ? (string)$_SESSION['lang_id'] : 'pl';
|
||||
}
|
||||
|
||||
$results = $this->service->searchProducts($query, $langId);
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode(['status' => 'ok', 'products' => $results]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function notes_save(): void
|
||||
{
|
||||
$this->service->saveNotes((int)\Shared\Helpers\Helpers::get('order_id'), (string)\Shared\Helpers\Helpers::get('notes'));
|
||||
}
|
||||
|
||||
public function order_status_change(): void
|
||||
{
|
||||
$response = $this->service->changeStatus(
|
||||
(int)\Shared\Helpers\Helpers::get('order_id'),
|
||||
(int)\Shared\Helpers\Helpers::get('status'),
|
||||
(string)\Shared\Helpers\Helpers::get('email') === 'true'
|
||||
);
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function order_resend_confirmation_email(): void
|
||||
{
|
||||
$response = $this->service->resendConfirmationEmail((int)\Shared\Helpers\Helpers::get('order_id'));
|
||||
|
||||
echo json_encode(['result' => $response]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function set_order_as_unpaid(): void
|
||||
{
|
||||
$orderId = (int)\Shared\Helpers\Helpers::get('order_id');
|
||||
$this->service->setOrderAsUnpaid($orderId);
|
||||
|
||||
header('Location: /admin/shop_order/order_details/order_id=' . $orderId);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function set_order_as_paid(): void
|
||||
{
|
||||
$orderId = (int)\Shared\Helpers\Helpers::get('order_id');
|
||||
$this->service->setOrderAsPaid($orderId, (int)\Shared\Helpers\Helpers::get('send_mail') === 1);
|
||||
|
||||
header('Location: /admin/shop_order/order_details/order_id=' . $orderId);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function send_order_to_apilo(): void
|
||||
{
|
||||
$orderId = (int)\Shared\Helpers\Helpers::get('order_id');
|
||||
|
||||
if ($this->service->sendOrderToApilo($orderId)) {
|
||||
\Shared\Helpers\Helpers::alert('Zamówienie zostanie wysłane ponownie do apilo.com');
|
||||
} else {
|
||||
\Shared\Helpers\Helpers::alert('Wystąpił błąd podczas wysyłania zamówienia do apilo.com');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_order/order_details/order_id=' . $orderId);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function toggle_trustmate_send(): void
|
||||
{
|
||||
echo json_encode($this->service->toggleTrustmateSend((int)\Shared\Helpers\Helpers::get('order_id')));
|
||||
exit;
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
$this->order_delete();
|
||||
}
|
||||
|
||||
public function order_delete(): void
|
||||
{
|
||||
if ($this->service->deleteOrder((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Zamówienie zostało usunięte');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_order/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
private function formatDateTime(string $value): string
|
||||
{
|
||||
if ($value === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$ts = strtotime($value);
|
||||
if ($ts === false) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return date('Y-m-d H:i', $ts);
|
||||
}
|
||||
}
|
||||
294
autoload/admin/Controllers/ShopPaymentMethodController.php
Normal file
294
autoload/admin/Controllers/ShopPaymentMethodController.php
Normal file
@@ -0,0 +1,294 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\PaymentMethod\PaymentMethodRepository;
|
||||
use Domain\Integrations\IntegrationsRepository;
|
||||
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;
|
||||
|
||||
class ShopPaymentMethodController
|
||||
{
|
||||
private PaymentMethodRepository $repository;
|
||||
|
||||
public function __construct(PaymentMethodRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'name', 'status', 'apilo_payment_type_id'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'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)\Shared\Helpers\Helpers::get('sort')) === '') {
|
||||
$sortDir = 'ASC';
|
||||
}
|
||||
|
||||
$result = $this->repository->listForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$sortDir,
|
||||
$listRequest['page'],
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$apiloPaymentTypes = $this->getApiloPaymentTypes();
|
||||
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)($item['id'] ?? 0);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
$apiloPaymentTypeId = $item['apilo_payment_type_id'] ?? null;
|
||||
|
||||
$apiloLabel = '-';
|
||||
if ($apiloPaymentTypeId !== null) {
|
||||
$apiloKey = (string)$apiloPaymentTypeId;
|
||||
if (isset($apiloPaymentTypes[$apiloKey])) {
|
||||
$apiloLabel = $apiloPaymentTypes[$apiloKey];
|
||||
}
|
||||
}
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'name' => '<a href="/admin/shop_payment_method/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'apilo_payment_type' => htmlspecialchars((string)$apiloLabel, ENT_QUOTES, 'UTF-8'),
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/shop_payment_method/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'apilo_payment_type', 'sort_key' => 'apilo_payment_type_id', 'label' => 'Typ platnosci Apilo', 'class' => 'text-center', 'sortable' => 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/shop_payment_method/list/',
|
||||
'Brak danych w tabeli.'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-payment-method/payment-methods-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$paymentMethod = $this->repository->find((int)\Shared\Helpers\Helpers::get('id'));
|
||||
if ($paymentMethod === null) {
|
||||
\Shared\Helpers\Helpers::alert('Metoda platnosci nie zostala znaleziona.');
|
||||
header('Location: /admin/shop_payment_method/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-payment-method/payment-method-edit', [
|
||||
'form' => $this->buildFormViewModel($paymentMethod, $this->getApiloPaymentTypes()),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$payload = $_POST;
|
||||
$paymentMethodId = isset($payload['id']) && $payload['id'] !== ''
|
||||
? (int)$payload['id']
|
||||
: (int)\Shared\Helpers\Helpers::get('id');
|
||||
|
||||
$id = $this->repository->save($paymentMethodId, $payload);
|
||||
if ($id !== null) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => (int)$id,
|
||||
'message' => 'Metoda platnosci zostala zapisana.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania metody platnosci wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $paymentMethod, array $apiloPaymentTypes): FormEditViewModel
|
||||
{
|
||||
$id = (int)($paymentMethod['id'] ?? 0);
|
||||
$name = (string)($paymentMethod['name'] ?? '');
|
||||
|
||||
$apiloOptions = ['' => '--- wybierz typ platnosci apilo.com ---'];
|
||||
foreach ($apiloPaymentTypes as $apiloId => $apiloName) {
|
||||
$apiloOptions[(string)$apiloId] = $apiloName;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'description' => (string)($paymentMethod['description'] ?? ''),
|
||||
'status' => (int)($paymentMethod['status'] ?? 0),
|
||||
'apilo_payment_type_id' => $paymentMethod['apilo_payment_type_id'] ?? '',
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $id),
|
||||
FormField::custom(
|
||||
'name_preview',
|
||||
\Shared\Html\Html::input([
|
||||
'label' => 'Nazwa',
|
||||
'name' => 'name_preview',
|
||||
'id' => 'name_preview',
|
||||
'value' => $name,
|
||||
'type' => 'text',
|
||||
'readonly' => true,
|
||||
]),
|
||||
['tab' => 'settings']
|
||||
),
|
||||
FormField::textarea('description', [
|
||||
'label' => 'Opis',
|
||||
'tab' => 'settings',
|
||||
'rows' => 5,
|
||||
]),
|
||||
FormField::select('apilo_payment_type_id', [
|
||||
'label' => 'Typ platnosci Apilo',
|
||||
'tab' => 'settings',
|
||||
'options' => $apiloOptions,
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
];
|
||||
|
||||
$tabs = [
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/shop_payment_method/save/id=' . $id;
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/shop_payment_method/list/'),
|
||||
FormAction::cancel('/admin/shop_payment_method/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'shop-payment-method-edit',
|
||||
'Edycja metody platnosci: ' . $name,
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/shop_payment_method/list/',
|
||||
true,
|
||||
['id' => $id]
|
||||
);
|
||||
}
|
||||
|
||||
private function getApiloPaymentTypes(): array
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
$integrationsRepository = new IntegrationsRepository( $mdb );
|
||||
$rawSetting = $integrationsRepository -> getSetting( 'apilo', 'payment-types-list' );
|
||||
$raw = null;
|
||||
|
||||
if (is_array($rawSetting)) {
|
||||
$raw = $rawSetting;
|
||||
} elseif (is_string($rawSetting)) {
|
||||
$decoded = @unserialize($rawSetting);
|
||||
if (is_array($decoded)) {
|
||||
$raw = $decoded;
|
||||
} else {
|
||||
$decodedJson = json_decode($rawSetting, true);
|
||||
if (is_array($decodedJson)) {
|
||||
$raw = $decodedJson;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_array($raw)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (isset($raw['message']) && isset($raw['code'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (isset($raw['items']) && is_array($raw['items'])) {
|
||||
$raw = $raw['items'];
|
||||
} elseif (isset($raw['data']) && is_array($raw['data'])) {
|
||||
$raw = $raw['data'];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($raw as $key => $paymentType) {
|
||||
if (is_array($paymentType)) {
|
||||
if (isset($paymentType['id'], $paymentType['name'])) {
|
||||
$list[(string)$paymentType['id']] = (string)$paymentType['name'];
|
||||
continue;
|
||||
}
|
||||
} elseif (is_scalar($paymentType)) {
|
||||
if (is_int($key) || (is_string($key) && preg_match('/^-?\d+$/', $key) === 1)) {
|
||||
$list[(string)$key] = (string)$paymentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
379
autoload/admin/Controllers/ShopProducerController.php
Normal file
379
autoload/admin/Controllers/ShopProducerController.php
Normal file
@@ -0,0 +1,379 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Producer\ProducerRepository;
|
||||
use Domain\Languages\LanguagesRepository;
|
||||
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 ShopProducerController
|
||||
{
|
||||
private ProducerRepository $repository;
|
||||
private LanguagesRepository $languagesRepository;
|
||||
private FormRequestHandler $formHandler;
|
||||
|
||||
public function __construct(ProducerRepository $repository, LanguagesRepository $languagesRepository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->languagesRepository = $languagesRepository;
|
||||
$this->formHandler = new FormRequestHandler();
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'name', 'status'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Aktywny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- aktywny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'name'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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 = (int)($item['id'] ?? 0);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
$img = trim((string)($item['img'] ?? ''));
|
||||
|
||||
$imgHtml = '';
|
||||
if ($img !== '') {
|
||||
$imgHtml = '<img src="' . htmlspecialchars($img, ENT_QUOTES, 'UTF-8') . '" style="max-height:30px;" />';
|
||||
}
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'name' => '<a href="/admin/shop_producer/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'img' => $imgHtml,
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/shop_producer/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/shop_producer/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybranego producenta?',
|
||||
'confirm_ok' => 'Usun',
|
||||
'confirm_cancel' => 'Anuluj',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'img', 'label' => 'Logo', 'sortable' => false, 'raw' => true],
|
||||
['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/shop_producer/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/shop_producer/edit/',
|
||||
'Dodaj producenta'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-producer/producers-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$producer = $this->repository->find((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
$validationErrors = $_SESSION['form_errors'][$this->formId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->formId()]);
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-producer/producer-edit', [
|
||||
'form' => $this->buildFormViewModel($producer, $languages, $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function producer_edit(): string
|
||||
{
|
||||
return $this->edit();
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
// Legacy JSON (gridEdit)
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania producenta wystapil blad. Prosze sprobowac ponownie.',
|
||||
];
|
||||
|
||||
if (is_array($values)) {
|
||||
$langs = $this->languagesRepository->languagesList(true);
|
||||
|
||||
$id = $this->repository->save(
|
||||
(int)($values['id'] ?? 0),
|
||||
(string)($values['name'] ?? ''),
|
||||
$this->toSwitchValue($values['status'] ?? 0),
|
||||
$values['img'] ?? null,
|
||||
$values['description'] ?? [],
|
||||
$values['data'] ?? [],
|
||||
$values['meta_title'] ?? [],
|
||||
$langs
|
||||
);
|
||||
|
||||
if (!empty($id)) {
|
||||
\Shared\Helpers\Helpers::htacces();
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Producent zostal zapisany.',
|
||||
'id' => (int)$id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Nowy flow (form-edit)
|
||||
$producer = $this->repository->find((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
$languages = $this->languagesRepository->languagesList();
|
||||
$form = $this->buildFormViewModel($producer, $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'];
|
||||
$langs = $this->languagesRepository->languagesList(true);
|
||||
|
||||
$translations = $data['translations'] ?? [];
|
||||
$description = [];
|
||||
$metaData = [];
|
||||
$metaTitle = [];
|
||||
foreach ($translations as $langId => $fields) {
|
||||
$description[$langId] = $fields['description'] ?? null;
|
||||
$metaData[$langId] = $fields['data'] ?? null;
|
||||
$metaTitle[$langId] = $fields['meta_title'] ?? null;
|
||||
}
|
||||
|
||||
$savedId = $this->repository->save(
|
||||
(int)($data['id'] ?? 0),
|
||||
(string)($data['name'] ?? ''),
|
||||
$this->toSwitchValue($data['status'] ?? 0),
|
||||
$data['img'] ?? null,
|
||||
$description,
|
||||
$metaData,
|
||||
$metaTitle,
|
||||
$langs
|
||||
);
|
||||
|
||||
if ($savedId) {
|
||||
\Shared\Helpers\Helpers::htacces();
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => $savedId,
|
||||
'message' => 'Producent zostal zapisany.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania producenta wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function producer_save(): void
|
||||
{
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->delete((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::htacces();
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
\Shared\Helpers\Helpers::alert('Producent zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_producer/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function producer_delete(): void
|
||||
{
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $producer, array $languages, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$id = (int)($producer['id'] ?? 0);
|
||||
$isNew = $id <= 0;
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'name' => (string)($producer['name'] ?? ''),
|
||||
'status' => (int)($producer['status'] ?? 1),
|
||||
'img' => $producer['img'] ?? null,
|
||||
'languages' => is_array($producer['languages'] ?? null) ? $producer['languages'] : [],
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $id),
|
||||
FormField::text('name', [
|
||||
'label' => 'Nazwa',
|
||||
'required' => true,
|
||||
'tab' => 'general',
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
'tab' => 'general',
|
||||
'value' => true,
|
||||
]),
|
||||
FormField::image('img', [
|
||||
'label' => 'Logo',
|
||||
'tab' => 'general',
|
||||
]),
|
||||
FormField::langSection('translations', 'description', [
|
||||
FormField::editor('description', [
|
||||
'label' => 'Opis',
|
||||
'height' => 250,
|
||||
]),
|
||||
FormField::editor('data', [
|
||||
'label' => 'Dane producenta',
|
||||
'height' => 250,
|
||||
]),
|
||||
]),
|
||||
FormField::langSection('translations', 'seo', [
|
||||
FormField::text('meta_title', [
|
||||
'label' => 'Meta title',
|
||||
]),
|
||||
]),
|
||||
];
|
||||
|
||||
$tabs = [
|
||||
new FormTab('general', 'Ogolne', 'fa-file'),
|
||||
new FormTab('description', 'Opis', 'fa-file'),
|
||||
new FormTab('seo', 'SEO', 'fa-globe'),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/shop_producer/save/' . ($isNew ? '' : ('id=' . $id));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/shop_producer/list/'),
|
||||
FormAction::cancel('/admin/shop_producer/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->formId(),
|
||||
'Edycja producenta',
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/shop_producer/list/',
|
||||
true,
|
||||
[],
|
||||
$languages,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function formId(): string
|
||||
{
|
||||
return 'shop-producer-edit';
|
||||
}
|
||||
|
||||
private function toSwitchValue($value): int
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
return $value ? 1 : 0;
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return ((int)$value) === 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
if (is_string($value)) {
|
||||
$normalized = strtolower(trim($value));
|
||||
return in_array($normalized, ['1', 'on', 'true', 'yes'], true) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
1193
autoload/admin/Controllers/ShopProductController.php
Normal file
1193
autoload/admin/Controllers/ShopProductController.php
Normal file
File diff suppressed because it is too large
Load Diff
328
autoload/admin/Controllers/ShopProductSetsController.php
Normal file
328
autoload/admin/Controllers/ShopProductSetsController.php
Normal file
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\ProductSet\ProductSetRepository;
|
||||
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;
|
||||
|
||||
class ShopProductSetsController
|
||||
{
|
||||
private ProductSetRepository $repository;
|
||||
|
||||
public function __construct(ProductSetRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'name', 'status'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Aktywny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- aktywny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'name'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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 = (int)($item['id'] ?? 0);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'name' => '<a href="/admin/shop_product_sets/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/shop_product_sets/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/shop_product_sets/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrany komplet produktow?',
|
||||
'confirm_ok' => 'Usun',
|
||||
'confirm_cancel' => 'Anuluj',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['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/shop_product_sets/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/shop_product_sets/edit/',
|
||||
'Dodaj komplet produktow'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-product-sets/product-sets-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
return $this->list();
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$set = $this->repository->find((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
$products = $this->repository->allProductsMap();
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-product-sets/product-set-edit', [
|
||||
'form' => $this->buildFormViewModel($set, $products),
|
||||
]);
|
||||
}
|
||||
|
||||
public function set_edit(): string
|
||||
{
|
||||
return $this->edit();
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania kompletu produktow wystapil blad. Prosze sprobowac ponownie.',
|
||||
];
|
||||
|
||||
if (is_array($values)) {
|
||||
$productIds = $values['set_products_id'] ?? [];
|
||||
if (!is_array($productIds)) {
|
||||
$productIds = $productIds ? [$productIds] : [];
|
||||
}
|
||||
|
||||
$id = $this->repository->save(
|
||||
(int)($values['id'] ?? 0),
|
||||
(string)($values['name'] ?? ''),
|
||||
$this->toSwitchValue($values['status'] ?? 0),
|
||||
$productIds
|
||||
);
|
||||
|
||||
if (!empty($id)) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Komplet produktow zostal zapisany.',
|
||||
'id' => (int)$id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$payload = $_POST;
|
||||
if (empty($payload['id'])) {
|
||||
$routeId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
if ($routeId > 0) {
|
||||
$payload['id'] = $routeId;
|
||||
}
|
||||
}
|
||||
|
||||
$productIds = $payload['set_products_id'] ?? [];
|
||||
if (!is_array($productIds)) {
|
||||
$productIds = $productIds ? [$productIds] : [];
|
||||
}
|
||||
|
||||
$id = $this->repository->save(
|
||||
(int)($payload['id'] ?? 0),
|
||||
(string)($payload['name'] ?? ''),
|
||||
$this->toSwitchValue($payload['status'] ?? 0),
|
||||
$productIds
|
||||
);
|
||||
|
||||
if (!empty($id)) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => (int)$id,
|
||||
'message' => 'Komplet produktow zostal zapisany.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania kompletu produktow wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->delete((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Komplet produktow zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_product_sets/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function set_delete(): void
|
||||
{
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $set, array $products = []): FormEditViewModel
|
||||
{
|
||||
$id = (int)($set['id'] ?? 0);
|
||||
$isNew = $id <= 0;
|
||||
$selectedProducts = $set['products'] ?? [];
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'name' => (string)($set['name'] ?? ''),
|
||||
'status' => (int)($set['status'] ?? 1),
|
||||
];
|
||||
|
||||
$productsSelectHtml = $this->renderProductsSelect($products, $selectedProducts);
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $id),
|
||||
FormField::text('name', [
|
||||
'label' => 'Nazwa',
|
||||
'tab' => 'settings',
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
'tab' => 'settings',
|
||||
'value' => true,
|
||||
]),
|
||||
FormField::custom('set_products', $productsSelectHtml, [
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
];
|
||||
|
||||
$tabs = [
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/shop_product_sets/save/' . ($isNew ? '' : ('id=' . $id));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/shop_product_sets/list/'),
|
||||
FormAction::cancel('/admin/shop_product_sets/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'shop-product-set-edit',
|
||||
$isNew ? 'Nowy komplet produktow' : ('Edycja kompletu produktow: ' . (string)($set['name'] ?? '')),
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/shop_product_sets/list/',
|
||||
true,
|
||||
['id' => $id]
|
||||
);
|
||||
}
|
||||
|
||||
private function toSwitchValue($value): int
|
||||
{
|
||||
if (is_numeric($value)) {
|
||||
return ((int)$value) === 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
if (is_string($value)) {
|
||||
$normalized = strtolower(trim($value));
|
||||
return in_array($normalized, ['1', 'on', 'true', 'yes'], true) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function renderProductsSelect(array $products, array $selectedProducts): string
|
||||
{
|
||||
$html = '<div class="form-group row">';
|
||||
$html .= '<label class="col-lg-4 control-label">Produkty do kompletu:</label>';
|
||||
$html .= '<div class="col-lg-8">';
|
||||
$html .= '<select id="set_products_id" multiple name="set_products_id[]" placeholder="produkty do kompletu">';
|
||||
$html .= '<option value="">wybierz produkt...</option>';
|
||||
|
||||
foreach ($products as $productId => $productName) {
|
||||
$pid = (int)$productId;
|
||||
$selected = in_array($pid, $selectedProducts, true) ? ' selected' : '';
|
||||
$html .= '<option value="' . $pid . '"' . $selected . '>'
|
||||
. htmlspecialchars((string)$productName, ENT_QUOTES, 'UTF-8')
|
||||
. '</option>';
|
||||
}
|
||||
|
||||
$html .= '</select>';
|
||||
$html .= '</div>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
327
autoload/admin/Controllers/ShopPromotionController.php
Normal file
327
autoload/admin/Controllers/ShopPromotionController.php
Normal file
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Promotion\PromotionRepository;
|
||||
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;
|
||||
|
||||
class ShopPromotionController
|
||||
{
|
||||
private PromotionRepository $repository;
|
||||
|
||||
public function __construct(PromotionRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'name', 'status', 'condition_type', 'date_from', 'date_to'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'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)\Shared\Helpers\Helpers::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);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
$conditionType = (int)($item['condition_type'] ?? 0);
|
||||
$dateFrom = trim((string)($item['date_from'] ?? ''));
|
||||
$dateTo = trim((string)($item['date_to'] ?? ''));
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'name' => '<a href="/admin/shop_promotion/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'condition_type' => htmlspecialchars((string)(\Domain\Promotion\PromotionRepository::$condition_type[$conditionType] ?? '-'), ENT_QUOTES, 'UTF-8'),
|
||||
'date_from' => $dateFrom !== '' ? htmlspecialchars($dateFrom, ENT_QUOTES, 'UTF-8') : '-',
|
||||
'date_to' => $dateTo !== '' ? htmlspecialchars($dateTo, ENT_QUOTES, 'UTF-8') : '-',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/shop_promotion/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/shop_promotion/delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybrana promocje?',
|
||||
'confirm_ok' => 'Usun',
|
||||
'confirm_cancel' => 'Anuluj',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'condition_type', 'sort_key' => 'condition_type', 'label' => 'Typ kuponu', 'sortable' => true],
|
||||
['key' => 'date_from', 'sort_key' => 'date_from', 'label' => 'Data od', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'date_to', 'sort_key' => 'date_to', 'label' => 'Data do', '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/shop_promotion/list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/shop_promotion/edit/',
|
||||
'Dodaj promocje'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-promotion/promotions-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$promotion = $this->repository->find((int)\Shared\Helpers\Helpers::get('id')) ?: [];
|
||||
$categories = $this->repository->categoriesTree(null);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-promotion/promotion-edit', [
|
||||
'form' => $this->buildFormViewModel($promotion, $categories),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania promocji wystapil blad. Prosze sprobowac ponownie.',
|
||||
];
|
||||
|
||||
if (is_array($values)) {
|
||||
$id = $this->repository->save($values);
|
||||
if (!empty($id)) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Promocja zostala zapisana.',
|
||||
'id' => (int)$id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$payload = $_POST;
|
||||
if (empty($payload['id'])) {
|
||||
$routeId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
if ($routeId > 0) {
|
||||
$payload['id'] = $routeId;
|
||||
}
|
||||
}
|
||||
|
||||
$id = $this->repository->save($payload);
|
||||
if (!empty($id)) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => (int)$id,
|
||||
'message' => 'Promocja zostala zapisana.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania promocji wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->delete((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Promocja zostala usunieta.');
|
||||
}
|
||||
|
||||
header('Location: /admin/shop_promotion/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $promotion, array $categories): FormEditViewModel
|
||||
{
|
||||
$id = (int)($promotion['id'] ?? 0);
|
||||
$isNew = $id <= 0;
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'name' => (string)($promotion['name'] ?? ''),
|
||||
'status' => (int)($promotion['status'] ?? 1),
|
||||
'include_coupon' => (int)($promotion['include_coupon'] ?? 0),
|
||||
'include_product_promo' => (int)($promotion['include_product_promo'] ?? 0),
|
||||
'condition_type' => (int)($promotion['condition_type'] ?? 1),
|
||||
'discount_type' => (int)($promotion['discount_type'] ?? 1),
|
||||
'min_product_count' => $promotion['min_product_count'] ?? '',
|
||||
'price_cheapest_product' => $promotion['price_cheapest_product'] ?? '',
|
||||
'amount' => $promotion['amount'] ?? '',
|
||||
'date_from' => (string)($promotion['date_from'] ?? ''),
|
||||
'date_to' => (string)($promotion['date_to'] ?? ''),
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $id),
|
||||
FormField::text('name', [
|
||||
'label' => 'Nazwa',
|
||||
'tab' => 'settings',
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywna',
|
||||
'tab' => 'settings',
|
||||
'value' => true,
|
||||
]),
|
||||
FormField::switch('include_coupon', [
|
||||
'label' => 'Lacz z kuponami rabatowymi',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::switch('include_product_promo', [
|
||||
'label' => 'Uwzglednij produkty przecenione',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::select('condition_type', [
|
||||
'label' => 'Warunki promocji',
|
||||
'tab' => 'settings',
|
||||
'options' => \Domain\Promotion\PromotionRepository::$condition_type,
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::select('discount_type', [
|
||||
'label' => 'Typ rabatu',
|
||||
'tab' => 'settings',
|
||||
'options' => \Domain\Promotion\PromotionRepository::$discount_type,
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::text('min_product_count', [
|
||||
'label' => 'Min. ilosc produktow z danej kategorii',
|
||||
'tab' => 'settings',
|
||||
'attributes' => ['class' => 'int-format'],
|
||||
]),
|
||||
FormField::text('price_cheapest_product', [
|
||||
'label' => 'Cena najtanszego produktu',
|
||||
'tab' => 'settings',
|
||||
'attributes' => ['class' => 'number-format'],
|
||||
]),
|
||||
FormField::text('amount', [
|
||||
'label' => 'Wartosc',
|
||||
'tab' => 'settings',
|
||||
'attributes' => ['class' => 'number-format'],
|
||||
]),
|
||||
FormField::date('date_from', [
|
||||
'label' => 'Data od',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::date('date_to', [
|
||||
'label' => 'Data do',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::custom('categories_group_1', \Shared\Tpl\Tpl::view('shop-promotion/promotion-categories-selector', [
|
||||
'label' => 'Kategorie grupa I',
|
||||
'inputName' => 'categories[]',
|
||||
'categories' => $categories,
|
||||
'selectedIds' => is_array($promotion['categories'] ?? null) ? $promotion['categories'] : [],
|
||||
]), [
|
||||
'tab' => 'categories',
|
||||
]),
|
||||
FormField::custom('categories_group_2', \Shared\Tpl\Tpl::view('shop-promotion/promotion-categories-selector', [
|
||||
'label' => 'Kategorie grupa II',
|
||||
'inputName' => 'condition_categories[]',
|
||||
'categories' => $categories,
|
||||
'selectedIds' => is_array($promotion['condition_categories'] ?? null) ? $promotion['condition_categories'] : [],
|
||||
]), [
|
||||
'tab' => 'categories',
|
||||
]),
|
||||
];
|
||||
|
||||
$tabs = [
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
new FormTab('categories', 'Kategorie', 'fa-folder-open'),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/shop_promotion/save/' . ($isNew ? '' : ('id=' . $id));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/shop_promotion/list/'),
|
||||
FormAction::cancel('/admin/shop_promotion/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'shop-promotion-edit',
|
||||
$isNew ? 'Nowa promocja' : ('Edycja promocji: ' . (string)($promotion['name'] ?? '')),
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/shop_promotion/list/',
|
||||
true,
|
||||
['id' => $id]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
265
autoload/admin/Controllers/ShopStatusesController.php
Normal file
265
autoload/admin/Controllers/ShopStatusesController.php
Normal file
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\ShopStatus\ShopStatusRepository;
|
||||
use Domain\Integrations\IntegrationsRepository;
|
||||
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;
|
||||
|
||||
class ShopStatusesController
|
||||
{
|
||||
private ShopStatusRepository $repository;
|
||||
|
||||
public function __construct(ShopStatusRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'status', 'color', 'o', 'apilo_status_id'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Status',
|
||||
'type' => 'text',
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'o'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::get('sort')) === '') {
|
||||
$sortDir = 'ASC';
|
||||
}
|
||||
|
||||
$result = $this->repository->listForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$sortDir,
|
||||
$listRequest['page'],
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$apiloStatusList = $this->getApiloStatusList();
|
||||
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)($item['id'] ?? 0);
|
||||
$statusName = trim((string)($item['status'] ?? ''));
|
||||
$color = trim((string)($item['color'] ?? ''));
|
||||
$apiloStatusId = $item['apilo_status_id'] ?? null;
|
||||
|
||||
$apiloStatusLabel = '';
|
||||
if ($apiloStatusId !== null && isset($apiloStatusList[$apiloStatusId])) {
|
||||
$apiloStatusLabel = $apiloStatusList[$apiloStatusId];
|
||||
}
|
||||
|
||||
$colorHtml = $color !== ''
|
||||
? '<span style="display:inline-block;width:20px;height:20px;background:' . htmlspecialchars($color, ENT_QUOTES, 'UTF-8') . ';border:1px solid #ccc;vertical-align:middle;margin-right:5px;"></span> ' . htmlspecialchars($color, ENT_QUOTES, 'UTF-8')
|
||||
: '-';
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'status' => '<a href="/admin/shop_statuses/edit/id=' . $id . '">' . htmlspecialchars($statusName, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'color' => $colorHtml,
|
||||
'apilo_status' => htmlspecialchars($apiloStatusLabel, ENT_QUOTES, 'UTF-8'),
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/shop_statuses/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'status', 'sort_key' => 'status', 'label' => 'Status', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'color', 'sort_key' => 'color', 'label' => 'Kolor', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'apilo_status', 'sort_key' => 'apilo_status_id', 'label' => 'Status Apilo', 'sortable' => 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/shop_statuses/list/',
|
||||
'Brak danych w tabeli.'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-statuses/view-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$status = $this->repository->find((int)\Shared\Helpers\Helpers::get('id'));
|
||||
if ($status === null) {
|
||||
\Shared\Helpers\Helpers::alert('Status nie zostal znaleziony.');
|
||||
header('Location: /admin/shop_statuses/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
$apiloStatusList = $this->getApiloStatusList();
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-statuses/status-edit', [
|
||||
'form' => $this->buildFormViewModel($status, $apiloStatusList),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
$response = [
|
||||
'status' => 'error',
|
||||
'msg' => 'Podczas zapisywania statusu wystapil blad. Prosze sprobowac ponownie.',
|
||||
];
|
||||
|
||||
if (is_array($values)) {
|
||||
$statusId = (int)($values['id'] ?? 0);
|
||||
$id = $this->repository->save($statusId, $values);
|
||||
if ($id !== null && $id >= 0) {
|
||||
$response = [
|
||||
'status' => 'ok',
|
||||
'msg' => 'Status zostal zapisany.',
|
||||
'id' => (int)$id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$payload = $_POST;
|
||||
$statusId = isset($payload['id']) && $payload['id'] !== '' ? (int)$payload['id'] : null;
|
||||
if ($statusId === null) {
|
||||
$statusId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
}
|
||||
|
||||
$id = $this->repository->save($statusId, $payload);
|
||||
if ($id !== null && $id >= 0) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => (int)$id,
|
||||
'message' => 'Status zostal zapisany.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania statusu wystapil blad.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $status, array $apiloStatusList): FormEditViewModel
|
||||
{
|
||||
$id = (int)($status['id'] ?? 0);
|
||||
|
||||
$apiloOptions = ['' => '--- wybierz status apilo.com ---'];
|
||||
foreach ($apiloStatusList as $apiloId => $apiloName) {
|
||||
$apiloOptions[$apiloId] = $apiloName;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'status' => (string)($status['status'] ?? ''),
|
||||
'color' => (string)($status['color'] ?? ''),
|
||||
'apilo_status_id' => $status['apilo_status_id'] ?? '',
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $id),
|
||||
FormField::text('status', [
|
||||
'label' => 'Status',
|
||||
'tab' => 'settings',
|
||||
'readonly' => true,
|
||||
]),
|
||||
FormField::color('color', [
|
||||
'label' => 'Kolor',
|
||||
'tab' => 'settings',
|
||||
]),
|
||||
FormField::select('apilo_status_id', [
|
||||
'label' => 'Status z Apilo',
|
||||
'tab' => 'settings',
|
||||
'options' => $apiloOptions,
|
||||
]),
|
||||
];
|
||||
|
||||
$tabs = [
|
||||
new FormTab('settings', 'Ustawienia', 'fa-wrench'),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/shop_statuses/save/id=' . $id;
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/shop_statuses/list/'),
|
||||
FormAction::cancel('/admin/shop_statuses/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'status-edit',
|
||||
'Edycja statusu zamowienia',
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/shop_statuses/list/',
|
||||
true,
|
||||
['id' => $id]
|
||||
);
|
||||
}
|
||||
|
||||
private function getApiloStatusList(): array
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
$integrationsRepository = new IntegrationsRepository( $mdb );
|
||||
|
||||
$list = [];
|
||||
$raw = @unserialize( $integrationsRepository -> getSetting( 'apilo', 'status-types-list' ) );
|
||||
if (is_array($raw)) {
|
||||
foreach ($raw as $apiloStatus) {
|
||||
if (isset($apiloStatus['id'], $apiloStatus['name'])) {
|
||||
$list[(int)$apiloStatus['id']] = (string)$apiloStatus['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
346
autoload/admin/Controllers/ShopTransportController.php
Normal file
346
autoload/admin/Controllers/ShopTransportController.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Transport\TransportRepository;
|
||||
use Domain\PaymentMethod\PaymentMethodRepository;
|
||||
use Domain\Integrations\IntegrationsRepository;
|
||||
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;
|
||||
|
||||
class ShopTransportController
|
||||
{
|
||||
private TransportRepository $transportRepository;
|
||||
private PaymentMethodRepository $paymentMethodRepository;
|
||||
|
||||
public function __construct(
|
||||
TransportRepository $transportRepository,
|
||||
PaymentMethodRepository $paymentMethodRepository
|
||||
) {
|
||||
$this->transportRepository = $transportRepository;
|
||||
$this->paymentMethodRepository = $paymentMethodRepository;
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
$sortableColumns = ['id', 'name', 'status', 'cost', 'max_wp', 'default', 'o'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'name',
|
||||
'label' => 'Nazwa',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Aktywny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- aktywny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'name'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::get('sort')) === '') {
|
||||
$sortDir = 'ASC';
|
||||
}
|
||||
|
||||
$result = $this->transportRepository->listForAdmin(
|
||||
$listRequest['filters'],
|
||||
$listRequest['sortColumn'],
|
||||
$sortDir,
|
||||
$listRequest['page'],
|
||||
$listRequest['perPage']
|
||||
);
|
||||
|
||||
$apiloCarrierAccounts = $this->getApiloCarrierAccounts();
|
||||
|
||||
$rows = [];
|
||||
$lp = ($listRequest['page'] - 1) * $listRequest['perPage'] + 1;
|
||||
foreach ($result['items'] as $item) {
|
||||
$id = (int)($item['id'] ?? 0);
|
||||
$name = trim((string)($item['name'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
$cost = (float)($item['cost'] ?? 0.0);
|
||||
$maxWp = $item['max_wp'] ?? null;
|
||||
$default = (int)($item['default'] ?? 0);
|
||||
$apiloCarrierAccountId = $item['apilo_carrier_account_id'] ?? null;
|
||||
|
||||
$apiloLabel = '-';
|
||||
if ($apiloCarrierAccountId !== null) {
|
||||
$apiloKey = (string)$apiloCarrierAccountId;
|
||||
if (isset($apiloCarrierAccounts[$apiloKey])) {
|
||||
$apiloLabel = $apiloCarrierAccounts[$apiloKey];
|
||||
}
|
||||
}
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'default' => $default === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'cost' => \Shared\Helpers\Helpers::decimal($cost) . ' zł',
|
||||
'max_wp' => $maxWp !== null ? (int)$maxWp : '-',
|
||||
'name' => '<a href="/admin/shop_transport/edit/id=' . $id . '">' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'apilo_carrier' => htmlspecialchars((string)$apiloLabel, ENT_QUOTES, 'UTF-8'),
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/shop_transport/edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'default', 'sort_key' => 'default', 'label' => 'Domyślna FT', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'cost', 'sort_key' => 'cost', 'label' => 'Koszt', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'max_wp', 'sort_key' => 'max_wp', 'label' => 'Maks. WP', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'name', 'sort_key' => 'name', 'label' => 'Nazwa', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'apilo_carrier', 'label' => 'Typ kuriera Apilo', 'class' => 'text-center', 'sortable' => false],
|
||||
],
|
||||
$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/shop_transport/list/',
|
||||
'Brak danych w tabeli.'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-transport/transports-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(): string
|
||||
{
|
||||
$transport = $this->transportRepository->find((int)\Shared\Helpers\Helpers::get('id'));
|
||||
if ($transport === null) {
|
||||
\Shared\Helpers\Helpers::alert('Rodzaj transportu nie został znaleziony.');
|
||||
header('Location: /admin/shop_transport/list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
$paymentMethods = $this->paymentMethodRepository->allForAdmin();
|
||||
$apiloCarrierAccounts = $this->getApiloCarrierAccounts();
|
||||
|
||||
return \Shared\Tpl\Tpl::view('shop-transport/transport-edit', [
|
||||
'form' => $this->buildFormViewModel($transport, $paymentMethods, $apiloCarrierAccounts),
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$payload = $_POST;
|
||||
$transportId = isset($payload['id']) && $payload['id'] !== ''
|
||||
? (int)$payload['id']
|
||||
: (int)\Shared\Helpers\Helpers::get('id');
|
||||
|
||||
$payload['id'] = $transportId;
|
||||
|
||||
$id = $this->transportRepository->save($payload);
|
||||
if ($id !== null) {
|
||||
\Shared\Helpers\Helpers::delete_dir('../temp/');
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'id' => (int)$id,
|
||||
'message' => 'Rodzaj transportu został zapisany.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['general' => 'Podczas zapisywania rodzaju transportu wystąpił błąd.'],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
private function buildFormViewModel(
|
||||
array $transport,
|
||||
array $paymentMethods,
|
||||
array $apiloCarrierAccounts
|
||||
): FormEditViewModel {
|
||||
$id = (int)($transport['id'] ?? 0);
|
||||
$name = (string)($transport['name'] ?? '');
|
||||
|
||||
$apiloOptions = ['' => '--- wybierz konto przewoźnika ---'];
|
||||
foreach ($apiloCarrierAccounts as $carrierId => $carrierName) {
|
||||
$apiloOptions[(string)$carrierId] = $carrierName;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'name' => $name,
|
||||
'name_visible' => (string)($transport['name_visible'] ?? ''),
|
||||
'description' => (string)($transport['description'] ?? ''),
|
||||
'cost' => (float)($transport['cost'] ?? 0.0),
|
||||
'max_wp' => $transport['max_wp'] ?? '',
|
||||
'default' => (int)($transport['default'] ?? 0),
|
||||
'status' => (int)($transport['status'] ?? 0),
|
||||
'delivery_free' => (int)($transport['delivery_free'] ?? 0),
|
||||
'apilo_carrier_account_id' => $transport['apilo_carrier_account_id'] ?? '',
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::hidden('id', $id),
|
||||
FormField::text('name', [
|
||||
'label' => 'Nazwa',
|
||||
'tab' => 'general',
|
||||
'readonly' => true,
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::text('name_visible', [
|
||||
'label' => 'Nazwa widoczna',
|
||||
'tab' => 'general',
|
||||
]),
|
||||
FormField::text('description', [
|
||||
'label' => 'Opis',
|
||||
'tab' => 'general',
|
||||
]),
|
||||
FormField::number('cost', [
|
||||
'label' => 'Koszt (PLN)',
|
||||
'tab' => 'general',
|
||||
'step' => 0.01,
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::number('max_wp', [
|
||||
'label' => 'Maks. WP',
|
||||
'tab' => 'general',
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::switch('default', [
|
||||
'label' => 'Domyślna forma dostawy',
|
||||
'tab' => 'general',
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
'tab' => 'general',
|
||||
]),
|
||||
FormField::switch('delivery_free', [
|
||||
'label' => 'Darmowa dostawa',
|
||||
'tab' => 'general',
|
||||
]),
|
||||
FormField::select('apilo_carrier_account_id', [
|
||||
'label' => 'Kurier z Apilo',
|
||||
'tab' => 'general',
|
||||
'options' => $apiloOptions,
|
||||
]),
|
||||
];
|
||||
|
||||
$transportPaymentMethods = $transport['payment_methods'] ?? [];
|
||||
|
||||
$paymentMethodsHtml = '';
|
||||
if (is_array($paymentMethods) && !empty($paymentMethods)) {
|
||||
foreach ($paymentMethods as $paymentMethod) {
|
||||
$pmId = (int)($paymentMethod['id'] ?? 0);
|
||||
$pmName = htmlspecialchars((string)($paymentMethod['name'] ?? ''), ENT_QUOTES, 'UTF-8');
|
||||
$pmStatus = (int)($paymentMethod['status'] ?? 0);
|
||||
$checked = in_array($pmId, $transportPaymentMethods) ? 'checked="checked"' : '';
|
||||
$statusClass = $pmStatus === 0 ? 'text-muted' : '';
|
||||
|
||||
$paymentMethodsHtml .= '<div class="form-group">';
|
||||
$paymentMethodsHtml .= '<div class="col-lg-12">';
|
||||
$paymentMethodsHtml .= '<div class="list">';
|
||||
$paymentMethodsHtml .= '<input type="checkbox" class="g-checkbox" name="payment_methods[]" value="' . $pmId . '" ' . $checked . ' />';
|
||||
$paymentMethodsHtml .= '<span class="bold ' . $statusClass . '">' . $pmName . '</span>';
|
||||
$paymentMethodsHtml .= '</div>';
|
||||
$paymentMethodsHtml .= '</div>';
|
||||
$paymentMethodsHtml .= '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
$fields[] = FormField::custom(
|
||||
'payment_methods_section',
|
||||
$paymentMethodsHtml,
|
||||
['tab' => 'payment_methods']
|
||||
);
|
||||
|
||||
$tabs = [
|
||||
new FormTab('general', 'Ogólne', 'fa-file'),
|
||||
new FormTab('payment_methods', 'Powiązane metody płatności', 'fa-wrench'),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/shop_transport/save/id=' . $id;
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/shop_transport/list/'),
|
||||
FormAction::cancel('/admin/shop_transport/list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
'shop-transport-edit',
|
||||
'Edycja rodzaju transportu: ' . $name,
|
||||
$data,
|
||||
$fields,
|
||||
$tabs,
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/shop_transport/list/',
|
||||
true,
|
||||
['id' => $id]
|
||||
);
|
||||
}
|
||||
|
||||
private function getApiloCarrierAccounts(): array
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
$integrationsRepository = new IntegrationsRepository( $mdb );
|
||||
$rawSetting = $integrationsRepository -> getSetting( 'apilo', 'carrier-account-list' );
|
||||
$raw = null;
|
||||
|
||||
if (is_array($rawSetting)) {
|
||||
$raw = $rawSetting;
|
||||
} elseif (is_string($rawSetting)) {
|
||||
$decoded = @unserialize($rawSetting);
|
||||
if (is_array($decoded)) {
|
||||
$raw = $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_array($raw)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
foreach ($raw as $carrier) {
|
||||
if (is_array($carrier) && isset($carrier['id'], $carrier['name'])) {
|
||||
$list[(string)$carrier['id']] = (string)$carrier['name'];
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
49
autoload/admin/Controllers/UpdateController.php
Normal file
49
autoload/admin/Controllers/UpdateController.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Update\UpdateRepository;
|
||||
|
||||
class UpdateController
|
||||
{
|
||||
private UpdateRepository $repository;
|
||||
|
||||
public function __construct( UpdateRepository $repository )
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function main_view(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view( 'update/main-view', [
|
||||
'ver' => \Shared\Helpers\Helpers::get_version(),
|
||||
'new_ver' => \Shared\Helpers\Helpers::get_new_version(),
|
||||
] );
|
||||
}
|
||||
|
||||
public function update(): void
|
||||
{
|
||||
$result = $this->repository->update();
|
||||
|
||||
if ( !$result['success'] ) {
|
||||
\Shared\Helpers\Helpers::alert( 'W trakcie aktualizacji systemu wystąpił błąd. Proszę spróbować ponownie.' );
|
||||
} else {
|
||||
\Shared\Helpers\Helpers::set_message( 'Aktualizacja przebiegła pomyślnie.' );
|
||||
}
|
||||
|
||||
header( 'Location: /admin/update/main_view/' );
|
||||
exit;
|
||||
}
|
||||
|
||||
public function updateAll(): void
|
||||
{
|
||||
$result = $this->repository->update();
|
||||
|
||||
$response = [
|
||||
'status' => !empty( $result['success'] ) && empty( $result['no_updates'] ),
|
||||
'version' => number_format( (float) \Shared\Helpers\Helpers::get( 'version_current' ) + 0.001, 3, '.', '' ),
|
||||
];
|
||||
|
||||
echo json_encode( $response );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
346
autoload/admin/Controllers/UsersController.php
Normal file
346
autoload/admin/Controllers/UsersController.php
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\User\UserRepository;
|
||||
use admin\ViewModels\Forms\FormAction;
|
||||
use admin\ViewModels\Forms\FormEditViewModel;
|
||||
use admin\ViewModels\Forms\FormField;
|
||||
use admin\Support\Forms\FormRequestHandler;
|
||||
|
||||
class UsersController
|
||||
{
|
||||
private UserRepository $repository;
|
||||
private FormRequestHandler $formHandler;
|
||||
|
||||
public function __construct(UserRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->formHandler = new FormRequestHandler();
|
||||
}
|
||||
|
||||
public function user_delete(): void
|
||||
{
|
||||
if ($this->repository->delete((int)\Shared\Helpers\Helpers::get('id'))) {
|
||||
\Shared\Helpers\Helpers::alert('Uzytkownik zostal usuniety.');
|
||||
}
|
||||
|
||||
header('Location: /admin/users/view_list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
public function user_save(): void
|
||||
{
|
||||
$legacyValues = \Shared\Helpers\Helpers::get('values');
|
||||
if ($legacyValues) {
|
||||
$values = json_decode((string)$legacyValues, true);
|
||||
if (!is_array($values)) {
|
||||
echo json_encode(['status' => 'error', 'msg' => 'Nieprawidlowe dane formularza.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!$this->isTwofaEmailValidForEnabled($values['twofa_enabled'] ?? 0, (string)($values['twofa_email'] ?? ''))) {
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'msg' => 'Jesli wlaczono dwustopniowe uwierzytelnianie (2FA), pole "E-mail do 2FA" jest wymagane.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$response = $this->repository->save(
|
||||
(int)($values['id'] ?? 0),
|
||||
(string)($values['login'] ?? ''),
|
||||
$values['status'] ?? 0,
|
||||
(string)($values['password'] ?? ''),
|
||||
(string)($values['password_re'] ?? ''),
|
||||
$values['admin'] ?? 1,
|
||||
$values['twofa_enabled'] ?? 0,
|
||||
(string)($values['twofa_email'] ?? '')
|
||||
);
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
$userId = (int)\Shared\Helpers\Helpers::get('id');
|
||||
$user = $this->normalizeUser($this->repository->find($userId));
|
||||
$viewModel = $this->buildFormViewModel($user);
|
||||
|
||||
$result = $this->formHandler->handleSubmit($viewModel, $_POST);
|
||||
if (!$result['success']) {
|
||||
$_SESSION['form_errors'][$this->getFormId()] = $result['errors'];
|
||||
echo json_encode(['success' => false, 'errors' => $result['errors']]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = $result['data'];
|
||||
$data['id'] = $userId;
|
||||
$data['admin'] = 1;
|
||||
|
||||
if (!$this->isTwofaEmailValidForEnabled($data['twofa_enabled'] ?? 0, (string)($data['twofa_email'] ?? ''))) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => [
|
||||
'twofa_email' => 'Pole "E-mail do 2FA" jest wymagane, gdy wlaczono 2FA.',
|
||||
],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$duplicateLoginCheck = $this->repository->checkLogin((string)($data['login'] ?? ''), $userId);
|
||||
if (($duplicateLoginCheck['status'] ?? '') !== 'ok') {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'errors' => ['login' => (string)($duplicateLoginCheck['msg'] ?? 'Podany login jest juz zajety.')],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$response = $this->repository->save(
|
||||
(int)$data['id'],
|
||||
(string)($data['login'] ?? ''),
|
||||
(int)($data['status'] ?? 0),
|
||||
(string)($data['password'] ?? ''),
|
||||
(string)($data['password_re'] ?? ''),
|
||||
1,
|
||||
(int)($data['twofa_enabled'] ?? 0),
|
||||
(string)($data['twofa_email'] ?? '')
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'success' => ($response['status'] ?? '') === 'ok',
|
||||
'message' => (string)($response['msg'] ?? 'Zmiany zostaly zapisane.'),
|
||||
'errors' => (($response['status'] ?? '') === 'ok') ? [] : ['general' => (string)($response['msg'] ?? 'Wystapil blad.')],
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function user_edit(): string
|
||||
{
|
||||
$user = $this->normalizeUser($this->repository->find((int)\Shared\Helpers\Helpers::get('id')));
|
||||
$validationErrors = $_SESSION['form_errors'][$this->getFormId()] ?? null;
|
||||
if ($validationErrors) {
|
||||
unset($_SESSION['form_errors'][$this->getFormId()]);
|
||||
}
|
||||
|
||||
return \Shared\Tpl\Tpl::view('users/user-edit', [
|
||||
'form' => $this->buildFormViewModel($user, $validationErrors),
|
||||
]);
|
||||
}
|
||||
|
||||
public function view_list(): string
|
||||
{
|
||||
$sortableColumns = ['login', 'status'];
|
||||
$filterDefinitions = [
|
||||
[
|
||||
'key' => 'login',
|
||||
'label' => 'Login',
|
||||
'type' => 'text',
|
||||
],
|
||||
[
|
||||
'key' => 'status',
|
||||
'label' => 'Aktywny',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'' => '- aktywny -',
|
||||
'1' => 'tak',
|
||||
'0' => 'nie',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$listRequest = \admin\Support\TableListRequestFactory::fromRequest(
|
||||
$filterDefinitions,
|
||||
$sortableColumns,
|
||||
'login'
|
||||
);
|
||||
|
||||
$sortDir = $listRequest['sortDir'];
|
||||
if (trim((string)\Shared\Helpers\Helpers::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 = (int)$item['id'];
|
||||
$login = trim((string)($item['login'] ?? ''));
|
||||
$status = (int)($item['status'] ?? 0);
|
||||
|
||||
$rows[] = [
|
||||
'lp' => $lp++ . '.',
|
||||
'status' => $status === 1 ? 'tak' : '<span style="color: #FF0000;">nie</span>',
|
||||
'login' => '<a href="/admin/users/user_edit/id=' . $id . '">' . htmlspecialchars($login, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
'_actions' => [
|
||||
[
|
||||
'label' => 'Edytuj',
|
||||
'url' => '/admin/users/user_edit/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-primary',
|
||||
],
|
||||
[
|
||||
'label' => 'Usun',
|
||||
'url' => '/admin/users/user_delete/id=' . $id,
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'confirm' => 'Na pewno chcesz usunac wybranego uzytkownika?',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$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' => 'status', 'sort_key' => 'status', 'label' => 'Aktywny', 'class' => 'text-center', 'sortable' => true, 'raw' => true],
|
||||
['key' => 'login', 'sort_key' => 'login', 'label' => 'Login', '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/users/view_list/',
|
||||
'Brak danych w tabeli.',
|
||||
'/admin/users/user_edit/',
|
||||
'Dodaj uzytkownika'
|
||||
);
|
||||
|
||||
return \Shared\Tpl\Tpl::view('users/users-list', [
|
||||
'viewModel' => $viewModel,
|
||||
]);
|
||||
}
|
||||
|
||||
public function list(): string
|
||||
{
|
||||
return $this->view_list();
|
||||
}
|
||||
|
||||
public function login_form(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view('site/unlogged-layout');
|
||||
}
|
||||
|
||||
public function twofa(): string
|
||||
{
|
||||
return \Shared\Tpl\Tpl::view('site/unlogged', [
|
||||
'content' => \Shared\Tpl\Tpl::view('users/user-2fa'),
|
||||
]);
|
||||
}
|
||||
|
||||
private function normalizeUser(?array $user): array
|
||||
{
|
||||
return [
|
||||
'id' => (int)($user['id'] ?? 0),
|
||||
'login' => (string)($user['login'] ?? ''),
|
||||
'status' => (int)($user['status'] ?? 1),
|
||||
'admin' => (int)($user['admin'] ?? 1),
|
||||
'twofa_enabled' => (int)($user['twofa_enabled'] ?? 0),
|
||||
'twofa_email' => (string)($user['twofa_email'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
private function buildFormViewModel(array $user, ?array $errors = null): FormEditViewModel
|
||||
{
|
||||
$userId = (int)($user['id'] ?? 0);
|
||||
$isNew = $userId <= 0;
|
||||
|
||||
$data = [
|
||||
'id' => $userId,
|
||||
'login' => (string)($user['login'] ?? ''),
|
||||
'status' => (int)($user['status'] ?? 1),
|
||||
'twofa_enabled' => (int)($user['twofa_enabled'] ?? 0),
|
||||
'twofa_email' => (string)($user['twofa_email'] ?? ''),
|
||||
'password' => '',
|
||||
'password_re' => '',
|
||||
];
|
||||
|
||||
$fields = [
|
||||
FormField::text('login', [
|
||||
'label' => 'Login',
|
||||
'required' => true,
|
||||
]),
|
||||
FormField::switch('status', [
|
||||
'label' => 'Aktywny',
|
||||
]),
|
||||
FormField::switch('twofa_enabled', [
|
||||
'label' => 'Dwustopniowe uwierzytelnianie (2FA)',
|
||||
]),
|
||||
FormField::email('twofa_email', [
|
||||
'label' => 'E-mail do 2FA',
|
||||
]),
|
||||
FormField::password('password', [
|
||||
'label' => 'Haslo',
|
||||
'required' => $isNew,
|
||||
'attributes' => ['minlength' => 5],
|
||||
]),
|
||||
FormField::password('password_re', [
|
||||
'label' => 'Haslo - powtorz',
|
||||
'required' => $isNew,
|
||||
'attributes' => ['minlength' => 5],
|
||||
]),
|
||||
];
|
||||
|
||||
$actionUrl = '/admin/users/user_save/' . ($isNew ? '' : ('id=' . $userId));
|
||||
$actions = [
|
||||
FormAction::save($actionUrl, '/admin/users/view_list/'),
|
||||
FormAction::cancel('/admin/users/view_list/'),
|
||||
];
|
||||
|
||||
return new FormEditViewModel(
|
||||
$this->getFormId(),
|
||||
$isNew ? 'Nowy uzytkownik' : 'Edycja uzytkownika',
|
||||
$data,
|
||||
$fields,
|
||||
[],
|
||||
$actions,
|
||||
'POST',
|
||||
$actionUrl,
|
||||
'/admin/users/view_list/',
|
||||
true,
|
||||
[
|
||||
'id' => $userId,
|
||||
'admin' => 1,
|
||||
],
|
||||
null,
|
||||
$errors
|
||||
);
|
||||
}
|
||||
|
||||
private function getFormId(): string
|
||||
{
|
||||
return 'users-edit';
|
||||
}
|
||||
|
||||
private function isTwofaEmailValidForEnabled($twofaEnabled, string $twofaEmail): bool
|
||||
{
|
||||
$enabled = ($twofaEnabled === 'on' || $twofaEnabled === 1 || $twofaEnabled === '1' || $twofaEnabled === true);
|
||||
if (!$enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return trim($twofaEmail) !== '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user