芝麻web文件管理V1.00
编辑当前文件:/home/mgatv524/cms.mgaplay.com.br/lib/Widget/MenuBoard.php
. */ namespace Xibo\Widget; use Carbon\Carbon; use Respect\Validation\Validator as v; use Slim\Http\Response as Response; use Slim\Http\ServerRequest as Request; use Xibo\Entity\MenuBoardCategory; use Xibo\Support\Exception\InvalidArgumentException; use Xibo\Support\Exception\NotFoundException; class MenuBoard extends ModuleWidget { public $codeSchemaVersion = 1; /** * @inheritDoc */ public function installOrUpdate($moduleFactory) { if ($this->module == null) { // Install $module = $moduleFactory->createEmpty(); $module->name = 'Menu Board'; $module->type = 'menuboard'; $module->class = 'Xibo\Widget\MenuBoard'; $module->description = 'Module for displaying Menu Boards'; $module->enabled = 1; $module->previewEnabled = 1; $module->assignable = 1; $module->regionSpecific = 1; $module->renderAs = 'html'; $module->schemaVersion = $this->codeSchemaVersion; $module->defaultDuration = 60; $module->validExtensions = ''; $module->settings = []; $module->installName = 'menuboard'; $this->setModule($module); $this->installModule(); } // Check we are all installed $this->installFiles(); } /** * @inheritDoc */ public function installFiles() { // Extends parent's method parent::installFiles(); $this->mediaFactory->createModuleSystemFile(PROJECT_ROOT . '/modules/vendor/jquery-cycle-2.1.6.min.js')->save(); $this->mediaFactory->createModuleSystemFile(PROJECT_ROOT . '/modules/xibo-menuboard-render.js')->save(); $this->mediaFactory->createModuleSystemFile(PROJECT_ROOT . '/modules/xibo-image-render.js')->save(); } /** @inheritdoc */ public function layoutDesignerJavaScript() { return 'menuboard-designer-javascript'; } /** * Get MenuBoard object, used by TWIG template. * * @return array * @throws NotFoundException */ public function getMenuBoard() { if ($this->getOption('menuId') != 0) { return [$this->menuBoardFactory->getById($this->getOption('menuId'))]; } else { return null; } } /** * Get Menu Board Categories * @return MenuBoardCategory[] * @throws NotFoundException */ public function getMenuBoardCategories() { return $this->menuBoardCategoryFactory->getByMenuId($this->getOption('menuId')); } public function getTemplatesWithInfo() { // Get templates with filter option $templates = $this->templatesAvailable(true); foreach ($templates as $template) { $template['orientation'] = $this->getTemplateOrientation($template['id']); } return $templates; } public function menuBoardCategoriesSelectedAssigned($columnId) { if ($this->getOption('menuId') == 0) { throw new InvalidArgumentException(__('Menu Board not selected')); } $return = []; $categories = $this->menuBoardCategoryFactory->getByMenuId($this->getOption('menuId')); $categoriesInColumn = explode(',', $this->getOption('categories_' . $columnId)); foreach ($categories as $category) { if (in_array($category->menuCategoryId, $categoriesInColumn)) { $return[] = $category; } } return $return; } public function menuBoardCategoriesSelectedNotAssigned() { if ($this->getOption('menuId') == 0) { throw new InvalidArgumentException(__('Menu Board not selected')); } $categories = $this->getMenuBoardCategories(); $categoriesInColumns = []; $notAssignedCategories = []; for ($i = 1; $i <= $this->getOption('templateZones'); $i++) { foreach (array_filter(explode(',', $this->getOption('categories_' . $i))) as $categoryId) { $categoriesInColumns[] = $categoryId; } } foreach ($categories as $category) { if (!in_array($category->menuCategoryId, $categoriesInColumns)) { $notAssignedCategories[] = $category; } } return $notAssignedCategories; } private function getTemplateInfo($templateId = null) { $templateInfo = []; $templateId = ($templateId) ? $templateId : $this->getOption('templateId'); $template = $this->getTemplateById($templateId); if (isset($template)) { $templateInfo = array_key_exists('info', $template) ? $template['info'] : []; } return $templateInfo; } private function getTemplateOrientation($templateId = null) { $templateOrientation = 'landscape'; $templateId = ($templateId) ? $templateId : $this->getOption('templateId'); $template = $this->getTemplateById($templateId); if (isset($template)) { $templateOrientation = array_key_exists('orientation', $template) ? $template['orientation'] : $templateOrientation; } return $templateOrientation; } /** @inheritdoc */ public function getExtra() { $menuBoard = $this->menuBoardFactory->getById($this->getOption('menuId')); $menuBoardCategories = $this->getMenuBoardCategories(); $products = []; foreach ($menuBoardCategories as $category) { foreach ($category->getProducts() as $product) { if ($product->availability === 1) { $products[] = $product; } } } // Get selected template info $templateInfo = $this->getTemplateInfo(); $templateOptions = array_key_exists('options', $templateInfo) ? $templateInfo['options'] : []; $templateGrid = array_key_exists('grid-template', $templateInfo) ? $templateInfo['grid-template'] : ''; $templateFlex = array_key_exists('flex-template', $templateInfo) ? $templateInfo['flex-template'] : ''; $templateFlexSize = array_key_exists('flex-size', $templateInfo) ? $templateInfo['flex-size'] : ''; // Translate name for each option foreach ($templateOptions as $key => $option) { $templateOptions[$key]['name'] = __($option['name']); } return [ 'menuBoard' => $menuBoard, 'menuCategories' => $menuBoardCategories, 'templateOptions' => $templateOptions, 'gridTemplate' => $templateGrid, 'flexTemplate' => $templateFlex, 'flexTemplateSize' => $templateFlexSize, 'products' => $products, 'highlightProducts' => explode(',', $this->getOption('highlightProducts')) ]; } /** * Validate * @throws InvalidArgumentException */ public function validate() { if (!v::intType()->min(1, true)->validate($this->getDuration())) { throw new InvalidArgumentException(__('You must enter a duration.'), 'duration'); } } /** @inheritdoc @override */ public function editForm(Request $request) { $sanitizedParams = $this->getSanitizer($request->getParams()); // Do we have a step provided? $step = $sanitizedParams->getInt('step', ['default' => 3]); if ($step == 1 || !$this->hasMenu()) { return 'menuboard-designer-form-edit-step1'; } elseif ($step == 2 || !$this->hasCategoriesAssigned()) { return 'menuboard-designer-form-edit-step2'; } else { return 'menuboard-designer-form-edit'; } } /** * Edit Widget * * @SWG\Put( * path="/playlist/widget/{widgetId}?menuboard", * operationId="WidgetMenuBoardEdit", * tags={"widget"}, * summary="Edit a Menu Board Widget", * description="Edit Menu Board Widget. This call will replace existing Widget object, all not supplied parameters will be set to default.", * @SWG\Parameter( * name="widgetId", * in="path", * description="The WidgetId to Edit", * type="integer", * required=true * ), * @SWG\Parameter( * name="name", * in="formData", * description="Optional Widget Name", * type="string", * required=false * ), * @SWG\Parameter( * name="useDuration", * in="formData", * description="Select only if you will provide duration parameter as well", * type="integer", * required=false * ), * @SWG\Parameter( * name="duration", * in="formData", * description="The Widget Duration", * type="integer", * required=false * ), * @SWG\Parameter( * name="enableStat", * in="formData", * description="The option (On, Off, Inherit) to enable the collection of Widget Proof of Play statistics", * type="string", * required=false * ), * @SWG\Parameter( * name="alignH", * in="formData", * description="Horizontal alignment - left, center, bottom", * type="string", * required=false * ), * @SWG\Parameter( * name="alignV", * in="formData", * description="Vertical alignment - top, middle, bottom", * type="string", * required=false * ), * @SWG\Response( * response=204, * description="successful operation" * ) * ) * * @inheritDoc */ public function edit(Request $request, Response $response): Response { $sanitizedParams = $this->getSanitizer($request->getParams()); // Do we have a step provided? $step = $sanitizedParams->getInt('step', ['default' => 3]); if ($step == 1) { // Read in the menuId, validate and store it $menuId = $sanitizedParams->getInt('menuId'); // Do we already have a Menu? if ($this->hasMenu() && $menuId != $this->getOption('menuId')) { // Reset the fields that are dependent on the menuId $this->setOption('categories', ''); $this->_clearColumnCategories(); } $this->setOption('menuId', $menuId); // Validate Menu Board Selected if ($menuId == 0) { throw new InvalidArgumentException(__('Please select a Menu Board'), 'menuId'); } // Check we have permission to use this menuId if (!$this->getUser()->checkViewable($this->menuBoardFactory->getById($this->getOption('menuId')))) { throw new InvalidArgumentException(__('You do not have permission to use that Menu Board'), 'menuId'); } // Template $template = $sanitizedParams->getString('templateId'); // Validate Menu Board Selected if (!$template) { throw new InvalidArgumentException(__('Please select a template'), 'templateId'); } // Did we change template? if ($template != $this->getOption('templateId')) { $this->_clearColumnCategories(); } $this->setOption('templateId', $template); $this->setOption('orientation', $sanitizedParams->getString('orientation')); // Set template zones and layout structure $templateInfo = $this->getTemplateInfo(); $templateZones = array_key_exists('zones', $templateInfo) ? $templateInfo['zones'] : 1; $this->setOption('templateZones', $templateZones); } elseif ($step == 2) { $categoriesAssigned = ''; // Categories for ($i = 1; $i <= $this->getOption('templateZones'); $i++) { $this->setOption('categories_' . $i, implode(',', $sanitizedParams->getIntArray('menuBoardCategories_' . $i, ['default' => []]))); $categoriesAssigned .= $this->getOption('categories_' . $i); } // Validate Menu Board Selected if ($categoriesAssigned == '') { throw new InvalidArgumentException(__('Please assign some Categories to the Menu structure'), 'structure'); } // Store all categories assigned $this->setOption('categoriesAssigned', $categoriesAssigned); } else { $highlightProducts = $sanitizedParams->getIntArray('productsHighlight', ['default' => []]); if (count($highlightProducts) == 0) { $this->setOption('highlightProducts', ''); } else { $this->setOption('highlightProducts', implode(',', $highlightProducts)); } // Other properties $this->setOption('name', $sanitizedParams->getString('name')); $this->setUseDuration($sanitizedParams->getCheckbox('useDuration')); $this->setDuration($sanitizedParams->getInt('duration', ['default' => $this->getDuration()])); $this->setOption('enableStat', $sanitizedParams->getString('enableStat')); $this->setOption('updateInterval', $sanitizedParams->getInt('updateInterval', ['default' => 120])); $this->setOption('alignH', $sanitizedParams->getString('alignH', ['default' => 'center'])); $this->setOption('alignV', $sanitizedParams->getString('alignV', ['default' => 'middle'])); // Template options $templateInfo = $this->getTemplateInfo(); $templateOptions = array_key_exists('options', $templateInfo) ? $templateInfo['options'] : []; foreach ($templateOptions as $key => $option) { if ($option['type'] === 'checkbox' || $option['type'] === 'switch') { $optionValue = $sanitizedParams->getCheckbox($key); } elseif ($sanitizedParams->getString($key) == '') { $optionValue = $option['default']; } else { $optionValue = $sanitizedParams->getString($key); } $this->setOption($key, $optionValue); } $this->setOption('showUnavailable', $sanitizedParams->getCheckbox('showUnavailable')); $this->setOption('fontFamily', $sanitizedParams->getString('fontFamily')); // Validate $this->isValid(); } // Save the widget $this->saveWidget(); return $response; } /** @inheritdoc */ public function getResource($displayId = 0) { $this ->initialiseGetResource() ->appendViewPortWidth($this->region->width) ->appendJavaScriptFile('vendor/jquery.min.js') ->appendJavaScriptFile('vendor/jquery-cycle-2.1.6.min.js') ->appendJavaScriptFile('xibo-layout-scaler.js') ->appendJavaScriptFile('xibo-menuboard-render.js') ->appendJavaScriptFile('xibo-image-render.js') ->appendJavaScript('var xiboICTargetId = ' . $this->getWidgetId() . ';') ->appendJavaScriptFile('xibo-interactive-control.min.js') ->appendJavaScript('xiboIC.lockAllInteractions()') ->appendFontCss() ->appendCss(file_get_contents($this->getConfig()->uri('css/client.css', true))); // Get CSS from the original template or from the input field $styleSheet = ''; $template = $this->getTemplateById($this->getOption('templateId')); if (!$template) { return; } $widgetOriginalWidth = null; $widgetOriginalHeight = null; $styleSheet = $template['css']; $widgetOriginalWidth = $template['widgetOriginalWidth']; $widgetOriginalHeight = $template['widgetOriginalHeight']; $styleSheet = $this->parseLibraryReferences($this->isPreview(), $styleSheet); // Parse stylesheet values using options $styleSheet = $this->parseCSSProperties($styleSheet); // Calculate duration $duration = $this->getCalculatedDurationForGetResource(); // Generate the table $table = $this->menuBoardHtml($displayId); // Replace and Control Meta options $this ->appendControlMeta('DURATION', $duration) ->appendCss($styleSheet) ->appendOptions([ 'type' => $this->getModuleType(), 'duration' => $duration, 'originalWidth' => $this->region->width, 'originalHeight' => $this->region->height, 'widgetDesignWidth' => $widgetOriginalWidth, 'widgetDesignHeight' => $widgetOriginalHeight, 'generatedOn' => Carbon::now()->format('c'), 'alignmentH' => $this->getOption('alignH'), 'alignmentV' => $this->getOption('alignV') ]) ->appendJavaScript(' $(document).ready(function() { $("body").xiboLayoutScaler(options); const runOnVisible = function() { $(".menu-board-parent-container").menuBoardRender(options); }; (xiboIC.checkVisible()) ? runOnVisible() : xiboIC.addToQueue(runOnVisible); $(".menu-board-parent-container").find("img").xiboImageRender(options); }); ')->appendBody($table['html']); return $this->finaliseGetResource(); } private function menuBoardHtml($displayId = 0) { // Show a preview of the Menu Board if ($this->hasMenu()) { $menuId = $this->getOption('menuId'); $menuBoard = $this->menuBoardFactory->getById($menuId); } else { return $this->noDataMessageOrDefault('No menu selected'); } if (!$this->hasCategoriesAssigned()) { return $this->noDataMessageOrDefault('No categories selected'); } $menu = ''; try { // Main menu container $menu .= '
'; // Menu board name $menu .= '
' . $menuBoard->name . '
'; // Get template option property $templateInfo = $this->getTemplateInfo(); $gridTemplate = array_key_exists('grid-template', $templateInfo) ? $templateInfo['grid-template'] : ''; $templateFlex = array_key_exists('flex-template', $templateInfo) ? $templateInfo['flex-template'] : ''; $templateFlexSize = array_key_exists('flex-size', $templateInfo) ? $templateInfo['flex-size'] : ''; $legacyTemplate = array_key_exists('legacy', $templateInfo) ? $templateInfo['legacy'] : false; // Menu categories container $menu .= "
getOption('templateZones'); $i++) { $categoryIds = array_filter(explode(',', $this->getOption('categories_' . $i))); $menu .= '
menuBoardCategoryFactory->getById((int)$categoryId); // get category products, depending on the showUnavailable fetch all or only available products if ($this->getOption('showUnavailable') == 0) { $categoryProductsData = $category->getAvailableProducts(['name']); } else { $categoryProductsData = $category->getProducts(['name']); } // Category header $menu .= '
'; $menu .= '
' . $category->name . '
'; // Product image $showImagesForCategories = array_key_exists('categoryImage', $templateInfo) ? $templateInfo['categoryImage'] : false; if ($showImagesForCategories) { try { $file = $this->mediaFactory->getById($category->mediaId); // Already in the library - assign this mediaId to the Layout immediately. $this->assignMedia($file->mediaId); $menu .= ($this->isPreview()) ? '
' : '
'; } catch (NotFoundException $e) { $this->getLog()->debug('Image for category ' . $category->mediaId . ' failed!'); } } $menu .= '
'; // Products $menu .= '
'; // Create products foreach ($categoryProductsData as $key => $categoryProduct) { // depending on configured options, we will want to assign different css classes to the MenuBoardProductContainer if ($categoryProduct->availability === 0 && $this->getOption('showUnavailable') == 0) { continue; } elseif ($categoryProduct->availability === 0 && $this->getOption('showUnavailable') == 1) { $menu .= '
'; } elseif (in_array($categoryProduct->menuProductId, explode(',', $this->getOption('highlightProducts')))) { $menu .= '
'; } else { $menu .= '
'; } // Product image $showImagesForProducts = array_key_exists('productImage', $templateInfo) ? $templateInfo['productImage'] : false; if ($showImagesForProducts) { try { $file = $this->mediaFactory->getById($categoryProduct->mediaId); // Already in the library - assign this mediaId to the Layout immediately. $this->assignMedia($file->mediaId); $menu .= ($this->isPreview()) ? '
' : '
'; } catch (NotFoundException $e) { $this->getLog()->debug('Image for product ' . $categoryProduct->mediaId . ' failed!'); } } // On legacy templates, we group the info items together if ($legacyTemplate) { $menu .= '
'; } // Product name and price should always be visible. $menu .= '
' . $categoryProduct->name . '
'; $menu .= '
' . $categoryProduct->price . '
'; // Product options $productOptions = $categoryProduct->getOptions(); if ($productOptions) { $menu .= '
'; foreach ($productOptions as $productOption) { $menu .= '
' . $productOption->option . ': ' . $productOption->value . '
'; } // Close menu-board-product-options-container $menu .= '
'; } // Description if ($categoryProduct->description) { $menu .= '
' . $categoryProduct->description . '
'; } // Allergy if ($categoryProduct->allergyInfo) { $menu .= '
' . $categoryProduct->allergyInfo . '
'; } // close info group if ($legacyTemplate) { $menu .= '
'; } // Close menu-board-product $menu .= '
'; } // Close menu-board-products-container $menu .= '
'; } // Close menu-board-zone $menu .= '
'; } // Close menu-board-categories-container $menu .= '
'; // Close menu-board-parent-container $menu .= '
'; return [ 'html' => $menu ]; } catch (NotFoundException $e) { $this->getLog()->info(sprintf('Request failed for MenuBoard id=%d. Widget=%d. Due to %s', $menuId, $this->getWidgetId(), $e->getMessage())); $this->getLog()->debug($e->getTraceAsString()); return $this->noDataMessageOrDefault(); } } /** * Parse CSS properties and build CSS based on them * @return string */ private function parseCSSProperties($css) { // Get template option property $templateInfo = $this->getTemplateInfo(); $templateOptions = array_key_exists('options', $templateInfo) ? $templateInfo['options'] : []; // We've got something at least, so prepare the template $matches = []; preg_match_all('/\[.*?\]/', $css, $matches); // Run through all [] substitutes in $matches for colors foreach ($matches[0] as $sub) { // Get option name $option = substr($sub, 1, -1); // Value from form options or default values from the template $value = $this->getOption($option) ? $this->getOption($option) : $templateOptions[$option]['default']; // Substitute the replacement we have found (it might be '') $css = str_replace($sub, $value, $css); } // Build override rules based on other options foreach ($templateOptions as $key => $option) { if (!array_key_exists('rule', $option)) { continue; } $query = array_key_exists('query', $option) ? $option['query'] : ('.' . $key); if ($option['rule'] == 'display' && $this->getOption($key, $option['default']) == 0) { $css .= ' ' . $query . ' { display: none; } '; } } // Font family if ($this->getOption('fontFamily') != '') { $css .= ' .menu-board-parent-container { font-family: ' . $this->getOption('fontFamily') . '; }'; } return $css; } /** * Does this module have a Menu yet? * @return bool */ private function hasMenu() { return (v::notEmpty()->validate($this->getOption('menuId'))); } /** * Does this module have assigned categories? * @return bool */ private function hasCategoriesAssigned() { return (v::notEmpty()->validate($this->getOption('categoriesAssigned'))); } /** @inheritdoc */ public function isValid() { if ($this->getUseDuration() == 1 && $this->getDuration() == 0) { throw new InvalidArgumentException(__('Please enter a duration'), 'duration'); } return ($this->hasMenu()) ? self::$STATUS_VALID : self::$STATUS_INVALID; } /** @inheritdoc */ public function getModifiedDate($displayId) { $widgetModifiedDt = $this->widget->modifiedDt; if ($this->hasMenu()) { $menuId = $this->getOption('menuId'); $menuBoard = $this->menuBoardFactory->getById($menuId); // Set the timestamp $widgetModifiedDt = ($menuBoard->modifiedDt > $widgetModifiedDt) ? $menuBoard->modifiedDt : $widgetModifiedDt; $menuBoard->setActive(); } return Carbon::createFromTimestamp($widgetModifiedDt); } /** * @param string|null $default * @return array * @throws \Xibo\Support\Exception\NotFoundException */ private function noDataMessageOrDefault($default = null) { if ($default === null) { $default = __('Empty Result Set with filter criteria.'); } throw new NotFoundException($default); } /** * Clear all the assigned categories from the manu structure */ private function _clearColumnCategories() { $this->setOption('categoriesAssigned', ''); for ($i = 1; $i <= $this->getOption('templateZones'); $i++) { $this->setOption('categories_' . $i, ''); } } /** @inheritdoc */ public function getCacheDuration() { return 1; } /** @inheritdoc */ public function getCacheKey($displayId) { // MenuBoards are display specific return $this->getWidgetId() . '_' . $displayId; } /** @inheritdoc */ public function isCacheDisplaySpecific() { return true; } /** @inheritdoc */ public function getLockKey() { return $this->getWidgetId() . '_' . $this->getOption('menuId'); } /** @inheritDoc */ public function hasTemplates() { return true; } /** @inheritDoc */ public function hasHtmlEditor() { return true; } /** @inheritDoc */ public function getHtmlWidgetOptions() { return ['template']; } }