• Как оптимизировать сложные проверки в Entity?

    @dzhebrak
    Как вариант, можно вынести только проверку в отдельный сервис в доменном слое (Domain Layer), и этот сервис передавать как аргумент в метод add() вашей сущности. Если этот сервис бросит исключение, то метод add прекращает выполнение. В сервис передавать в конструкторе репозиторий или другой объект, который подгрузит необходимые для проверки данные.

    Далее вынести вызов метода add() в сервис на уровне приложения (Application Layer), как вы написали, в котором и передавать ранее созданный сервис проверки в метод add().

    В такой реализации вам всегда будет необходим этот доменный сервис, и вызвать метод add() без него не получится.

    Пример:
    class Entity
    {
    	public function add(ComplexEntityValidator $validator) {
    		$validator->validate();
    	}
    }
    
    class ComplexEntityValidator
    {
    	public function __construct(EntityRepository $repository) {
    
    	}
    
    	public function validate() {
    		// проверка
    	}
    }
    
    class EntityApplicationService
    {
    	public function __construct(ComplexEntityValidator $validator) {
    
    	}
    
    	public function __invoke() {
    		$entity = new Entity();
    		$entity->add($validator);
    		// сохранение сущности
    	}
    }
    Ответ написан
    3 комментария
  • Как сделать очередь на PHP по работе с CRM системой?

    @dzhebrak
    Готовых вариантов для динамического создания воркеров, к сожалению, нет (или по крайней мере я никогда не сталкивался с такими). Можно сделать следующим образом.

    В базе данных сделайте таблицу для очереди, в которой одним из столбцов будет номер аккаунта клиента.
    При получении вебхука не обрабатывайте (т.е. не делайте запросы к crm) его сразу, а только сохраняйте в вышеуказанную таблицу.
    Напишите скрипт, который будет запускаться раз в минуту по крону. Этот скрипт должен получить уникальные аккаунты (DISTINCT) из таблицы очереди и запустить все обработчики, каждый из которых будет обрабатывать только 1 аккаунт клиента (т.е. аккаунт передается обработчику как аргумент). Запускать нужно как фоновый процесс (&). Можно перед запуском проверять, не запущены ли они уже, или сделать это на следующем шаге.
    Обработчик при старте проверяет, не запущен ли другой его экземпляр для этого же клиента. Затем до тех пор, пока есть записи в очереди именно для этого аккаунта, скрипт получает по 7 записей для этого аккаунта, и по ним делает 7 одновременных запросов к api crm с помощью guzzle docs.guzzlephp.org/en/stable/quickstart.html#concu... , после чего удаляет записи из очереди.

    Альтернативным вариантом будет использование очереди вроде RabbitMQ вместо базы данных. Нужно будет в exchange создать очередь для каждого аккаунта клиента, и также скриптом по крону получать информацию по тому, какие есть очереди и запускать обработчиков. Первый способ, на мой взгляд, проще, да и его будет достаточно, если вы не обрабатываете миллионы записей ежедневно.
    Ответ написан
    3 комментария
  • MySQL как создать если не существует?

    @dzhebrak
    Сделайте уникальный индекс по этим трем столбцам https://www.mysqltutorial.org/mysql-unique/ , а при записи используйте ON DUPLICATE KEY UPDATE https://www.mysqltutorial.org/mysql-insert-or-upda...
    Ответ написан
    2 комментария
  • Как проверить значения массива на схожесть?

    @dzhebrak
    Еще одно решение - вычислить расстояние Левенштейна между строками https://www.php.net/manual/ru/function.levenshtein.php

    Расстояние Левенштейна - это минимальное количество вставок, замен и удалений символов, необходимое для преобразования str1 в str2. Сложность алгоритма равна O(m*n), где n и m - длины строк str1 и str2 (неплохо по сравнению с similar_text(), имеющей сложность O(max(n,m)**3), но все же довольно много).

    echo(levenshtein('abcdefg', 'amcdehg'));
    Если расстояние между строками равно 2, значит нужно вставить, заменить или удалить 2 символа, соответственно строки похожи.

    Функция для работы с русским языком: https://gist.github.com/shankao/b0d92e15c65852fda481

    Пример:
    $lines = [
      'Продам клинок демона +6 / Солнцеликий плащ +2 тьма',
      'Продам клинок демона +6, Солнцеликий плащщ +2тьма',
      'Акция! Продам клинок демона +6, Солнцеликий плащ +2тьма',
      'Продам клинок ангела +3, Луноликая куртка +4свет',
      'Продам клинок ангелла +3, Луноликая куртка +4свет',
      'Акция ! Продам клинок ангела +3, Луноликая куртка +4свет',
      'тест акции',
      'проверка демона',
      'проверка ангела',
    ];
    
    $res = [];
    $allSimilar = [];
    
    foreach ($lines as $line) {
        $similarLines = [];
    
        if(in_array($line, $allSimilar)) {
            continue;
        }
    
        foreach ($lines as $line1) {
            $lev = mb_levenshtein($line, $line1);
            $maxDistance = (int)(0.2 * max(mb_strlen($line), mb_strlen($line1)));
    
            if($lev <= $maxDistance) {
                $similarLines[] = $line1;
                $allSimilar[] = $line1;
            }
        }
    
        $res[$line] = $similarLines;
    }
    
    print_r($res);

    Похожими считаются фразы, которые отличаются менее чем на 20% их длины.
    Ответ написан
    Комментировать
  • Как указть ячейку Excel для записи в неё определенного значения из Python?

    @dzhebrak
    В csv вероятнее всего так сделать нельзя, но можно в xlsx с помощью модуля XlsxWriter https://xlsxwriter.readthedocs.io/getting_started.html

    import xlsxwriter
    
    workbook = xlsxwriter.Workbook('hello.xlsx')
    worksheet = workbook.add_worksheet()
    
    worksheet.write('A1', 'Hello world')
    
    workbook.close()
    Ответ написан
    1 комментарий
  • PHP, как решить конфликт множественного использования trait?

    @dzhebrak
    Как вариант, в OtherFirstTrait и OtherSecondTrait можно не использовать ErrorTrait, а сделать абстрактный метод с той же сигнатурой, что и в ErrorTrait. В ChildClass в свою очередь использовать ErrorTrait, OtherFirstTrait, OtherSecondTrait.

    Пример:
    trait ErrorTrait
    {
    	public function someMethod($someArg) {
    		echo __TRAIT__ . ": " . $someArg . "\n";
    	}
    }
    
    trait OtherFirstTrait
    {
    	abstract public function someMethod($someArg);
    
    	public function someMethod1($someArg) {
    		echo __TRAIT__ . ": " . $someArg . "\n";
    		$this->someMethod($someArg);
    	}
    }
    
    trait OtherSecondTrait
    {
    	abstract public function someMethod($someArg);
    
    	public function someMethod2($someArg) {
    		echo __TRAIT__ . ": " . $someArg . "\n";
    		$this->someMethod($someArg);
    	}
    }
    
    abstract class MainClass
    {
    	use ErrorTrait;
    }
    
    class ChildCLass extends MainClass
    {
    	use OtherFirstTrait, OtherSecondTrait;
    }
    
    $o = new ChildCLass();
    $o->someMethod("test ErrorTrait");
    print("\n");
    $o->someMethod1("test OtherFirstTrait");
    print("\n");
    $o->someMethod2("test OtherSecondTrait");

    Вывод:
    ErrorTrait: test ErrorTrait
    
    OtherFirstTrait: test OtherFirstTrait
    ErrorTrait: test OtherFirstTrait
    
    OtherSecondTrait: test OtherSecondTrait
    ErrorTrait: test OtherSecondTrait
    Ответ написан
    3 комментария
  • Проверка карты на валд?

    @dzhebrak
    Да, можно проверить с помощью регулярных выражений. В symfony есть хороший пример:
    https://github.com/symfony/symfony/blob/8a7c776b92...
    Ответ написан
    Комментировать
  • Как заменить или удалить на стороннем сайте стайл в DIV?

    @dzhebrak
    Используйте расширение вроде Stylus https://addons.mozilla.org/ru/firefox/addon/styl-us/ - с его помощью можно изменить стили для сторонних сайтов
    Ответ написан
    4 комментария
  • Как обновлять кеш на клиенте с Nginx?

    @dzhebrak
    Добавляйте к файлам css и js случайный параметр, который модифицируйте после внесения изменений в сами файлы. Это сбросит кэш в браузере у пользователя. Например,:
    <link rel="stylesheet" href="/style.css?v=1">
    После изменения файла style.css увеличьте счетчик на единицу:
    <link rel="stylesheet" href="/style.css?v=2">
    Ответ написан
    7 комментариев
  • Как сделать переход на ссылку при клике на кнопку в зависимости от выбранного цвета?

    @dzhebrak
    Например, так (add-to-bag - ссылка, а не кнопка):
    var selectors = ['black', 'white'];
    
    $(".add-to-bag").click(function() {
        var $this = $(this);
    
        $.each(selectors, function(index, value ) {
            if($('.'+value).hasClass("active")) {
                console.log(value);
                $this.attr("href", value+".html")
            }
        });
    });
    Ответ написан
    Комментировать
  • Как поменять данные http на https в wp?

    @dzhebrak
    Так можно заменить http://olddomain.com на https://olddomain.com во всех css файлах в текущей и вложенных директориях:
    find . -name "*.css" -exec sed -i 's|http://olddomain.com|https://olddomain.com|g' {} \;

    Команду нужно выполнять из каталога темы. Вместо olddomain.com укажите свой домен. И на всякий случай перед выполнением сделайте бэкап файлов.
    Ответ написан
    1 комментарий
  • Как запретить доступ к сайту с других стран?

    @dzhebrak
    Если ваши конкуренты мешают вашей деятельности сейчас, то вполне возможно, что будут и после того, как вы запретите доступ из стран кроме Казахстана - достаточно будет найти новые прокси. Более того в такой реализации нужно будет дополнительно разрешать доступ для поисковых ботов, чтобы не было проблем с seo.

    Возможно, лучшим решением будет скрывать (или как-то помечать) от вашего менеджера заявки, которые были сделаны посетителями не из Казахстана. Менеджер не будет их видеть, зато ваши конкуренты будут и дальше тратить свое время на фейковые заявки.

    Вот пример, как можно определить страну и заблокировать всех, кто не из Казахстана:
    $ip = $_SERVER['REMOTE_ADDR'];
    $ipInfo = json_decode(file_get_contents("http://ip-api.com/json/{$ip}?fields=status,message,country,countryCode"), true);
    
    if(isset($ipInfo['country']) && $ipInfo['country'] != 'Kazakhstan') {
    	//print('BLOCKED COUNTRY');	
        http_response_code(403);
    	  die('Forbidden');
    }
    Ответ написан
    5 комментариев
  • Как опредилить на какой сайт ведёт ссылка?

    @dzhebrak
    Можно сделать с помощью jquery:
    $(document).ready(function() {
        $('a[href^="http://"], a[href^="https://"]').not('a[href*="'+document.domain+'"]').attr('target','_blank');
    });
    Ответ написан
    3 комментария
  • Выполнение функции после ввода 6 символов в input?

    @dzhebrak
    Например, так:
    $( "#checkout-index_pochta" ).keyup(function( event ) {
      	var v = $(this).val();
    
      	if($.trim(v).length >= 6) {
      		console.log('showRaschet');
      	}
    });
    Ответ написан
    Комментировать
  • Как создать уникальный индекс с условием?

    @dzhebrak
    Можно сделать индекс сразу по двум столбцам:
    CREATE TABLE example (
        id SERIAL PRIMARY KEY,
        contractor_id INT NOT NULL,
        is_main BOOLEAN NOT NULL,
        UNIQUE (contractor_id, is_main)
    );

    https://www.postgresqltutorial.com/postgresql-uniq...
    или
    CREATE UNIQUE INDEX CONCURRENTLY contractor_id_main ON table_name (contractor_id, is_main);
    Ответ написан
    Комментировать
  • Как изменить отображение слова Меню на русский язык?

    @dzhebrak
    В header.php, функция esc_html_e():
    <a href="<?php echo esc_url( ( get_option( 'permalink_structure' ) ? home_url( '/menu/' ) : home_url( '/?menu' ) ) ); ?>"><?php esc_html_e( 'Menu', 'susty' ); ?></a>

    https://github.com/jacklenox/susty/blob/5b4d019b06...
    Заменить на:
    <a href="<?php echo esc_url( ( get_option( 'permalink_structure' ) ? home_url( '/menu/' ) : home_url( '/?menu' ) ) ); ?>"><?php esc_html_e( 'Меню', 'susty' ); ?></a>


    Альтернативным решением будет перевод темы на русский язык: https://misha.blog/wordpress/translations.html
    Ответ написан
    1 комментарий
  • Не могу разобраться с массивом?

    @dzhebrak
    Если я правильно понял вашу задачу, то:

    var o = {'0-1-211': 1, '1-1-290': 2, '2-1-380': 3};
    
    for (var key in o) {
    	console.log(key.split('-')[2]);
    }


    Если же у вас дана строка, а не массив, то:
    var s = '{0-1-211: 1, 1-1-290: 2, 2-1-380: 3}';
    
    s.split(',').forEach(function(v, k, arr) {
    	var vv = v.split(':')[0];
    	console.log(vv.split('-')[2]);
    });
    Ответ написан
    1 комментарий
  • Как подогнать путь к файлу сайта под нужный формат Python?

    @dzhebrak
    Если вариант с regex не подходит, то можно разбить каждую строку с помощью urllib.parse и затем собрать обратно, как нужно:
    from urllib.parse import urlparse
    
    def parse_domain(line):
    	scheme, netloc, path, params, query, fragment = urlparse(line)
    	path = path.split('/', 1)[0].strip('/')
    
    	# fix для site.com
    	if scheme == '' and netloc == '':
    		netloc = path
    
    	if scheme == '':
    		scheme = 'http'
    
    	# в дальнейшем может не сработать, если сайт доступен только по www и не настроен редирект с варианта без www
    	if netloc.startswith('www.'):
    		netloc = netloc[4:]
    
    	return '{}://{}'.format(scheme, netloc)

    Тест:
    https://site.com/ -> https://site.com
    www.site.com/ -> http://site.com
    www.site.com -> http://site.com
    site.com -> http://site.com
    http://site.com -> http://site.com
    site.com/test/ -> http://site.com
    site/com/ -> http://site
    Ответ написан
    Комментировать
  • Как сохранить числа с сайта в эксель?

    @dzhebrak
    Для записи в excel файл необходимо использовать сторонние модули, вроде XlsxWriter
    import xlsxwriter
    
    workbook = xlsxwriter.Workbook('hello.xlsx')
    worksheet = workbook.add_worksheet()
    
    worksheet.write('A1', 'Hello world')
    
    workbook.close()

    https://xlsxwriter.readthedocs.io/getting_started.html
    Еще вариант - использовать csv файлы https://docs.python.org/3/library/csv.html
    Ответ написан
    Комментировать
  • Как сформулировать массив в данной верстке?

    @dzhebrak
    Да, вы верно определили элементы массива - осталось только создать массив. У вас получится что-то вроде следующего:

    $items = [
    	'My Tasks' => [ // уникальный ключ для каждого элемента
    		'text' => '130 / 500', // текст, который показывается для элемента в span
    		'color' => 'bg-fusion-400', // цвет
    		'progress_wrapper_class' => 'mb-3', // класс для progress (уникальный у User Testing) или использовать if, как в примере ниже
    		'progress_value' => 65, // значение progress bar
    	],
    	'Transfered' => [
    		'text' => '440 TB',
    		'color' => 'bg-success-500',
    		'progress_wrapper_class' => 'mb-3',
    		'progress_value' => 34,
    	],
            // остальные элементы
    ];

    Далее вам необходимо перебрать этот массив с помощью foreach:
    <?php foreach ($items as $key => $item) : ?>
            <div class="d-flex <?php if ($key == 'My Tasks'): ?>mt-2<?php endif; ?>">
                <?= $key ?>
                <span class="d-inline-block ml-auto"><?= $item['text'] ?></span>
            </div>
            <div class="progress progress-sm mb-3">
                <div class="progress-bar <?= $item['color'] ?>" role="progressbar" style="width: <?= $item['progress_value'] ?>%;" aria-valuenow="<?= $item['progress_value'] ?>" aria-valuemin="0" aria-valuemax="100"></div>
            </div>
    <?php endforeach; ?>

    Но в современной разработке все-таки чаще используются шаблонизаторы вроде twig.
    Ответ написан
    3 комментария