feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
- Base: wintercms/winter branch 1.2 (full framework) - Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS - Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication - Partials: hero (offline-first), features, modes (offline/nube toggle), screenshots, pricing (3 planes), comparison, FAQ, CTA - Plugin VivesPOS.Site with ContactForm - Dockerfile: PHP 8.2 Apache, port 80, healthcheck - Added winter/wn-pages, blog, sitemap, seo plugins - Active theme set to vivespos
This commit is contained in:
309
modules/cms/models/ThemeData.php
Normal file
309
modules/cms/models/ThemeData.php
Normal file
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
namespace Cms\Models;
|
||||
|
||||
use Cms\Classes\Theme as CmsTheme;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Lang;
|
||||
use System\Classes\CombineAssets;
|
||||
use System\Models\File;
|
||||
use Winter\Storm\Database\Model;
|
||||
|
||||
/**
|
||||
* Customization data used by a theme
|
||||
*
|
||||
* @package winter\wn-cms-module
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
class ThemeData extends Model
|
||||
{
|
||||
use \Winter\Storm\Database\Traits\Validation;
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'cms_theme_data';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* @var array List of attribute names which are json encoded and decoded from the database.
|
||||
*/
|
||||
protected $jsonable = ['data'];
|
||||
|
||||
/**
|
||||
* @var array The rules to be applied to the data.
|
||||
*/
|
||||
public $rules = [];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $attachOne = [];
|
||||
|
||||
/**
|
||||
* @var ThemeData Cached array of objects
|
||||
*/
|
||||
protected static $instances = [];
|
||||
|
||||
/**
|
||||
* @var int The number of minutes the theme data is cached for.
|
||||
*/
|
||||
protected static $cacheTtl = 1440;
|
||||
|
||||
/**
|
||||
* Before saving the model, strip dynamic attributes applied from config.
|
||||
* @return void
|
||||
*/
|
||||
public function beforeSave()
|
||||
{
|
||||
/*
|
||||
* Dynamic attributes are stored in the jsonable attribute 'data'.
|
||||
*/
|
||||
$staticAttributes = ['id', 'theme', 'data', 'created_at', 'updated_at'];
|
||||
$dynamicAttributes = array_except($this->getAttributes(), $staticAttributes);
|
||||
|
||||
$this->data = $dynamicAttributes;
|
||||
$this->setRawAttributes(array_only($this->getAttributes(), $staticAttributes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear asset cache after saving to ensure `assetVar` form fields take
|
||||
* immediate effect.
|
||||
*/
|
||||
public function afterSave()
|
||||
{
|
||||
static::flushCache($this->theme);
|
||||
|
||||
try {
|
||||
CombineAssets::resetCache();
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache after deleting so that the record isn't served from the cache.
|
||||
*/
|
||||
public function afterDelete()
|
||||
{
|
||||
static::flushCache($this->theme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cache key used to store the data for the provided theme directory.
|
||||
*/
|
||||
public static function getCacheKey(string $dirName): string
|
||||
{
|
||||
return 'cms::theme.data.' . $dirName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes both the persistent and in memory cache of the provided theme directory's data.
|
||||
*/
|
||||
public static function flushCache(?string $dirName = null): void
|
||||
{
|
||||
if (is_null($dirName)) {
|
||||
self::$instances = [];
|
||||
return;
|
||||
}
|
||||
|
||||
Cache::forget(static::getCacheKey($dirName));
|
||||
unset(self::$instances[$dirName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cached version of this model, based on a Theme object.
|
||||
* @param $theme Cms\Classes\Theme
|
||||
* @return self
|
||||
*/
|
||||
public static function forTheme($theme)
|
||||
{
|
||||
$dirName = $theme->getDirName();
|
||||
if ($themeData = array_get(self::$instances, $dirName)) {
|
||||
return $themeData;
|
||||
}
|
||||
|
||||
try {
|
||||
// The record is cached rather than queried on every request; it is invalidated
|
||||
// by afterSave() / afterDelete(), which also covers the initial creation below.
|
||||
$themeData = self::where('theme', $dirName)
|
||||
->remember(self::$cacheTtl, self::getCacheKey($dirName))
|
||||
->first() ?: self::create(['theme' => $dirName]);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
// Database failed
|
||||
$themeData = new self(['theme' => $dirName]);
|
||||
}
|
||||
|
||||
return self::$instances[$dirName] = $themeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* After fetching the model, intiialize model relationships based
|
||||
* on form field definitions.
|
||||
* @return void
|
||||
*/
|
||||
public function afterFetch()
|
||||
{
|
||||
$data = (array) $this->data + $this->getDefaultValues();
|
||||
|
||||
foreach ($this->getFormFields() as $id => $field) {
|
||||
if (!isset($field['type'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Repeater and nested form fields store arrays and must be jsonable.
|
||||
*/
|
||||
if (in_array($field['type'], ['repeater', 'nestedform'])) {
|
||||
$this->jsonable[] = $id;
|
||||
} elseif ($field['type'] === 'fileupload') {
|
||||
if (array_get($field, 'multiple', false)) {
|
||||
$this->attachMany[$id] = File::class;
|
||||
} else {
|
||||
$this->attachOne[$id] = File::class;
|
||||
}
|
||||
unset($data[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill this model with the jsonable attributes kept in 'data'.
|
||||
*/
|
||||
$this->setRawAttributes((array) $this->getAttributes() + $data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Before model is validated, set the default values.
|
||||
* @return void
|
||||
*/
|
||||
public function beforeValidate()
|
||||
{
|
||||
if (!$this->exists) {
|
||||
$this->setDefaultValues();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates relationships for this model based on form field definitions.
|
||||
*/
|
||||
public function initFormFields()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default values on this model based on form field definitions.
|
||||
*/
|
||||
public function setDefaultValues()
|
||||
{
|
||||
foreach ($this->getDefaultValues() as $attribute => $value) {
|
||||
$this->{$attribute} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets default values for this model based on form field definitions.
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaultValues()
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($this->getFormFields() as $attribute => $field) {
|
||||
if (($value = array_get($field, 'default')) === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[$attribute] = $value;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all fields defined for this model, based on form field definitions.
|
||||
* @return array
|
||||
*/
|
||||
public function getFormFields()
|
||||
{
|
||||
if (!$theme = CmsTheme::load($this->theme)) {
|
||||
throw new Exception(Lang::get('Unable to find theme with name :name', $this->theme));
|
||||
}
|
||||
|
||||
$config = $theme->getFormConfig();
|
||||
|
||||
return array_get($config, 'fields', []) +
|
||||
array_get($config, 'tabs.fields', []) +
|
||||
array_get($config, 'secondaryTabs.fields', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns variables that should be passed to the asset combiner.
|
||||
* @return array
|
||||
*/
|
||||
public function getAssetVariables()
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($this->getFormFields() as $attribute => $field) {
|
||||
if (!$varName = array_get($field, 'assetVar')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[$varName] = $this->{$attribute};
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies asset variables to the combiner filters that support it.
|
||||
* @return void
|
||||
*/
|
||||
public static function applyAssetVariablesToCombinerFilters($filters)
|
||||
{
|
||||
$theme = CmsTheme::getActiveTheme();
|
||||
|
||||
if (!$theme) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$theme->hasCustomData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$assetVars = $theme->getCustomData()->getAssetVariables();
|
||||
|
||||
foreach ($filters as $filter) {
|
||||
if (method_exists($filter, 'setPresets')) {
|
||||
$filter->setPresets($assetVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a cache key for the combiner, this allows variables to bust the cache.
|
||||
* @return string
|
||||
*/
|
||||
public static function getCombinerCacheKey()
|
||||
{
|
||||
$theme = CmsTheme::getActiveTheme();
|
||||
if (!$theme->hasCustomData()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$customData = $theme->getCustomData();
|
||||
|
||||
return (string) $customData->updated_at ?: '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user