Автовывод заполненных модификаций и опций msOptionPrice2

Доброго дня!

Нужна помощь. Кто готов сделать полностью на платной основе — пожалуйста https://modx.pro/work/16473

На фронтенде выводятся модификации товара и опции автоматически — без указания в чанке, какую опцию выводить, а какую нет.

На фронтенде это выглядит так:


Модификации (для понимания) такие:
Цвет (Белый) — Ширина умывальника (80) — +1000р
Цвет (Белый) — Ширина умывальника (100) — +2000р
Цвет (Черный) — Ширина умывальника (80) — +3000р
Цвет (Черный) — Ширина умывальника (100) — +4000р

Нужно сделать некоторые доработки:
1. В модификациях вывести автоматически не только опции товара, но и свойства товара. Компонент позволяет в модификациях использовать не только опции товара, но и свойства. Сейчас настроен автовывод только опций — нужно и модификаций.
2. Сделать вывод названия опции и свойства из caption (так же, как называется в админке, а не из лексикона) — на изображении ms2_product_color2 не задавать через словарь.
3. Из списка опций, которые под модификациями, исключить автоматически те, которые использованы в модификациях. На изображении под модификациями автоматически выводятся опции. Стоит, видимо, объединить вывод модификаций и вывод списком опций и в процессе перебора опций и свойств разделить на те, которые использованы в модификациях и на остальные. Модификации вывести с возможностью выбора значений, а остальные — просто в виде таблицы.

Логику действий понимаю, но знаний реализовать не хватает. Буду рад любым промежуточным вариантам или готовому решению.
Общий вывод такой:
{*модификации*}
            {set $properties = 'msOptionsPrice.properties'|snippet:[
            'tpl' => 'tpl.modifications',
            ]}
            {'msOptionsPrice.option'|snippet:$properties}
            {*/модификации*}
            
            {*опции*}
            {'msProductOptions' | snippet : [
                'tpl' => 'productOptions',
                'ignoreOptions' => 'add,select'
            ]}
            {*/опции*}
msOptionsPrice.properties:
<?php
// msOptionsPrice.properties

/** @var modX $modx */
/** @var array $scriptProperties */
$product = !empty($product) && $product != $modx->resource->id ? $modx->getObject('msProduct', $product) : $modx->resource;
if (!($product instanceof msProduct)) {
    $modx->log(1, print_r("[msOptions] The resource with id = {$product->id} is not instance of msProduct.", 1));

    return $scriptProperties;
}

$options = array_map('trim', explode(',', $options));
$options = @array_diff($options, ['']);

$c = $modx->newQuery('msCategoryOption');
$c->innerJoin('msOption', 'Option');
$c->innerJoin('msProductOption', 'ProductOption', 'ProductOption.key = Option.key AND ProductOption.value != "" AND ProductOption.product_id = ' . $product->id);
$c->select('Option.key');
if (empty($options)) {
    $c->where([
        'category_id' => $product->parent,
    ]);
} else {
    $c->where([
        'category_id'          => $product->parent,
        'ProductOption.key:IN' => $options,
    ]);
}
$c->sortby('rank', 'asc');
$c->groupby('Option.key');
if ($c->prepare() AND $c->stmt->execute()) {
    $options = $c->stmt->fetchAll(PDO::FETCH_COLUMN);
}
$options = $options ? $options : [];

$constraintOptions = [];
if (!empty($options)) {
    foreach ($options as $idx => $key) {
        if ($idx) {
            $constraintOptions[$key] = [$options[$idx - 1]];
        }
    }
}

return array_merge($scriptProperties, ['options' => implode(',', $options), 'constraintOptions' => $constraintOptions]);
tpl.modifications:
{foreach $options as $name => $values}
    <div class="sm-text"><b>{('ms2_product_' ~ $name) | lexicon}</b></div>
    <div
        {if $constraints[$name]}
            data-constraints="{$constraints[$name]| json_encode: 256 | htmlentities}"
        {/if}
        >
        {foreach $values as $value index=$index}
         
        <label class="input-parent">
        <input type="radio" value="{$values[$index]}" name="options[{$name}]" 
            {if $index == 0}checked="checked"{/if}
            
            {if $constraints[$name]}
                data-relations="{$relations[$name][$value]| json_encode: 256 | htmlentities}"
            {/if}
                    
            />
            {$values[$index]}
        </label>
    
        {/foreach}
    </div>
{/foreach}
msOptionsPrice.option:
<?php
$classModification = 'msopModification';
$classOption = 'msopModificationOption';

if (!function_exists('getModificationOptions')) {
    function getModificationOptions(modX & $modx, $rid = null, $showZeroCount = true)
    {
        $options = array();

        $classModification = 'msopModification';
        $classOption = 'msopModificationOption';
        $classMsOption = 'msOption';

        $q = $modx->newQuery($classOption);
        $q->innerJoin($classModification, $classModification, "{$classModification}.id = {$classOption}.mid");
        $q->leftJoin($classMsOption, $classMsOption, "{$classOption}.key = {$classMsOption}.key");

        $q->select($modx->getSelectColumns($classOption, $classOption));
        $q->select($modx->getSelectColumns($classMsOption, $classMsOption, '', array('caption'), false));

        $q->where(array(
            "{$classOption}.rid"          => "{$rid}",
            "{$classModification}.active" => true,
        ));
        if (!$showZeroCount) {
            $q->andCondition(array(
                "{$classModification}.count:>" => 0,
            ));
        }

        if ($q->prepare() AND $q->stmt->execute()) {
            while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
                $k = $row['key'];
                if (!isset($options[$k])) {
                    $options[$k] = array($row['value']);
                } else {
                    $options[$k][] = $row['value'];
                }

                foreach ($row as $x => $value) {
                    $options[$k . '.' . $x] = $value;
                }
            }
        }

        return $options;
    }
}

if (!function_exists('getOptionColors')) {
    function getOptionColors(modX & $modx, $rid = null, $key = null)
    {
        $colors = array();

        $classColor = 'msocColor';
        $q = $modx->newQuery($classColor);
        $q->where(array(
            "{$classColor}.rid" => "{$rid}",
            "{$classColor}.key" => "{$key}",
        ));
        $q->andCondition(array(
            "{$classColor}.color:!="       => "",
            "OR:{$classColor}.color2:!="   => "",
            "OR:{$classColor}.pattern:!="  => "",
            "OR:{$classColor}.pattern2:!=" => "",
        ));

        $q->select($modx->getSelectColumns($classColor, $classColor, '', array('rid', 'key'), true));
        if ($q->prepare() AND $q->stmt->execute()) {
            while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
                $k = $row['value'];
                $colors[$k] = $row;
            }
        }

        return $colors;
    }
}

/** @var modX $modx */
/** @var array $scriptProperties */
$tpl = $modx->getOption('tpl', $scriptProperties, 'tpl.msOptions');
$showZeroCount = (bool)$modx->getOption('showZeroCount', $scriptProperties, true);
$showProductOptions = (bool)$modx->getOption('showProductOptions', $scriptProperties, false);
$processColors = (bool)$modx->getOption('processColors', $scriptProperties, false);

if (!empty($input) && empty($product)) {
    $product = $input;
}
if (!empty($name) && empty($options)) {
    $options = $name;
}
$names = array_map('trim', explode(',', $options));
$names = array_diff($names, array(''));

$product = !empty($product) && $product != $modx->resource->id
    ? $modx->getObject('msProduct', $product)
    : $modx->resource;
if (!($product instanceof msProduct)) {
    return "[msOptions] The resource with id = {$product->id} is not instance of msProduct.";
}
$modx->lexicon->load('minishop2:product');

$constraints = $modx->getOption('constraintOptions', $scriptProperties);
if ($constraints AND !is_array($constraints)) {
    $constraints = json_decode($constraints, true);
}

$data = $productData = getModificationOptions($modx, $product->id, $showZeroCount);
if ($showProductOptions) {
    $productData = $product->loadOptions();
}

$options = $captions = $relations = $colors = array();
foreach ($names as $name) {
    $option = $modx->getOption($name, $data);
    if (!$option AND $showProductOptions) {
        $option = $modx->getOption($name, $productData);
    }
    if ($option) {
        $option = array_unique($option);
        sort($option);
        $options[$name] = $option;

        // process captions
        if (isset($data[$name . '.caption'])) {
            $captions[$name] = $data[$name . '.caption'];
        } else {
            $captions[$name] = $modx->lexicon('ms2_product_' . $name);
        }

        // process relations
        if (!empty($constraints) AND array_key_exists($name, $constraints)) {
            $relations[$name] = array();

            $q = $modx->newQuery($classOption);
            $q->innerJoin($classModification, $classModification, "{$classModification}.id = {$classOption}.mid");
            $q->leftJoin($classOption, 'Values', "{$classOption}.mid = Values.mid");
            $q->where(array(
                "{$classOption}.rid"          => "{$product->id}",
                "{$classOption}.key"          => "{$name}",
                "{$classModification}.active" => true,
            ));
            if (!$showZeroCount) {
                $q->andCondition(array(
                    "{$classModification}.count:>" => 0,
                ));
            }

            $q->limit(0);
            $q->sortby("{$classOption}.key", "ASC");
            $q->groupby("{$classOption}.mid");
            $q->select("{$classOption}.value, GROUP_CONCAT(CONCAT_WS('=',`Values`.`key`,`Values`.`value`) SEPARATOR '&') as value");

            $rows = array();
            if ($q->prepare() && $q->stmt->execute()) {
                if (!$rows = $q->stmt->fetchAll(PDO::FETCH_COLUMN | PDO::FETCH_GROUP)) {
                    $rows = array();
                }
                foreach ($rows as $key => &$row) {
                    foreach ($row as $k => $v) {
                        parse_str($v, $row[$k]);
                        ksort($row[$k]);
                        unset($row[$k][$name]);

                        $v = array();
                        foreach ($row[$k] as $param => $value) {
                            $v[] = "{$param}={$value}";
                        }
                        $row[$k] = implode('&', $v);
                    }
                }
                $relations[$name] = $rows;
            }
        }

        // process colors
        if ($processColors) {
            $colors[$name] = getOptionColors($modx, $product->id, $name);
        }
    }
}

if (!empty($scriptProperties['sortOptions'])) {
    $sorts = array_map('trim', explode(',', $scriptProperties['sortOptions']));
    foreach ($sorts as $sort) {
        $sort = explode(':', $sort);
        $key = $sort[0];
        $order = SORT_ASC;
        if (!empty($sort[1])) {
            $order = constant($sort[1]);
        }
        $type = SORT_STRING;
        if (!empty($sort[2])) {
            $type = constant($sort[2]);
        }
        $first = null;
        if (!empty($sort[3])) {
            $first = $sort[3];
        }

        if (array_key_exists($key, $options) AND is_array($options[$key]) AND !empty($options[$key])) {
            array_multisort($options[$key], $order, $type);
            if ($first && ($index = array_search($first, $options[$key])) !== false) {
                unset($options[$key][$index]);
                array_unshift($options[$key], $first);
            }
        }
    }
}

/** @var pdoTools $pdoTools */
$pdoTools = $modx->getService('pdoTools');
return $pdoTools->getChunk($tpl, array(
    'product'     => isset($product) ? $product->toArray() : array(),
    'options'     => $options,
    'captions'    => $captions,
    'relations'   => $relations,
    'constraints' => $constraints,
    'colors'      => $colors,
));
msProductOptions:
<?php
/** @var modX $modx */
/** @var array $scriptProperties */

$tpl = $modx->getOption('tpl', $scriptProperties, 'tpl.msOptions');
if (!empty($input) && empty($product)) {
    $product = $input;
}

$product = !empty($product) && $product != $modx->resource->id
    ? $modx->getObject('msProduct', $product)
    : $modx->resource;
if (!($product instanceof msProduct)) {
    return "[msProductOptions] The resource with id = {$product->id} is not instance of msProduct.";
}

$ignoreOptions = array_map('trim', explode(',', $modx->getOption('ignoreOptions', $scriptProperties, '')));
$onlyOptions = array_map('trim', explode(',', $modx->getOption('onlyOptions', $scriptProperties, '')));
$groups = !empty($groups)
    ? array_map('trim', explode(',', $groups))
    : array();
/** @var msProductData $data */
if ($data = $product->getOne('Data')) {
    $optionKeys = $data->getOptionKeys();
}
if (empty($optionKeys)) {
    return '';
}
$productData = $product->loadOptions();

$options = array();
foreach ($optionKeys as $key) {
    // Filter by key
    if (!empty($onlyOptions) && $onlyOptions[0] != '' && !in_array($key, $onlyOptions)) {
        continue;
    } elseif (in_array($key, $ignoreOptions)) {
        continue;
    }
    $option = array();
    foreach ($productData as $dataKey => $dataValue) {
        $dataKey = explode('.', $dataKey);
        if ($dataKey[0] == $key && (count($dataKey) > 1)) {
            $option[$dataKey[1]] = $dataValue;
        }
    }
    $option['value'] = $product->get($key);

    // Filter by groups
    $skip = !empty($groups) && !in_array($option['category'], $groups) && !in_array($option['category_name'], $groups);
    if ($skip || empty($option['value'])) {
        continue;
    }
    $options[$key] = $option;
}

/** @var pdoTools $pdoTools */
$pdoTools = $modx->getService('pdoTools');

return $pdoTools->getChunk($tpl, array(
    'options' => $options,
));
productOptions:
{if $options}  {* Проверяем на пустоту *}
    <h4 class="m-b-20">Характеристики товара</h4>
    <div class="chartable">
        {foreach $options as $option}   {* Перебираем *}
            <div class="tr">
                <div class="td">{$option.caption}</div>   {* Выводим название опции *}
                <div class="td">
                    {if $option.value is array}  {* Проверям, если значение опции является массивом *}
                        <b>{$option.value | join : ', '} {$option.measure_unit}</b>  {* то выводим с помощью разделителя *}
                    {else} {* иначе, т.е. строка, число и другое *}
                        </b>{$option.value} {$option.measure_unit}</b>    {* просто выводим *}
                    {/if}
                </div>
            </div>
        {/foreach}
    </div>
{/if}
Мартин Очоа
28 сентября 2018, 13:22
modx.pro
1 492
0

Комментарии: 0

Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
0