OpenXE/www/pages/wizard.php

455 lines
16 KiB
PHP
Raw Normal View History

2021-05-21 08:49:41 +02:00
<?php
/*
**** COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
*
* Xentral (c) Xentral ERP Sorftware GmbH, Fuggerstrasse 11, D-86150 Augsburg, * Germany 2019
*
* This file is licensed under the Embedded Projects General Public License *Version 3.1.
*
* You should have received a copy of this license from your vendor and/or *along with this file; If not, please visit www.wawision.de/Lizenzhinweis
* to obtain the text of the corresponding license version.
*
**** END OF COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
*/
?>
<?php
use Xentral\Components\Http\JsonResponse;
use Xentral\Modules\Wizard\Exception\WizardExceptionInterface;
use Xentral\Modules\Wizard\WizardService;
class Wizard
{
/** @var erpooSystem $app */
public $app;
/** @var WizardService $service */
protected $service;
/**
* @param erpooSystem $app
* @param bool $intern
*/
public function __construct($app, $intern = false)
{
$this->app = $app;
if ($intern) {
return;
}
$this->service = $this->app->Container->get('WizardService');
$this->app->ActionHandlerInit($this);
$this->app->ActionHandler('list', 'WizardList');
$this->app->ActionHandler('ajax', 'WizardAjax');
$this->app->ActionHandler('create', 'WizardCreate');
$this->app->ActionHandlerListen($app);
}
/**
* @return void
*/
public function Install()
{
$this->app->erp->CheckTable('wizard');
$this->app->erp->CheckColumn('id', 'int(11)', 'wizard', 'NOT NULL AUTO_INCREMENT');
$this->app->erp->CheckColumn('user_id', 'INT(11)', 'wizard', "DEFAULT '0' NOT NULL");
$this->app->erp->CheckColumn('key', 'VARCHAR(32)', 'wizard', "DEFAULT '' NOT NULL");
$this->app->erp->CheckColumn('title', 'VARCHAR(64)', 'wizard', "DEFAULT '' NOT NULL");
$this->app->erp->CheckColumn('skip_link_text', 'VARCHAR(64)', 'wizard', 'DEFAULT NULL');
$this->app->erp->CheckColumn('params', 'VARCHAR(512)', 'wizard', 'DEFAULT NULL');
$this->app->erp->CheckColumn('options', 'VARCHAR(512)', 'wizard', 'NULL DEFAULT NULL');
$this->app->erp->CheckColumn('active', 'TINYINT(1)', 'wizard', "DEFAULT '1' NOT NULL");
$this->app->erp->CheckColumn('created_at', 'DATETIME', 'wizard', 'DEFAULT CURRENT_TIMESTAMP NOT NULL');
$this->app->erp->CheckIndex('wizard', ['user_id', 'key'], true);
$this->app->erp->CheckTable('wizard_step');
$this->app->erp->CheckColumn('id', 'int(11)', 'wizard_step', 'NOT NULL AUTO_INCREMENT');
$this->app->erp->CheckColumn('wizard_id', 'INT(11)', 'wizard_step', "DEFAULT '0' NOT NULL");
$this->app->erp->CheckColumn('key', 'VARCHAR(32)', 'wizard_step', "DEFAULT '' NOT NULL");
$this->app->erp->CheckColumn('link', 'VARCHAR(255)', 'wizard_step', "DEFAULT '' NOT NULL");
$this->app->erp->CheckColumn('title', 'VARCHAR(64)', 'wizard_step', "DEFAULT '' NOT NULL");
$this->app->erp->CheckColumn('caption', 'VARCHAR(255)', 'wizard_step', 'DEFAULT NULL');
$this->app->erp->CheckColumn('description', 'TEXT', 'wizard_step', "DEFAULT '' NOT NULL");
$this->app->erp->CheckColumn('options', 'VARCHAR(512)', 'wizard_step', 'DEFAULT NULL');
$this->app->erp->CheckColumn('position', 'TINYINT(3)', 'wizard_step', "DEFAULT '0' NOT NULL");
$this->app->erp->CheckColumn('checked', 'TINYINT(1)', 'wizard_step', "DEFAULT '0' NOT NULL");
$this->app->erp->CheckColumn('created_at', 'DATETIME', 'wizard_step', 'DEFAULT CURRENT_TIMESTAMP NOT NULL');
$this->app->erp->CheckIndex('wizard_step', ['wizard_id', 'key'], true);
$this->app->erp->CheckAlterTable('ALTER TABLE `wizard_step` CHANGE `description` `description` TEXT NOT NULL; ');
$this->app->erp->RegisterHook('before_final_parse_page', 'wizard', 'checkForActiveWizard');
}
public function checkForActiveWizard()
{
$this->service = $this->app->Container->get('WizardService');
$userId = $this->app->User->GetID();
if($userId === null) {
return;
}
if ($activeWizardKey = $this->service->getActiveWizardKey($userId)) {
$this->app->Tpl->Set('ACTIVE_WIZARD_KEY', $activeWizardKey);
$this->app->Tpl->Parse('BODYENDE', 'active_wizard.tpl');
}
}
/**
* @return void
*/
protected function WizardMenu()
{
$this->app->erp->MenuEintrag('index.php?module=wizard&action=create', 'Neuen Wizard anlegen');
$this->app->erp->MenuEintrag('index.php?module=wizard&action=list', '&Uuml;bersicht');
$this->app->Tpl->Set('UEBERSCHRIFT', 'Wizard');
$this->app->erp->Headlines('Wizard');
$this->app->Tpl->Set('TABTEXT', 'Wizard');
}
/**
* @return void
*/
public function WizardList()
{
$this->WizardMenu();
$cmd = $this->app->Secure->GetGET('cmd');
if ($cmd === 'loadexample') {
$data = $this->GetExampleWizardData();
$data['settings']['active'] = true;
try {
$this->service->replaceWizard($data, $this->app->User->GetID());
} catch (Exception $e) {
}
}
$this->app->Tpl->Parse('PAGE', 'wizard_list.tpl');
}
/**
* @return void
*/
public function WizardCreate()
{
$this->WizardMenu();
$jsonOutput = '';
$selectedUserId = 0;
$cmd = $this->app->Secure->GetGET('cmd');
switch ($cmd) {
// JSON einlesen
case 'jsoninput':
$createWizardJsonRaw = $this->app->Secure->GetPOST('createwizard_json');
$selectedUserId = $this->app->Secure->GetPOST('createwizard_user');
if (!empty($createWizardJsonRaw)) {
$createWizardJson = str_replace('\r\n', '', $createWizardJsonRaw);
$createWizardJson = stripslashes($createWizardJson);
$data = json_decode($createWizardJson, true);
if (json_last_error() > 0) {
$message = sprintf('JSON konnte nicht gelesen werden. Code "%s" - Meldung "%s"', json_last_error(), json_last_error_msg());
$this->app->Tpl->Set('MESSAGE', '<div class="error">' . htmlspecialchars($message, ENT_QUOTES) . '</div>');
$jsonOutput = stripslashes(str_replace('\r\n', "\r\n", $createWizardJsonRaw));
break;
}
try {
// JSON konnte fehlerfrei dekodiert werden
$overwriteUserId = (int)$selectedUserId > 0 ? $selectedUserId : null;
$wizardId = $this->service->replaceWizard($data, $overwriteUserId);
$this->app->Tpl->Set('MESSAGE', '<div class="success">Wizard wurde erfolgreich gespeichert.</div>');
// JSON aus den gespeicherten Daten neu generieren
$data = $this->service->generateTemplateFromExistingWizard($wizardId);
$jsonOutput = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
} catch (WizardExceptionInterface $e) {
$message = htmlspecialchars($e->getMessage(), ENT_QUOTES);
$this->app->Tpl->Set('MESSAGE', '<div class="error">Konnte Wizard nicht erstellen. Fehler: ' . $message . '</div>');
$jsonOutput = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
}
break;
// JSON von einem vorhandenen Wizard laden
case 'loadwizard':
if (!empty($this->app->Secure->GetPOST('loadwizard_button'))) {
$loadWizardId = (int)$this->app->Secure->GetPOST('loadwizard_selected');
$data = $this->service->generateTemplateFromExistingWizard($loadWizardId);
$selectedUserId = $data['settings']['user_id'];
$jsonOutput = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
break;
case 'loadexample':
$data = $this->GetExampleWizardData();
$jsonOutput = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
break;
case 'deletewizard':
$deleteWizardId = (int)$this->app->Secure->GetPOST('deletewizard_selected');
$this->service->deleteWizardById($deleteWizardId);
break;
}
$this->app->Tpl->Set('CREATEWIZARDJSON', $jsonOutput);
$this->app->Tpl->Set('CREATEWIZARDUSEROPTIONS', $this->GenerateUserSelectOptions($selectedUserId));
$this->app->Tpl->Set('LOADWIZARDOPTIONS', $this->GenerateWizardSelectOptions());
$this->app->Tpl->Parse('PAGE', 'wizard_create.tpl');
}
/**
* @return JsonResponse|\Xentral\Components\Http\RedirectResponse
*/
public function WizardAjax()
{
$userId = $this->app->User->GetID();
$cmd = $this->app->Secure->GetGET('cmd');
switch ($cmd) {
case 'save_visit':
$wizardKey = $this->app->Secure->GetPOST('wizard');
$stepKey = $this->app->Secure->GetPOST('step');
$success = $this->service->setStepVisited($wizardKey, $stepKey, $userId);
$data = ['success' => $success];
break;
case 'deactivate_wizard':
try {
$wizardKey = $this->app->Secure->GetPOST('wizard');
$this->service->deactivateWizard($wizardKey, $userId);
$data = ['success' => true];
} catch (WizardExceptionInterface $e) {
$data = ['success' => false, 'error' => $e->getMessage()];
}
break;
case 'cancel_active_wizard':
try {
$this->service->cancelActiveWizardForUser($userId);
$data = ['success' => true];
} catch (WizardExceptionInterface $e) {
$data = ['success' => false, 'error' => $e->getMessage()];
}
break;
case 'finish_wizard':
try {
$wizardKey = $this->app->Secure->GetGET('key');
$this->service->finishWizardForUser($wizardKey, $userId);
$data = ['success' => true];
} catch (WizardExceptionInterface $e) {
$data = ['success' => false, 'error' => $e->getMessage()];
}
break;
case 'reset_wizard':
try {
$wizardKey = $this->app->Secure->GetGET('key');
$this->service->resetWizardForUser($wizardKey, $userId);
$data = ['success' => true];
} catch (WizardExceptionInterface $e) {
$data = ['success' => false, 'error' => $e->getMessage()];
}
break;
case 'get_wizards':
$data = [];
$wizardKeys = $this->service->getActiveWizardKeys($userId);
foreach ($wizardKeys as $wizardKey) {
$wizardData = $this->service->getWizard($wizardKey, $userId);
$data[] = $wizardData;
}
break;
case 'get_by_key':
$key = $this->app->Secure->GetGET('key');
$userId = $this->app->User->getId();
$data = $this->service->getWizard($key, $userId);
break;
case 'set_active_wizard':
$key = $this->app->Secure->GetGET('key');
$userId = $this->app->User->getId();
if($this->service->isWizardCompletedForUser($key, $userId)){
$this->service->resetWizardForUser($key,$userId);
}
$this->service->setActiveWizardKey($key, $userId);
$this->service->setMinimizedForUser($userId, false);
$link = $this->service->getFirstWizardLink($key);
return \Xentral\Components\Http\RedirectResponse::createFromUrl($link);
break;
case 'complete_step':
$key = $this->app->Secure->GetGET('key');
$completedStep = $this->app->Secure->GetPOST('step');
$lastVisitedLink = $this->app->Secure->GetPOST('link');
$userId = $this->app->User->getId();
$this->service->setStepVisited($key, $completedStep, $userId);
$this->service->saveLastVisitedLink($key, $lastVisitedLink, $userId);
$data = ['success' => true];
break;
case 'set_minimized':
$state = $this->app->Secure->GetGET('value');
$isMinimized = $state === 'true';
$userId = $this->app->User->getId();
$isMinimized = $this->service->setMinimizedForUser($userId, $isMinimized);
$data = ['success' => true, 'is_minimized' => $isMinimized];
break;
default:
$data = ['success' => false, 'error' => 'Incomplete request'];
break;
}
return new JsonResponse(
$data, $data['success'] === false ? JsonResponse::HTTP_NOT_FOUND : JsonResponse::HTTP_OK
);
}
/**
* Test-Callback-Methode für die 'check_callback'-Option
*
* @return bool
*/
public function CheckArticlesProvidedCallback()
{
$articleCount = $this->app->DB->Select(
'SELECT COUNT(a.id) FROM `artikel` AS `a` WHERE a.geloescht = 0'
);
return (int)$articleCount > 10;
}
/**
* @return array
*/
protected function GetExampleWizardData()
{
$settings = [
'user_id' => $this->app->User->GetID(),
'active' => true,
'key' => 'firstrun',
'title' => 'Einrichtungsassistent',
'skip_link_text' => 'Einrichtung überspringen',
'params' => [
'shop_id' => 1,
]
];
$steps = [
[
'key' => 'grundeinstellungen',
'link' => './index.php?module=firmendaten&action=edit#tabs-1',
'title' => 'Grundeinstellungen',
'caption' => 'Meine Firmen-Informationen pflegen ',
'description' =>
'Bitte tragen Sie hier Ihren Firmennamen und bla bla ein. ',
'position' => 1,
],
[
'key' => 'briefkopf',
'link' => './index.php?module=firmendaten&action=edit#tabs-2',
'title' => 'Briefkopf einrichten',
'caption' => 'Aussehen der Geschäftsbriefe anpassen',
'position' => 2,
'options' => [
'highlight' => [
'breite_position', 'breite_nummer'
]
],
],
[
'key' => 'artikel',
'link' => './index.php?module=artikel&action=list',
'title' => 'Artikel pflegen',
'caption' => 'Beispiel mit Modul-Callback',
'position' => 3,
'description' =>
'Beispiel mit Modul-Callback. Anforderungen:<br>Callback-Methode muss <code>public</code> sein und Rückgabe ' .
'muss zu <code>bool</code> wandelbar sein.',
'options' => [
'check_callback' => [
'module_name' => 'Wizard',
'module_action' => 'CheckArticlesProvidedCallback',
'args' => [
'Wert für erstes Callback-Argument',
'Zweites Argument mit ##shop_id## Parameter'
],
],
]
],
[
'key' => 'adressen',
'link' => './index.php?module=adresse&action=list',
'title' => 'Adressen pflegen',
'caption' => 'Beispiel mit Objekt-Protokoll-Prüfung',
'position' => 4,
'options' => [
'check_protocol' => [
'object_name' => 'shop',
'action_name' => 'shop_created',
'object_id' => '##shop_id##',
],
]
],
];
return [
'settings' => $settings,
'steps' => $steps
];
}
/**
* @param int $selectedUserId
*
* @return string
*/
protected function GenerateUserSelectOptions($selectedUserId)
{
$data = $this->app->DB->SelectArr(
'SELECT u.id, a.name
FROM `user` AS `u`
INNER JOIN `adresse` AS `a` ON u.adresse = a.id
ORDER BY a.name ASC'
);
$html = '';
$selectedUserId = (int)$selectedUserId;
foreach ($data as $row) {
$selectedAttr = $selectedUserId === (int)$row['id'] ? ' selected="selected"' : '';
$html .= sprintf(
'<option value="%s"%s>%s</option>',
$row['id'], $selectedAttr, $row['name']
);
}
return $html;
}
/**
* @return string
*/
protected function GenerateWizardSelectOptions()
{
$data = $this->app->DB->SelectArr(
'SELECT w.id, w.key, w.title, w.active, w.user_id, a.name AS username
FROM `wizard` AS `w`
LEFT JOIN `user` AS `u` ON w.user_id = u.id
INNER JOIN `adresse` AS `a` ON u.adresse = a.id
WHERE 1
ORDER BY w.user_id ASC, w.created_at ASC'
);
$html = '';
foreach ($data as $row) {
$html .= sprintf(
'<option value="%s">%s [%s] - %s (%s)</option>',
$row['id'], $row['username'], $row['user_id'], $row['title'], (int)$row['active'] === 1 ? 'aktiv' : 'inaktiv'
);
}
return $html;
}
}