Александр Туниеков

Александр Туниеков

С нами с 19 декабря 2015; Место в рейтинге пользователей: #15
Александр Туниеков
18 ноября 2018, 19:26
+1
Компонент дорабатывается и это хорошо :). Единственно со времени публикации статьи было еще несколько важных правок. Только времени описать их не было. Опишу на скорую руку что помню, надеюсь, это вам поможет в совершенствовании YandexMaps2.
1. Вызов
$o['properties'][$k] = $this->modx->runSnippet('pdoResources',array(
                                                               'resources' => $row['parent'],
                                                               'tpl' => $properties[$k],
                                                               'includeTVs'=>$includeTVs,
                                                            ));
не очень хорошая идея. Как выяснилось на каждый объект в результатах поиска приходиться более десятка вызовов в базу данных. Что, конечно, тормозит работу сайта. Более разумное решение присоединить все что можно к основному запросу и потом вытащить из него нужные данные.

[[!mFilter2?
&paginator=`pdoPage`
&ajaxMode=`button`
&parents=`[[*id:is=`38`:then=`4`:else=`[[*id]]`]]`
&element=`pdoResources`
&hideContainers=`1`
&tpl=`my.tpl.mSearch2.row`
&includeTVs=`price_from,city,district,county,metro,room_facilities,hot_offer,region`
&tvPrefix=``
&class=`modResource`
&loadModels=`ms2Gallery,yandexmaps2,citystruct,easycomm`
&leftJoin=`{
	"ym2Map": {
		"class":"ym2Map",
		"alias":"ym2Map",
		"on": "ym2Map.parent = modResource.id AND ym2Map.class = 'modDocument'"
	},
	"medium1":{
	    "class":"msResourceFile",
	    "alias":"medium1",
	    "on":"medium1.resource_id = modResource.id AND medium1.parent != 0 AND medium1.path LIKE '%\/small\/%' AND medium1.active = 1 AND medium1.rank = 0"
	},
	"ecThread": {
		"class":"ecThread",
		"alias":"ecThread",
		"on": "ecThread.name = CONCAT('resource-',modResource.id)"
	},
	"CSDistrict": {
		"class":"CSDistrict",
		"alias":"CSDistrict",
		"on": "CSDistrict.id = TVdistrict.value"
	},
	"CSCounty": {
		"class":"CSCounty",
		"alias":"CSCounty",
		"on": "CSCounty.id = TVcounty.value"
	},
	"CSRegion": {
		"class":"CSRegion",
		"alias":"CSRegion",
		"on": "CSRegion.id = TVregion.value"
	}
}`
&select=`{
	"modResource":"*",
	"medium1":"medium1.url as medium,medium1.name as medium_name,medium1.alt as medium_alt",
	"ym2Map":"objects",
	"ecThread":"rating_simple",
	"CSDistrict":"CSDistrict.name as district_name",
	"CSCounty":"CSCounty.name as county_name",
	"CSRegion":"CSRegion.name as region_name"
}`
&groupby=`modResource.id`
&limit=`30`
&filters=`
tv|price_from:number,
parent:categories,
tv|city,
tv|region,
tv|district,
tv|county,
tv|metro,
tv|room_facilities,
`
&aliases=`
        tv|price_from==price,
        tv|city==city,
        tv|region==region,
        tv|district==district,
        tv|county==county,
        tv|metro==metro,
        tv|room_facilities==room_facilities,
    `
&tplFilter.outer.default=`my.tpl.mFilter2.filter.outer`
&tplFilter.row.default=`my.tpl.mFilter2.filter.checkbox`

&tplFilter.outer.price=`my.tpl.mFilter2.filter.slider`
&tplFilter.row.price=`tpl.mFilter2.filter.number`

&tplFilter.row.city=`tpl.mFilter2.filter.city`
&tplFilter.row.region=`tpl.mFilter2.filter.region`
&tplFilter.row.metro=`tpl.mFilter2.filter.metro`
&tplFilter.row.district=`tpl.mFilter2.filter.district`
&tplFilter.row.county=`tpl.mFilter2.filter.county`
&tplOuter=`tpl.mFilter2.outer3`
]]
Присоединяем
"ym2Map": {
		"class":"ym2Map",
		"alias":"ym2Map",
		"on": "ym2Map.parent = modResource.id AND ym2Map.class = 'modDocument'"
	},
и выбираем колонку с данными объектов карты «ym2Map»:«objects».
Чанк my.tpl.mSearch2.row
<div class="mse2-row">
    <!-- Блок номера -->
    <div class="block">
        <h2><a href="{$uri}">{$pagetitle}</a></h2>
        <a href="{$uri}">
        <div class="img">
            {if $hot_offer}
            <div class="fire">
                <svg width="134pt" viewBox="0.031285762786865234 0 89.66130065917969 134.0590057373047" height="134pt" xmlns="http://www.w3.org/2000/svg" data-type="shape" role="img" preserveAspectRatio="xMidYMid meet" style="stroke-width: 0px;">
                    <g>
                        <path d="M23.348 134.059C8.445 84.953 39.934 67.023 39.934 67.023 37.73 93.227 52.62 113.641 52.62 113.641c5.477-1.653 15.93-9.375 15.93-9.375 0 9.375-5.516 29.78-5.516 29.78s19.309-14.929 25.387-39.726c6.07-24.797-11.563-49.691-11.563-49.691a66.494 66.494 0 0 1-16.507 48 9.514 9.514 0 0 0 1.445-2.227c2.09-4.18 5.445-15.043 3.48-40.199C62.512 14.891 30.516 0 30.516 0c2.757 21.516-5.512 26.473-24.883 67.313-19.371 40.832 17.715 66.746 17.715 66.746zm0 0"></path>
                    </g>
                </svg>
            </div>
            {/if}
            
                <img src="{if $medium}{$medium}{else}{('assets_url' | option) ~ 'components/ms2gallery/img/web/ms2_medium.png'}{/if}" 
                alt="{$medium_alt}" title="{$medium_name}"/>
            
        </div>
        </a>
        <div class="right">
            <h2>{$pagetitle}</h2>
            {var $rating_simple_pr = $rating_simple/5*100}
            <div class="ec-stars" title="{$rating_simple}" itemscope itemtype="http://schema.org/AggregateRating">
                <span style="width: {$rating_simple_pr}%"></span>
            </div>
            {var $metroes = 'getMetroesName' | snippet : ['metro'=>$metro,'tpl'=>'getMetroesName']}
            <ul>
                {if $metroes}
                <li><span>Метро:</span>
                    
                    {$metroes}
                </li>
                {/if}
                {if $region && $region != 1}
                <li><span>Область:</span> 
                    
                        <a href="{$_modx->makeUrl($_modx->resource.id,'',['region'=>$region])}">{$region_name}</a>
                    
                </li>
                {/if}
                {if $county}
                <li><span>Округ:</span> 
                    
                        <a href="{$_modx->makeUrl($_modx->resource.id,'',['county'=>$county])}">{$county_name}</a>
                    
                </li>
                {/if}
                {if $district}
                <li><span>Район:</span>
                    
                        <a href="{$_modx->makeUrl($_modx->resource.id,'',['district'=>$district])}">{$district_name}</a>
                    
                </li>
                {/if}
            </ul>
            <div class="price">{$price_from} &#8381;/сутки</div>
            <div class="btn modal_booking_hotel" data-hotel_id="{$id}" data-hotel_pagetitle="{$pagetitle}">Бронировать</div>
        </div>
    </div>
</div>

{if count($objects) > 0}
    {foreach $objects as $k => $o}
        {var $objects.$k.properties.balloonContent = $_modx->parseChunk('tpl.balloonContent', [
            'id' => $id,
            'uri' => $uri,
            'pagetitle' => $pagetitle,
            'metroes' => $metroes,
            'district' => $district,
            'district_name' => $district_name,
            'county' => $county,
            'county_name' => $county_name,
            'price_from' => $price_from,
            'hot_offer' => $hot_offer,
            'rating_simple' => $rating_simple,
            'region' => $region,
            'region_name' => $region_name,
        ])}
        {if $price_from}
            {var $objects.$k.options.price_from = $price_from}
        {/if}
    {/foreach}
<!-- 
YandexMaps2Start{($objects | toJSON) | replace : "[" : "[ "}YandexMaps2End
-->
{/if}
{if count($objects) > 0}
    {foreach $objects as $k => $o}
        {var $objects.$k.properties.balloonContent = $_modx->parseChunk('tpl.balloonContent', [
            'id' => $id,
            'uri' => $uri,
            'pagetitle' => $pagetitle,
            'metroes' => $metroes,
            'district' => $district,
            'district_name' => $district_name,
            'county' => $county,
            'county_name' => $county_name,
            'price_from' => $price_from,
            'hot_offer' => $hot_offer,
            'rating_simple' => $rating_simple,
            'region' => $region,
            'region_name' => $region_name,
        ])}
        {if $price_from}
            {var $objects.$k.options.price_from = $price_from}
        {/if}
    {/foreach}
<!-- 
YandexMaps2Start{($objects | toJSON) | replace : "[" : "[ "}YandexMaps2End
-->
{/if}
дебаем балун и выводим объекты карты в результаты поиска

Чанк tpl.mFilter2.outer3
<div class="row msearch2" id="mse2_mfilter">
        <div id="main_image">
        {var $objects = 'YM2GetObjectsFromMF2Result' | snippet : ['results' => $results]}
        {'!YandexMaps2' | snippet : [
            'objects' => $objects,
            'mode' => 'mfilter2',
            'jquery' => '0',
        ]}
        </div>

        <div id="title_paginate">
          <div class="container">
              <svg height="512" width="512" viewBox="0 9.045000076293945 193.14199829101562 175.0540008544922" xmlns="http://www.w3.org/2000/svg" data-type="color" role="img" preserveAspectRatio="xMidYMid meet" style="">
                <g>
                    <path fill="#fc4e19" d="M185.142 24.931v15.421a18.126 18.126 0 0 0-10.234-3.153h-34.887V24.931h-8v12.268H66.617v-2.371c0-9.374-7.626-17-17-17H28.266c-9.374 0-17 7.626-17 17v3.761A18.14 18.14 0 0 0 8 40.351V9.045H0v175.054h8v-16.643h124.021v16.643h8v-16.643h45.121v16.643h8V24.931h-8zm-10.235 20.267c5.643 0 10.234 4.591 10.234 10.234v2.258H140.02V45.198h34.887zm-42.886 33.05v48.157H66.617v-2.372c0-9.374-7.626-17-17-17H28.266c-9.374 0-17 7.626-17 17v3.762A18.208 18.208 0 0 0 8 129.557v-51.31h124.021zM18.234 134.405H132.02v12.491H8v-2.258c0-5.642 4.591-10.233 10.234-10.233zm121.787 0h34.887c2.581 0 4.936.968 6.738 2.551h-41.625v-2.551zm0 12.491v-1.94h45.121v1.94h-45.121zm34.886-20.491H140.02v-8.129h45.121v11.282a18.126 18.126 0 0 0-10.234-3.153zm10.235-16.129h-45.121V91.598h45.121v18.678zm0-26.678h-45.121v-5.35h45.121v5.35zm-166.908-38.4H132.02V57.69H8v-2.258c0-5.643 4.591-10.234 10.234-10.234z" data-color="1"></path>
                </g>
              </svg>
              <div class="paginate">
                  <h1 class="zg">[[*pagetitle]]</h1>
                  [[!pdoMenu?
                    &parents=`4`
                    &resources=`-[[*id]]`
                    &level=`1`
                    &tpl=`mFilter2.tpl.menu`
                    ]]
              </div>
            </div>
        </div>

        <div class="container">
            <div id="sort">
                <div class="left">
                    <div id="mse2_sort" class="span5 col-md-5">
        				<a href="#" data-sort="price" data-dir="[[+mse2_sort:is=`price:desc`:then=`desc`]]" data-default="desc" class="sort">ПО ЦЕНЕ <span></span></a>
        				<a href="#" data-sort="rating_simple" data-dir="[[+mse2_sort:is=`rating_simple:desc`:then=`desc`]]" data-default="desc" class="sort">ПО РЕЙТИНГУ <span></span></a>
        			</div>
                </div>
                <div class="right">
                    <a class="bloch active" href="#">
                      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19 19" id="view-grid" width="100%" height="100%"><path d="M0 0h8v8H0zm11 0h8v8h-8zm0 11h8v8h-8zM0 11h8v8H0z"></path></svg>
                    </a>
                    <a class="liners" href="#">
                      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 19" id="view-list" width="100%" height="100%"><path d="M0 0h8v8H0zm11 0h14.004v8H11zm0 11h14.004v8H11zM0 11h8v8H0z"></path></svg>
                    </a>
                </div>
            </div>

            <div class="main_aside">
                <main>
                    <div id="list_of_places">
                        <div id="mse2_results">
                			[[+results]]
                		</div>
                		<div class="mse2_pagination">
                			[[!+page.nav]]
                		</div>
                    </div>
                </main>
                <aside>
                    <div id="filter">
                        <div class="top">
                            <span>ФИЛЬТР ПОИСКА</span>

                            <svg xmlns="http://www.w3.org/2000/svg" width="512pt" viewBox="0 0 512 511.9999694824219" height="512pt" data-type="shape" role="img" preserveAspectRatio="xMidYMid meet" style="stroke-width: 0px;">
                              <g>
                                  <path d="M302 90c-66.184 0-120 53.832-120 120s53.816 120 120 120 120-53.832 120-120S368.184 90 302 90zm70.605 100.605l-75 75c-2.93 2.93-6.77 4.395-10.605 4.395s-7.676-1.465-10.605-4.395l-45-45c-5.86-5.859-5.86-15.351 0-21.21s15.351-5.86 21.21 0L287 233.789l64.395-64.394c5.859-5.86 15.351-5.86 21.21 0s5.86 15.351 0 21.21zm0 0"></path>
                                  <path d="M4.395 443.973c-5.86 5.859-5.86 15.351 0 21.21l42.421 42.422c2.93 2.93 6.77 4.395 10.606 4.395s7.676-1.465 10.605-4.395l75.184-75.183-63.633-63.633zm0 0"></path>
                                  <path d="M302 0C186.219 0 92 94.203 92 210c0 41.637 12.328 80.375 33.313 113.055l-24.524 24.523 63.633 63.633 24.523-24.524C221.625 407.673 260.367 420 302 420c115.781 0 210-94.203 210-210S417.781 0 302 0zm0 360c-82.707 0-150-67.297-150-150S219.293 60 302 60c82.703 0 150 67.297 150 150s-67.297 150-150 150zm0 0"></path>
                              </g>
                            </svg>
                        </div>
                        <div class="bottom">
                            <form action="[[~[[*id]]]]" method="post" id="mse2_filters">
                    			[[+filters]]
                    			<button type="reset" class="reset" class="btn btn-default hidden">Сбросить</button>
                    		</form>
                            
                        </div>
                    </div>
                </aside>
            </div>
        </div>
</div>
{var $objects = 'YM2GetObjectsFromMF2Result' | snippet : ['results' => $results]}
        {'!YandexMaps2' | snippet : [
            'objects' => $objects,
            'mode' => 'mfilter2',
            'jquery' => '0',
        ]}
Вытаскиваем из результатов поиска и выводим на карту.
Скрипт assets/components/yandexmaps2/js/web/default.js
(function () {
    function YandexMaps2(options) {
        //
        ['map'].forEach(function (val, i, arr) {
            if (typeof(options[val]) == 'undefined' || options[val] == '') {
                console.error('[YandexMaps2] Bad config.', arr);
                return;
            }
        });

        //
        var self = this;
        self['initialized'] = false;
        self['running'] = false;

        /**
         * Инициализирует класс.
         * @returns {boolean}
         */
        self.Initialize = function (options) {
            if (!self['initialized']) {
                //
                self['config'] = {
                    map: 'ym2map',
                    center: [55.72, 37.64],
                    zoom: 10,
                };
                self['classes'] = {};
                self['selectors'] = {};

                //
                Object.keys(options).forEach(function (key) {
                    if (['selectors'].indexOf(key) !== -1) {
                        return;
                    }
                    self.config[key] = options[key];
                });
                ['selectors'].forEach(function (key) {
                    if (options[key]) {
                        Object.keys(options[key]).forEach(function (i) {
                            self.selectors[i] = options.selectors[i];
                        });
                    }
                });
            }
            self['initialized'] = true;

            return self['initialized'];
        };

        /**
         * Запускает основные действия.
         * @returns {boolean}
         */
        self.Run = function () {
            if (self['initialized'] && !self['running']) {
                ymaps.ready(self.Map['initialize']);
                // console.log('self.Run self', self);

                if (self.config['mode'] == 'mfilter2' || self.config['mode'] == 'mfilter') {
                    $(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 + ']');
                            if (typeof(results) == 'object') {
                                var objects = [];
                                for (var a in results) {
                                    if (!results[a]['length']) {
                                        continue;
                                    }
                                    for (var b in results[a]) {
                                        objects.push(results[a][b]);
                                    }
                                }
                                self.Map.clean(function () {
                                    self.Map.addObjects(objects);
                                });
                            }
                        }
                    });
                }
            }
            self['running'] = true;

            return self['running'];
        };

        /**
         * Колбеки
         */
        self.Callbacks = {
            onLoad: function () {
                var self = this;
                // console.log('JS onLoad self', self);

                var objects = ('objects' in self['config']) ? self.config['objects'] : [];
                // console.log('JS onLoad objects', objects);

                objects.forEach(function (o) {
                    self.Map.addObject(o);
                });
                self['map'].setBounds(self.map['geoObjects'].getBounds(), {checkZoomRange:true}).then(function(){ if(self['map'].getZoom() > 10) self['map'].setZoom(10);});
            },
        };

        /**
         * Действия с картой
         */
        self.Map = {
            /**
             * Инициализация карты
             */
            initialize: function () {
                self['map'] = new ymaps.Map(self.config['map'], {
                    center: self.config['center'],
                    zoom: self.config['zoom'],
                }, {
                    searchControlProvider: 'yandex#search',
                });

                self.Callbacks.onLoad.bind(self)();

                // Отключаем зуммирование при скролле
                if (!self.config['scrollZoom']) {
                    self['map'].behaviors.disable('scrollZoom');
                }
            },

            /**
             * Добавляем на карту объекты
             */
            addObjects: function (objects) {
                objects.forEach(function (o) {
                    self.Map.addObject(o);
                });
                self['map'].setBounds(self.map['geoObjects'].getBounds(), {checkZoomRange:true}).then(function(){ if(self['map'].getZoom() > 10) self['map'].setZoom(10);});
            },

            /**
             * Добавляем на карту объект (ломаная линия, многоугольник, круг, точка)
             */
            addObject: function (arg) {
                var o;
                var type = arg['type'];
                var geometry = arg['geometry'];
                var options = $.extend({}, arg['options']);
                var properties = $.extend({}, arg['properties']);
                // console.log('properties', properties);

                //
                switch (type) {
                    case 'placemark':
                        if(options.price_from  !== undefined){
                            if(options.price_from  !== 0){
                                var iconColor = '#ef790f';
					            var iconImageHref = '/assets/templates/img/placemark.svg';
					            var placemarkLayout = ymaps.templateLayoutFactory.createClass(
					                '<div class="marker-layout"><div class="marker-layout__text">от '+
					                options.price_from +' &#8381;</div></div>');
					           options = {
            						iconLayout: placemarkLayout,
            						iconShape: {
            							type: 'Rectangle',
            							coordinates: [
            								[-40, -40], [40, -5]
            							]
            						}
            					};
                            }
                        }
                        //console.log(options);
                        o = new ymaps.Placemark(geometry, properties, options);
                        break;

                    case 'polyline':
                        o = new ymaps.Polyline(geometry, properties, options);
                        break;

                    case 'polygon':
                        o = new ymaps.Polygon(geometry, properties, options);
                        break;

                    case 'circle':
                        o = new ymaps.Circle(geometry, properties, options);
                        break;
                }

                // Добавляем на карту и в массив
                self.map['geoObjects'].add(o);

                return o;
            },

            /**
             * Очищает карту.
             */
            clean: function (callback) {
                // var tmp = [];
                // self.map['geoObjects'].each(function (o) {
                //     tmp.push(o);
                // });
                // tmp.forEach(function (o) {
                //     self.map['geoObjects'].remove(o);
                // });
                // delete tmp;
                self.map['geoObjects'].removeAll();

                callback.bind(self)();
            }
        };

        /**
         * Сообщения.
         * @type {object}
         */
        self.Message = {
            success: function (message) {
            },
            error: function (message) {
                alert(message);
            }
        };

        /**
         * Инструменты.
         * @type {object}
         */
        self.Tools = {};

        /**
         * Initialize && Run!
         */
        if (self.Initialize(options)) {
            self.Run();
        }
    }

    window.YandexMaps2 = YandexMaps2;
})();
Изменилась регулярка чтоб она работала в safary
var results1 = s.match(/(?=YandexMaps2Start)(.*?)(?=YandexMaps2End)/g);

Маштабировать и центрировать карту чтобы все объекты на нее влезали
self['map'].setBounds(self.map['geoObjects'].getBounds(), {checkZoomRange:true}).then(function(){ if(self['map'].getZoom() > 10) self['map'].setZoom(10);});
И свой тип метки на карте
if(options.price_from  !== undefined){
                            if(options.price_from  !== 0){
                                var iconColor = '#ef790f';
					            var iconImageHref = '/assets/templates/img/placemark.svg';
					            var placemarkLayout = ymaps.templateLayoutFactory.createClass(
					                '<div class="marker-layout"><div class="marker-layout__text">от '+
					                options.price_from +' &#8381;</div></div>');
					           options = {
            						iconLayout: placemarkLayout,
            						iconShape: {
            							type: 'Rectangle',
            							coordinates: [
            								[-40, -40], [40, -5]
            							]
            						}
            					};
                            }
                        }
Еще чтобы работал поиск как надо надо поправить ошибки в pdoTools
Файл core/components/pdotools/model/pdotools/pdofetch.class.php
Функция addSelects строка примерно 367:
if ($i == 0 && $this->config['setTotal']) {
                    if (is_string($fields)){
                        $fields = 'SQL_CALC_FOUND_ROWS ' . $fields;
                    }else{
                        $fields = 'SQL_CALC_FOUND_ROWS ' . implode(",",$fields);
                    }
                }
$fields = 'SQL_CALC_FOUND_ROWS '. implode(",",$fields); это чтобы в запрос не попадало SQL_CALC_FOUND_ROWS Arroy

Функция addJoins строка примерно 304
$tmp = array_merge($this->config['tvsJoin'], $tmp);
Здесь поменял порядок присоединения таблиц чтоб tv присоединялись раньше чем все остальное. Иначе mySQL ругается на CSDistrict.id = TVdistrict.value. TVdistrict присоединяется позже и типо ему оно не известно. Надо чтоб лефтджоин с TVdistrict был раньше уже сделан.

Ну вот что помню :). Надеюсь это поможет вам и остальным разработчикам :)
Александр Туниеков
08 октября 2018, 21:13
0
А вот эти строки
$modx = new modX();
$modx->initialize('mgr');
$modx->getService('error','error.modError');
точно нужны? Я делал другой плагин копируя этот и у меня из-за них возникала проблема что не находит xpdo классы компонентов. Не понятно зачем нужна вообще здесь инициализация нового объекта $modx
Александр Туниеков
12 сентября 2018, 12:58
+1
В файле схемы были не правильно заданы типы полей phptype. Вместо text поставил string и все заработало. На рабочем сайте обновите компонент и проверяйте как там работает.
В emailqueue.mysql.schema.xml вместо этого
<field key="body" dbtype="text" phptype="text" null="true" default=""/>
<field key="attachments" dbtype="text" phptype="text" null="true" default=""/>
сделал это
<field key="body" dbtype="text" phptype="string" null="true" default=""/>
<field key="attachments" dbtype="text" phptype="string" null="true" default=""/>
Я эти поля как в modExtra сделано так и делал.
Александр Туниеков
12 сентября 2018, 12:03
0
Сделайте плиз если не трудно. у меня на php 7.2 ничего тестового нет
Александр Туниеков
12 сентября 2018, 11:40
0
Здравствуйте! Вот чтоб именно пустое поле получилось вообще странно :(. Пока скачиваю Опенсервер новый. Попробую поставить PHP 7.2.00 и посмотреть.
Хм. Он 3 часа обещает скачиваться. Может все таки дадите доступ к вашему MODX?
Александр Туниеков
08 сентября 2018, 01:06
0
А нашел. просто раньше не пролистал вниз вкладку :(
Александр Туниеков
08 сентября 2018, 00:37
0
Это к чему вообще? :) Каюсь по ссылке не досмотрел, но ругань все равно не понятная :)
Кстати а как через менеджер MIGX inputTV проставить? я только через правку JSON конфига сделал.
Александр Туниеков
08 сентября 2018, 00:06
0
Ищи в поиске migx внутри migx
например https://www.youtube.com/watch?v=_CFCr_embNw
Я недавно делал migx внутри migxdb :)
Александр Туниеков
06 сентября 2018, 09:22
0
Правила приема приложений в App Store
Редакция МОЖЕТ отклонить приложения, которые:
2.11 повторяют приложения которые уже есть в App Store, особенно если их там уже много, например: фонарики, Кама Сутры, пукающие приложения.
Хорошее правило, но явно не запрет прямых аналогов.
в лучшем случае авторы зарабатывают десятки тысяч в месяц и лучше пусть один автор получает денюжку но делает безупречный продукт и имеет стимул его совершенствовать
Прямо реклама монополии :). Всю жизнь учили, что конкуренция лучше, а тут прямым текстом монополия лучше :). Я отстал от жизни? Монополия в ИТ лучше?
Мне кажется, что монополия провоцирует не совершенствовать продукт, а просто сидеть и стричь денежки :).
Если вдруг на мой компонент появиться конкурент и продажи упадут вдвое, то я, скорее всего, увеличу стоимость компонента вдвое. В расчете на то, что конкуренту тоже надо отбивать вложения, и так как, сложный компонент дорого делать, то конкурент тоже подымет стоимость.
Александр Туниеков
06 сентября 2018, 08:40
0
А чем вам эта идея не нравиться? Стандартным импортом минишоп пользуются. Если будет компонент который будет позволять им пользоваться без танцев в бубном, то им тоже будут пользоваться.
А по факту, я почти на 100% уверен, что если вы сделаете стоящий и сложный компонент, который пусть и содержит идеи других авторов но выполняет их на голову выше — модерация его одобрит, а сообщество похлопает
А я вот не уверен. В правилах четко написано никаких прямых аналогов. Значит никаких. А то что за произвол? Это понравилось одобрим, а это не одобрим. И вдруг стоящий и сложный компонент чуть чуть не дотянет и его не одобрят, а время то на сложный надо много :(.
Александр Туниеков
05 сентября 2018, 16:26
0
Владельцы MODSTORE обычно сначала интересуются мнением авторов аналогичных платных дополнений. И если автор против нового компонента (обоснованно), то магазин отказывает в публикации. Это уже много раз обсуждалось.
Можно ссылки где это обсуждалось. Что-то я не верные слова в поиск забиваю.
Александр Туниеков
05 сентября 2018, 16:16
0
Очень заинтересован, как можно ознакомиться с демо компонента?
Мой компонент UserTest. По крайней мере требовалось сделать статистику тестов. Сколько на что сдали и т.д. с диаграммами. Сейчас заказчик в отпуске и говорит не знает требуется ли еще статистика.
Вы в разработке этого компонента заинтересованы? Или в чем заинтересовались? :)
Александр Туниеков
05 сентября 2018, 16:09
0
Есть и минусы и плюсы.
1 минус. Как в моем случае, нельзя просто дополнение выпустить. Надо еще и сам функционал компонента под статистику доработать.
2 минус. Клиентам 2 дополнения придется ставить.
3 минус. Функционал компонента может измениться и дополнение станет не совместимым. Если в одном компоненте, то там это отслеживаешь, чтоб компонент был полностью рабочим. А в дополнении хата не моя и не знаю что там твориться :).
1 плюс как вы сказали
автор отвечает на вопросы по своему функционалу, а вы по своему
2 плюс если клиенту не нужна статистика он ее просто может не покупать.

В целом мне было бы интересней и клиентам удобней в одном компоненте. Только админам Modstore под группы разработчиков переделывать магазин — это много работы. Наверно они на это не пойдут :(.
Александр Туниеков
05 сентября 2018, 15:49
0
Понятие прямого аналога все таки нечеткое. Допустим компонент msImportExport. Например я сделаю просто кнопку в админке для импорта товаров через стандартный скрипт минишопа http://webcandy.ru/manuals/import-csv-minishop2/. Плюс доработаю на долгую обработку, чтоб не обрывало при импорте многих товаров. Это будет считаться прямым аналогом?
Здесь в
в упрощенном режиме
а в msImportExport
бОльший функционал
Александр Туниеков
31 августа 2018, 18:50
+2
Вообще есть тема такая. У меня есть заказ на доработку моего компонента. Прикрутить статистику тестов. Доработка не идет. Не складывается. Мне было бы удобно найти разраба, который бы эту доработку сделал. Но права на компонент и деньги за него я терять не хочу. Мне было бы удобно, если в модсторе были бы группы разработчиков и оплата за компонент перечислялась каждому разрабу по договеренности. Например сейчас компонент стоит 1990р другой разраб делает статистику, получает деньги от заказчика доработки и говорит 200р ему от продаж компонента. Наценяем компонент на 200р и от продаж мне падает 1990 а ему 200р.
Некоторые разработчики перестают развивать свои компоненты. Некогда или интерес пропал. Вышеописанная идея как раз для них подойдет.
Открытое ПО как раз и ценно тем, что его дорабатывать может кто захочет. А запрет на прямые аналоги эту ценность прибивают.
Александр Туниеков
31 августа 2018, 18:29
+1
Ну мне главное не продавать компонент, а разнообразие доступных компонентов. Доступных в смысле посмотрел в магазине, что есть и выбрал, что более подходит. Я не все топики читаю неудобно по ним рыться. Да и компонент в модсторе гарантия, что перечислил кому-то левому деньги и не фига не получил. И для разраба удобнее через магазин. Гарантирует, что деньги получишь.
Александр Туниеков
31 августа 2018, 17:49
+1
Кажется это сделано для того, чтобы разработчики не воровали код у друг друга. Код то открытый и в компоненте, при желании, можно восстановить билд, переименовать компонент и продавать как свой.
Но лучше с воровством бороться как-нибудь другим методом :(. Разнообразие компонентов нужно.
Пишите комментарии. 2 отзыва маловато, чтоб на администраторов modstore повлиять.
Александр Туниеков
12 августа 2018, 22:56
0
у phpThumbOn качество по умолчанию стоит 0.9 и я его не менял. А вот OptiPic этот же файл сжал на 67%
Александр Туниеков
12 августа 2018, 21:08
0
У меня при загрузке в ms2Gallery картинки не загружались. Поправил следующим образом.
В файле core/components/tinycompressor/model/tinycompressor/tinycompressor.class.php
это
function createTinyPNG() {

        require_once $this->config['modelPath'] . '/tinycompressor/lib/tinify/init_tinify.php';
        $this->tinyPNGClient = (empty(trim($this->config['tinyPNGApiKey'])) ) ? false : new Tinify\Client($this->config['tinyPNGApiKey']);
        $this->tinyPNGCrazyClient = new Tinify\CrazyClient();
        return true;
    }

    function createILovePDF()
    {
        require_once $this->config['modelPath'] . '/tinycompressor/lib/ilovepdf/init_ilovepdf.php';
        $this->iLovePDF = (empty(trim($this->config['iLovePDFProjectID'])) || empty(trim($this->config['iLovePDFProjectKey'])) ) ? false : new Ilovepdf\Ilovepdf($this->config['iLovePDFProjectID'], $this->config['iLovePDFProjectKey']);

        return true;

    }
заменил на это
function createTinyPNG() {

        require_once $this->config['modelPath'] . '/tinycompressor/lib/tinify/init_tinify.php';
        $t = trim($this->config['tinyPNGApiKey']);
        $this->tinyPNGClient = (empty($t) ) ? false : new Tinify\Client($this->config['tinyPNGApiKey']);
        $this->tinyPNGCrazyClient = new Tinify\CrazyClient();
        return true;
    }

    function createILovePDF()
    {
        require_once $this->config['modelPath'] . '/tinycompressor/lib/ilovepdf/init_ilovepdf.php';
        $t1 = trim($this->config['iLovePDFProjectID']);
        $t2 = trim($this->config['iLovePDFProjectKey']);
        $this->iLovePDF = (empty($t1) || empty($t2) ) ? false : new Ilovepdf\Ilovepdf($this->config['iLovePDFProjectID'], $this->config['iLovePDFProjectKey']);

        return true;

    }
Теперь работает, но сервис после phpTrumbOn картинки меньше не делает.


PageSpeed Insights ругается, что картинки можно сжать еще. В итоге компонент мне не подходит. Буду пробовать OptiPic
Александр Туниеков
12 августа 2018, 18:54
0
Т.е. я не знаю зачем это нужно, поэтому удалю нафиг?
Да :). Там где это точно не на что не повлияет. Просто имя кеша будет другое и все. А в сам $scriptProperties не трогаю. Я ведь верно понимаю, что удаление из переменной $options внутри функции на $scriptProperties не влияет? И в остальном коде setTotal присутствует?
Не знаю в каких. Наверно не в каких, но если вдруг где-то еще кеш используется, то очистка зависимости имени файла кеша от request не помешает.
И вообще включите на гитхабе issue и я бы вообще в этот код не лез.