• Как правильно сделать типизацию объектов?

    @Vitsliputsli
    Вы можете воспользоваться контравариантностью (php>=7.4), т.е. указать в абстрактном классе родительский класс для User:
    abstract protected function mapToArray(Model $object ): array;
    
    ...
    
    class User extends Model

    Либо ввести DTO, чтобы mapper брал данные из него и вообще никак не обращался к бизнесовым сущностям.
    Ответ написан
    6 комментариев
  • Вопрос про модели и репозиторий php?

    @tukreb
    На ваш вопрос, если полностью разжёванный ответ:
    https://elisdn.ru/blog/104/domain-entities-modelling

    Да и вообще советую полистать там сайт, очень много подробной информации с отличными примерами.
    Ответ написан
    Комментировать
  • Вопрос про модели и репозиторий php?

    Если тут так и не будет лаконичного объяснения - советую поискать
    ответы на эти вопросы в книге:
    Implementing Domain Driven Design, Vaughn Vernon
    Там есть целые разделы посвященные как моделям так и репозиториям.
    Ответ написан
    Комментировать
  • Правильно ли реализован класс для работы с базой данных по принципу SOLID?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Во-первых, это никакой не DatabaseManager , а CRUDManager. Работа с БД далеко не ограничивается этими 4 примитивными функциями.

    Отсюда мы делаем логичный вывод, что соединение с БД никаким местом не должно создаваться в конструкторе менеджера крудов. А должно точно так же передаваться в него в качестве зависимости. Это может быть либо ванильная ПДО, либо инстанс реального MySQLDatabase (но поскольку мы пока не знаем, как он должен выглядеть, то лучше остановиться на PDO).

    Сам по себе DatabaseManager выглядит избыточным. Непонятно, зачем он нужен, если любой потребитель DatabaseManager-а может просто написать
    public function __construct(CRUDInterface $crud) {
    }

    и получить тот самый полиморфизм, которого мы изначально и добивались. Передадим другую реализацию - будет другая, но с тем же публичным контрактом, то есть всё будет работать.

    В-четвёртых, хоть это и не относится напрямую к теме SOLID, но для меня является очень важным: собственно, реализация методов CRUD-а. Что в них передаётся? Откуда берутся названия таблиц, полей? Передаются в параметрах методов? Это прямая дорога к SQL инъекции, не говоря уже о нарушении инкапсуляции. Поэтому, отвечая на вопрос "Как вы реализуете работу с базой данных", лично я всё больше в последнее время от развесистых ORM-ов склоняюсь к простым TableGateway-ам. Да, кода писать больше, но он строже и понятнее. И не встаёт колом в нестандартных ситуациях. Тем более что приведённый пример кода как раз очень и похож на этот паттерн. То есть
    abstract class MysqlTableGateway implements CrudInterface
    {
        protected $db;
        protected $table;
        protected $fields;
        protected $primary = 'id';
    
        public function __construct(\PDO $db)
        {
            $this->db = $db;
        }
        public function read($id): ?array
        {
            $stmt = $this->db->prepare("SELECT * FROM `$this->table` WHERE `$this->primary`=?");
            $stmt->execute([$id]);
            return $stmt->fetch();
        }
         // ну и так далее
    }

    И дальше уже классы по работе с отдельными табличками наследовать от него,
    final class UserGateway extends MysqlTableGateway {
        protected $table = 'users';
        protected $fields = ['email', 'password','phone'];
    }

    Соответственно, если мы захотим перейти с мускуля на какой-нибудь редис с джейсоном внутре, то надо будет создать новый абстрактный класс с тем же интерфейсом, и от него отнаследовать реализации. Соответственно, в интерфейсе надо нормально прописать входные и выходные параметры:
    interface CRUDInterface {
        public function create(array $data):int;
        public function read(int $id):?array;
        public function update(array $data);
        public function delete(int $id);
    }

    Другое дело, что в реальности такой шалтай-болтай будет сделать довольно сложно, поскольку классы для работы с отдельными таблицами будут расширяться запросами, специфичными для данной таблицы - то есть все их придется дописывать во все драйверы. То есть в реальности с D будут проблемы. Но чисто с теоретической точки зрения примерно вот так оно будет выглядеть.
    Ответ написан
    4 комментария
  • Сохранение сессий в базе данных?

    swaro
    @swaro
    Nice code - awesome bugs
    Получается, что в этом случае не нужно создавать сессию в PHP с помощью session_start()?
    Да
    Получается, что при каждом запросе к серверу будет запрос в базу данных для поиска переданного ид из куки.
    Да
    Нормально так проектировать приложение или нет?
    Абсолютно нормально.
    Ответ написан
    Комментировать
  • Включить защищённое подключение для websocket?

    ky0
    @ky0
    Миллиардер, филантроп, патологический лгун
    Сам по себе порт не гарантирует ничего, как настроите веб-сервер - так и будет. Проверить можно, например, с помощью curl`а в verbose-режиме.

    У нас никаких отдельных портов для WS не используется (потому что зачем?), всё на стандартном 443, просто отдельный урл типа /app_ws.
    Ответ написан
    2 комментария
  • Как убедиться что сообщение дошло websocket?

    @Vitsliputsli
    В чате кроме онлайн отправки сообщений должен быть механизм отложенного получения. После соединения клиент проверяет накопившиеся сообщения. Периодически клиент проверяет потерянные сообщения. Если у сообщений последовательные ID, то по пропускам клиент также определяет потерянные сообщения.
    Как вариант контроль не на стороне клиента, а на стороне сервера. Тогда клиент подтверждает получение. Но это больше взаимодействий и хранения данных на стороне сервера.
    Ответ написан
    Комментировать
  • Как правильно использовать команду at в линукс?

    Zoominger
    @Zoominger
    System Integrator
    Ну так правильно, вы сначала curl запускаете, а потом уже at.
    Читните: https://linuxize.com/post/at-command-in-linux/
    Лучше курл запихивать через <<.
    Ответ написан
    Комментировать
  • Как лучше сделать сохранение в базу данных из нескольких запросов для одинаковых полей в базе данных?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Это какой-то ужас.
    Я не знаю, вопрос звучит как "Мне надо надеть штаны на голову и выйти погулять. Я думаю продеть в штанины руки, зайти в туалет, облиться холодной водой, высохнуть, надеть штаны на голову и идти гулять. Вот только боюсь простудиться, потому что вода холодная".

    Весь этот кошмар происходит потому, что вы используете базу данных как микроскоп для колки орехов. Все проблемы тут оттого, что "это" сохраняется в одно поле в базе данных. А должно в разные. Так база данных устроена. Каждая частичка данных хранится в своем поле. Исключения бывают, но именно как исключения, а не как подход по умолчанию, и это явно не ваш случай.

    Надо сделать отдельную таблицу, где будут разные поля, которые привязываются к пользователю по его id. И никаких проблем при редактировании этих полей никогда не будет.

    Я имею в виду что должна это быть одна таблица, которая линкуется к текущей по связи один-ко-многим: таблица из трех колонок - id, user_id и собственно то значение, которое надо менять. Таким образом подмножество этой таблицы с одним и тем же user_id будет представлять из себя то самое "поле", которые вы пытаетесь редактировать сейчас. Но при этом все элементы будут лежать в отдельных строках, и редактироваться обычными SQL запросами.
    Ответ написан
    Комментировать
  • Правильное указание ссылки на объект в js?

    vabka
    @vabka
    Токсичный шарпист
    Да, нормально.
    Ответ написан
    Комментировать
  • Как оптимизировать пинг в мультилпеере?

    dollar
    @dollar
    Делай добро и бросай его в воду.
    Это очень сложная проблема, которую не решить в двух словах раз и навсегда. Поэтому ответ будет зависеть от особенностей игры. В общем случае - никак. Нет универсального рецепта.

    Например, если это пошаговая игра, то пинг вообще не критичен и можно блокировать действия всех игроков, пока все не получат обновлённое состояние игры.

    А если это шутер, то "блокировать" игру - не вариант, игроку необходимо оставить возможность двигаться своим персонажем и совершать действия, а серверу - задним числом засчитывать какие-то действия или отменять слишком смелые/резкие действия (откатывать к более "честному" состоянию). Ещё можно идти на компромиссы всякие, когда у разных игроков отображается чуточку разное состояние, но плюс-минус по сути одно и то же (по смыслу), а 1 шаг влево-вправо не считается.

    В "стратегиях" (т.е. в играх, где есть карта и много объектов с физикой или юнитов с ИИ), чтобы не пересылать всю информацию о том, что происходит в мире, есть такой подход, чтобы пересылать только команды игроков, а каждый у себя (на клиентской стороне) "симулирует" игру, так что она одинаковая у всех игроков. При таком подходе даже мелкие различия приведут к проблеме рассинхронизации игровой сессии с необходимостью послать сейв заново.

    В общем, так или иначе это какие-то уступки, допущения, округления, предположения (предсказания траектории движения объекта), ограничения и т.д.

    Кстати, пинг - это ещё пол беды. Если бы все пакеты приходили гарантированно хотя бы в окне 300 мс, это была бы сказка. К сожалению, пакеты ещё могут теряться совсем. И это тоже нужно как-то оптимизировать, чтобы игра не лагала и не подвисала. Опять-таки, способ зависит от игры, и хуже всего приходится играм от первого лица.
    Ответ написан
    Комментировать
  • Как оптимизировать пинг в мультилпеере?

    @antonwx
    Можно забить на эту проблему и попытаться решить её оптимальным расположением серверов для целевой аудитории (так делают, например, дота 2, вов)
    Можно попытаться параллельно воспроизводить игровой процесс как на сервере, так и на клиенте, и синхронизировать (так делает, например, псо2, варфрейм)
    Ответ написан
    Комментировать
  • Обработка персональных данных, которые пользователь хочет, чтобы они были в свободном доступе?

    Vad1mPr0
    @Vad1mPr0
    1. Если пользователь сам разместил информацию о себе в общедоступном источнике, то это общедоступные данные, не имеющие отношения к персональным (с точки зрения юридических формулировок).
    2. Персональные данные граждан РФ, согласно нормативке, в том числе и Роскомнадзора, должны обрабатываться только на территории РФ.
    3. Шифрование данных является лицензируемым видом деятельности.
    Ответ написан
    Комментировать
  • Какой шаблон проектирования подходит для плагина WordPress?

    glaphire
    @glaphire
    PHP developer
    Достаточно обычного рефакторинга на уровне "читаемо" и "без дублирования" (с размазыванием на пару классов по необходимости), MVC и паттерны это не ответ на такой вопрос (MVC - потому что это обобщенное понятие и просто притянуто к вебу из другой темы, а паттерн может вырисоваться сам во время рефакторинга, да и границы между некоторыми из них условны).
    Ответ написан
    1 комментарий
  • Upwork direct to local bank. Можно ли вывести на счёт физ. лица. Физ. лицо является самозанятым. Будет ли валютный контроль?

    LobsterJoe
    @LobsterJoe
    Как сказано выше, физическое лицо не может и не обязано проходить валютный контроль.
    Выводил на Tinkoff Black до $3k единоразово - деньги заходят естественно в рублях с Qiwi банка.
    Сейчас работаю через ИП - использовал несколько раз Direct to Local Bank - также приходят в рублях через Ситибанк. Саппорт Тинькофф говорит, что в данном случае ВК проходить не нужно.

    Агентом валютного контроля в данном случае являются Qiwi/Ситибанк - те банки-партнёры Upwork, где происходит "слом" валюты - конвертация долларов в рубли.
    Ответ написан
    4 комментария
  • Влагозащита в механической или мембранной клавиатуры в ноутбуке?

    hint000
    @hint000
    у админа три руки
    Если клавиатура действительно механическая, то под каждой клавишей механический переключатель в своём корпусе. cherry_mx_brown.png Попавшая на клавиатуру единственная капля вряд ли проникнет внутрь переключателя. Зато если жидкости будет больше, и она всё же проникнет в переключатели, то уже не надейтесь, что высохнет, потребуется замена переключателей. IMHO.
    Ответ написан
    Комментировать
  • Почему сайт доступен по HTTP, а по SFTP нет?

    deepblack
    @deepblack
    Должен быть запущен ssh server и соответственно открыт его порт (обычно это порт 22, но может быть и другой).
    Еще как вариант установлен fail2ban и настроен port-knocking
    Ответ написан
    Комментировать
  • Почему html5 шаблоны популярны?

    kores
    @kores
    Помог ответ? Отметь решением!
    Смотря какие. Если например это admin template - его используют действительно в основном разработчики, чтобы не пилить свои варианты дизайна административной панели для своих скриптов. Они позволяют из готовых блоков создать хорошее визуальное решение, интуитивно понятное пользователю (потому что скорее всего над шаблоном работали ui/ux дизайнеры и они имеют больший опыт, в отличии от программистов).

    Если же речь идет про обычные шаблоны сайтов, то многим достаточно для мелких сайтов обычного html/css кода без движка. Люди вырезают ненужные блоки, вставляют свой текст и вуаля - простой сайт готов, кому-то этого может быть достаточно.

    P.S. А так же скажу по своему опыту с ThemeForest, почему сразу не сабмитят шаблон в вордпресс тот же самый, а идут по пути - psd template -> html template -> wordpress theme.
    Тут логика в следующем. Если дизайн приняли - то если корректный HTML, то мало вероятности что ревьюверы докопаются до дизайна (ведь его уже до этого приняли). Такая же история и с HTML -> Wordpress. Т.е. ты проходишь этапы по шагам.
    Ответ написан
    2 комментария
  • Вопрос про strpos php?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега PHP
    По большому счёту, от ваших "оптимизаций" толку никакого, потому что str_replace всё равно сам ищет совпадение и если его там нет, вызов равносилен вызову strpos.
    А вот если совпадение есть, то логика поиска выполняется дважды.

    А ещё вы на спичках экономить пытаетесь.

    $text = str_replace(
      ['word1', 'word2', 'word3'],
      ['word-replace1', 'word-replace2', 'word-replace3'],
      $text
    );
    Ответ написан
    1 комментарий