YandexMaps2 с напильником

На один сайт нужно яндекс карту совместимую с mFilter2. Приобрели YandexMaps2. Как оказалось, компонент не совсем подходит по наши нужды. Во первых, нужно в поиске чтоб высвечивались не только точки на карте, но и были ниже карты сами результаты поиска. Во вторых, нужно на карте выводить подпись и балун общие для всех точек. Так как это сделано на предыдущей версии сайта.

К счастью, нужный функционал оказалось не сложно допилить напильником. Под катом описание.

1. Нужно в поиске чтоб высвечивались не только точки на карте, но и были ниже карты сами результаты поиска.
В Работа с mFilter2 на шаге 3 меняют чанк tpl.mSearch2.row
{'!YandexMaps2' | snippet : [
    'parent' => $id,
    'scripts' => false,
    'tpl' => '@INLINE {($objects | toJSON) | replace : "[" : "[ "}',
]}
То есть, в результаты поиска попадают только координаты точек на карте.
И в ява-скрипте assets/components/yandexmaps2/js/web/default.js в строке
$(document).on('mse2_load', function (e, response) {
ловиться событие mse2_load mFilter2
И в строке
var results = JSON.parse('[' + response.data['results'] + ']');

и ниже эти метки добавляются на карту.
Решение
Меняем чанк tpl.mSearch2.row так
<div class="mse2-row">
	[[+idx]]. <a href="[[+uri]]" class="search-link">[[+pagetitle]]</a>[[+weight]]
	[[+intro]]
</div>

<!--msearch2_weight  ([[%mse2_weight]]: [[+weight]])-->
<!--msearch2_intro <p>[[+intro]]</p>-->
<!-- 
YandexMaps2Start{'!YandexMaps2' | snippet : [
    'parent' => $id,
    'scripts' => false,
    'tpl' => '@INLINE {($objects | toJSON) | replace : "[" : "[ "}',
]}YandexMaps2End
-->
И затем объекты карты вылавливаем из результатов поиска с помощью регулярок (YandexMaps2Start и YandexMaps2End пишем слитно без переносов строки. а то регулярки не сработают).
Меняем в ява-скрипте assets/components/yandexmaps2/js/web/default.js с 61 строки до if (typeof(results) == 'object') { на следующий код
$(document).on('mse2_load', function (e, response) {
                        if (response['success']) {
                             //console.log('YandexMaps2 mse2_load response', response);
                            var s = response.data['results'];
                            var results1 = s.match(/(?<=YandexMaps2Start)(.*?)(?=YandexMaps2End)/g);

                            //console.log(s);
                            //console.log(results1);
                            if(results1 === null){
                                results1 ="";
                            }else{
                                results1 = results1.join();
                            } 
                            var results = JSON.parse('[' + results1 + ']');
                            // var results = JSON.parse('[' + response.data['results'] + ']');
                            if (typeof(results) == 'object') {
В чанке tpl.mFilter2.outer в нужном месте выводим карту с объектами
<div class="row msearch2" id="mse2_mfilter">
	<div class="span3 col-md-3">
		<form action="[[~[[*id]]]]" method="post" id="mse2_filters">
			[[+filters]]
			
			[[+filters:isnot=``:then=`
				<button type="reset" class="btn btn-default hidden">[[%mse2_reset]]</button>
				<button type="submit" class="btn btn-success pull-right hidden">[[%mse2_submit]]</button>
				<div class="clearfix"></div>
			`]]
		</form>

		

		<div>[[%mse2_limit]]
			<select name="mse_limit" id="mse2_limit">
				<option value="10" [[+limit:is=`10`:then=`selected`]]>10</option>
				<option value="25" [[+limit:is=`25`:then=`selected`]]>25</option>
				<option value="50" [[+limit:is=`50`:then=`selected`]]>50</option>
				<option value="100" [[+limit:is=`100`:then=`selected`]]>100</option>
			</select>
		</div>
	</div>
    <div class="span9 col-md-9">
        <!-- вывод карты -->
        {var $objects = 'YM2GetObjectsFromMF2Result' | snippet : ['results' => $results]}
        {'!YandexMaps2' | snippet : [
            'objects' => $objects,
            'mode' => 'mfilter2',
        ]}
    </div>
	<div class="span9 col-md-9">
		<h3>[[%mse2_filter_total]] <span id="mse2_total">[[+total:default=`0`]]</span></h3>

		<div class="row">
			<div id="mse2_sort" class="span5 col-md-5">
				[[%mse2_sort]]
				<a href="#" data-sort="resource|publishedon" data-dir="[[+mse2_sort:is=`resource|publishedon:desc`:then=`desc`]]" data-default="desc" class="sort">[[%mse2_sort_publishedon]] <span></span></a>
			</div>

			[[+tpls:notempty=`
			<div id="mse2_tpl" class="span4 col-md-4">
				<a href="#" data-tpl="0" class="[[+tpl0]]">[[%mse2_chunk_default]]</a> /
				<a href="#" data-tpl="1" class="[[+tpl1]]">[[%mse2_chunk_alternate]]</a>
			</div>
			`]]
		</div>

		<div id="mse2_selected_wrapper">
			<div id="mse2_selected">[[%mse2_selected]]:
				<span></span>
			</div>
		</div>

		<div id="mse2_results">
			[[+results]]
		</div>

		<div class="mse2_pagination">
			[[!+page.nav]]
		</div>

	</div>
</div>
Сниппет YM2GetObjectsFromMF2Result вылавливает из результатов поиска объекты карты:
<?php
preg_match_all('|(?<=YandexMaps2Start)(.*?)(?=YandexMaps2End)|', $results, $matches);
//$modx->log(1,$results);
//$modx->log(1,print_r($matches,1));
if(isset($matches[1])){
    return implode(",",$matches[1]);
}else{
    return "";
}
Вывод mFilter2 в нужном месте
[[!mFilter2?
&parents=`[[*id]]`
&limit=`0`
&filters=`
tv|city,
tv|metro,
`
&showLog=`0`
&_filterOptions=`{«autoLoad»:0}`
&tplOuter=`tpl.mFilter2.outer2`
]]
tv|city,tv|metro подставте ваши фильтры.

Нужно на карте выводить подпись и балун общие для всех точек
Решение
Меняем сниппет YandexMaps2 добавляем параметры для подписей и балунов.
<?php
/** @var modX $modx */
/** @var YandexMaps2 $ym2 */
/** @var array $scriptProperties */
$sp = &$scriptProperties;
$modelPath = MODX_CORE_PATH . 'components/yandexmaps2/model/yandexmaps2/';
if (!$ym2 = $modx->getService('yandexmaps2', 'YandexMaps2', $modelPath)) {
    return 'Could not load YandexMaps2 class!';
}
$ym2->initialize($modx->context->key);

//
$tpl = $sp['tpl'] ?: 'tpl.YandexMaps2';
$sp['parent'] = isset($sp['parent']) ? $sp['parent'] : 0;
$sp['class'] = isset($sp['class']) ? $sp['class'] : '';
$sp['list'] = !empty($sp['list']) ? $sp['list'] : 'default';
$sp['map'] = !empty($sp['map']) ? $sp['map'] : 'ym2map';
$sp['center'] = is_array($sp['center']) ? $sp['center'] : ($ym2->tools->isJSON($sp['center']) ? $sp['center'] : ('[' . $sp['center'] . ']'));
$sp['center'] = is_array($sp['center']) ? $sp['center'] : $modx->fromJSON($sp['center']);
$sp['center'] = !empty($sp['center']) ? $sp['center'] : '[55.72, 37.64]';
$sp['zoom'] = !empty($sp['zoom']) ? $sp['zoom'] : 10;
$sp['scrollZoom'] = isset($sp['scrollZoom']) ? $sp['scrollZoom'] : true;
$sp['mode'] = strtolower(!empty($sp['mode']) ? $sp['mode'] : 'default');
$properties['iconContent'] = isset($sp['tpl.iconContent']) ? $sp['tpl.iconContent'] : '';
$properties['iconCaption'] = isset($sp['tpl.iconCaption']) ? $sp['tpl.iconCaption'] : '';
$properties['balloonContent'] = isset($sp['tpl.balloonContent']) ? $sp['tpl.balloonContent'] : '';
$includeTVs = isset($sp['includeTVs']) ? $sp['includeTVs'] : '';
unset($sp['tpl']);


//
if (isset($sp['objects'])) {
    $objects = array();
    if (!empty($sp['objects']) && !is_array($sp['objects']) && !$ym2->tools->isJSON(!$sp['objects'])) {
        $tmp = $modx->fromJSON('[' . $sp['objects'] . ']');
        foreach ($tmp as $v) {
            $objects = array_merge($objects, $v);
        }
    }
    unset($tmp);

    $objects = !empty($objects) ? $objects : array();
    $objects = is_array($objects) ? $objects : $modx->fromJSON($objects);
    $sp['objects'] = is_array($objects) ? $objects : array();
} else {
    $sp['objects'] = $ym2->getObjects(array(
        'parent' => $sp['parent'],
        'class' => $sp['class'],
        'list' => $sp['list'],
    ),$properties,$includeTVs);
}

// if ($sp['objectsPlaceholder']) {
//     //
//     if (!empty($sp['objects'])) {
//         $objects = $modx->getPlaceholder($sp['objectsPlaceholder']);
//         $objects = is_array($objects) ? $objects : ($ym2->tools->isJSON($objects) ? $modx->fromJSON($objects) : array());
//         $objects = array_merge($objects, $sp['objects']);
//         $modx->setPlaceholder($sp['objectsPlaceholder'], $modx->toJSON($objects));
//     }
//     return;
// }

if ($sp['scripts']) {
    $ym2->loadFrontendScripts('YandexMaps2', $sp);
}

//
return $ym2->tools->getChunk($tpl, $sp);
В файле core/components/yandexmaps2/model/yandexmaps2/yandexmaps2.class.php меняем функцию getObjects
public function getObjects(array $data, $properties, $includeTVs)
    {
        foreach (array('parent', 'class') as $k) {
            if (empty($data[$k])) {
                unset($data[$k]);
            }
        }

        $objects = array();
        $q = $this->modx->newQuery('ym2Map', $data);
        $q->select(array('parent as parent, objects as objects'));
        if ($q->prepare() && $q->stmt->execute()) {
            if ($rows = $q->stmt->fetchAll(PDO::FETCH_ASSOC)) {
                $this->getTools();
                foreach ($rows as $row) {
                    //$this->modx->log(1,"getObjects ".print_r($row,1));
                    $row['objects'] = !is_array($row['objects']) ? $this->modx->fromJSON($row['objects']) : $row['objects'];
                    foreach ($row['objects'] as &$o) {
                        //$this->modx->log(1,"getObjects o ".print_r($o['properties'],1));
                        if (!empty($o['properties'])) {
                            //$this->modx->log(1,"getObjects o2 ".print_r($o['properties'],1));
                            foreach (
                                array(
                                    'iconContent',
                                    'iconCaption',
                                    'balloonContent',
                                ) as $k
                            ) {
                                if (!empty($o['properties'][$k])) {
                                    $o['properties'][$k] = $this->tools->getChunk('@INLINE:' . $o['properties'][$k], array(
                                        'data' => array_merge($data, array(
                                            'parent' => $row['parent'],
                                        )),
                                    ));
                                }
                            }
                        }else{
                            //$this->modx->log(1,"getObjects 1 ".print_r($properties,1));
                            //Добавлено это
                            foreach (
                                array(
                                    'iconContent',
                                    'iconCaption',
                                    'balloonContent',
                                ) as $k
                            ) {
                                if (!empty($properties[$k])) {
                                    $this->modx->log(1,"getObjects ".print_r($properties,1));
                                    $o['properties'][$k] = $this->modx->runSnippet('pdoResources',array(
                                                               'resources' => $row['parent'],
                                                               'tpl' => $properties[$k],
                                                               'includeTVs'=>$includeTVs,
                                                            ));
                                    //$this->modx->log(1,"getObjects o ".print_r($o['properties'],1));
                                    /*$o['properties'][$k] = $this->tools->getChunk($properties[$k], array(
                                        'data' => array_merge($data, array(
                                            'parent' => $row['parent'],
                                        )),
                                    ));*/
                                }
                            }
                        }
                    }
                    unset($o);
                    $objects = array_merge($objects, $row['objects']);
                }
            }
        }

        return $objects;
    }
}
В чанке tpl.mSearch2.row прописываем параметры балуна и tv:
<div class="mse2-row">
	[[+idx]]. <a href="[[+uri]]" class="search-link">[[+pagetitle]]</a>[[+weight]]
	[[+intro]]
</div>

<!--msearch2_weight  ([[%mse2_weight]]: [[+weight]])-->
<!--msearch2_intro <p>[[+intro]]</p>-->
<!-- 
YandexMaps2Start{'!YandexMaps2' | snippet : [
    'parent' => $id,
    'scripts' => false,
    'tpl' => '@INLINE {($objects | toJSON) | replace : "[" : "[ "}',
    'tpl.balloonContent' =>'tpl.balloonContent',
    'tpl.iconCaption' => 'tpl.iconCaption',
    'includeTVs'=>'metro',
]}YandexMaps2End
-->
Чанк tpl.balloonContent:
<p>id {$id}</p>
<p>pagetitle {$pagetitle}</p>
<p>metro [[+tv.metro]]</p>
Страница поиска пока выглядит так
Александр
26 октября 2018, 09:05
14
307
+17

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

Паша
27 октября 2018, 14:13
0
Круто!