Задать вопрос
  • Что такое Доменный объект и Предметная область, простым языком?

    @deliro
    Предметная область — множество всех сущностей и их отношений в рамках контекста.

    Например:
    В рамках магазина это покупатели, продавцы, товары, цены, скидки, поставщики, процесс продажи, прихода на склад, возврата и т.п.
    В рамках дискорда это пользователи, серверы, комнаты, группы, права на доступ, процессы присоединения к серверу, входа в комнату, оплаты nitro, написания текстового сообщения и т.п.

    В целом, это всё, что понимает твой менеджер и ничего, что он не понимает. В предметную область не входит, например, то, где именно ты хранишь данные — в mysql, в файлах, получаешь и сохраняешь их по API или хранишь их в redis'е. Но входит абстрактная сущность "хранилище". Она же — интерфейс репозитория. Репозиторий — это паттерн, который скрывает реализацию конкретного хранилища и который оперирует объектами доменной модели — элементами предметной области, как будто они хранятся у тебя в оперативной памяти. Например, у репозитория могут быть методы
    users.getByID(1234), users.save(user), users.getByEmail("hello@world")
    и т.п. Реализация репозитория определяет, куда именно сохранится этот user или откуда он скачается. В одну таблицу или в несколько. Нормализованные ли будут данные лежать в РСУБД или денормализованные. Именно здесь можно реализовать запись в master, а чтение с реплик. Или энкодинг в msgpack и передачу его по API куда-то. Или по gRPC. Потому что предметная область не должна перегружаться деталями реализации хранилищ.

    Про доменную модель:
    Словарь (он же хэш, он же ассоциативный массив) — это не доменная модель (хотя в некоторых функциональных языках может быть). Объект ORM — это тоже не доменная модель, хотя много где пытается ей быть. Доменная модель не зависит от конкретных фреймворков, баз данных, оптимизаций этих баз и прочих навязанных технической составляющей сущностей. Чаще всего это обычный класс на языке, на котором пишется код (или struct в случае Golang).

    Недавний пример:
    У сущности есть теги по категориям:
    {"category1": ["foo", "bar"], "cat2": ["foo", "hello", "world"]}
    . Их так удобно представлять на уровне предметной области, об этой структуре я могу общаться с заказчиком. Но в монге они сохраняются в виде
    ['category1%%foo', 'category1%%bar', 'cat2%%foo', 'cat2%%hello', 'cat2world']
    , потому что так их легче индексировать и быстрее по ним искать. Но это скрыто в реализации репозитория, доменная область про это ничего не знает. Это даёт сразу много преимуществ:
    1. Это очень просто тестировать, без всяких моков. Вместо репозитория с монгой я делаю репозиторий, который хранит сущности в оперативе. Всё, тесты бизнес-логики не зависят от инфраструктуры. А репозиторий монги я тестирую отдельно, мокая запросы в саму монгу или даже не мокая
    2. Это облегчает понимание всего продукта. Мозг не пытается составить полную картину, когда запросы в БД перемешаны с логикой, тут же сплиты-джойны строк, какие-то ещё низкоуровневые действия. Мозгу легко ориентироваться в пределах уровня. На уровне репозитория я думаю о том, как сущности хранить и доставать из хранилища, на уровне служб я думаю о том, как сущности взаимодействую и какие их них нужно извлечь/сохранить, но не как
    3. Рефакторинг очень простой. Даже теоретическая смена БД. Завтра с монги нужно будет перенести одну сущность на постгрес — без проблем. Я напишу один новый репозиторий, не затронув ни строчки кода за его пределами, кроме места, где он создаётся. При этом, остальные сущности могут лежать всё также в монге

    Доменные модели бывают богатыми и анемичными (но не бескровными). Оба подхода применяются и, имхо, не является антипаттерном ни один из них. Лично я использую анемичные модели, а всю бизнес-логику храню в службах.
    Ответ написан
    2 комментария
  • Shell script с root правами из PHP?

    faustoFF
    @faustoFF Автор вопроса
    Проблема решилась. Во всем виновата собственная невнимательность. Моя опечатка в описании помогла мне найти опечатку в реальных конфигах в этом же месте (путь к скрипту в sudoers и реальный путь не совпадали) :) Теперь скрипт успешно отрабатывает из под www-data от root-а с рутовыми же правами.

    Забавно, из-за собственной невнимательности сгенерировал такое обсуждение. Надеюсь кому-то это окажется полезным.
    Ответ написан
    1 комментарий
  • Как автоматический обновлять сайт на сервере с Github?

    littleguga
    @littleguga
    Не стыдно не знать, а стыдно не интересоваться.
    1. Забейте на хостинг от Джино, vps на Digital Ocean стоит 5$, не такие уж большие деньги.
    2. Перейдя на VPS откройте для себя мир CI(непрерывной интеграции), если разобраться с системами CI будет совсем тяжко, то есть простые скрипты типо такого или такого.

    Можете попробовать вот это
    Ответ написан
    Комментировать
  • Как подключить приватные репозитории к зависимостям в Composer?

    just_i
    @just_i
    php | js программист
    https://toranproxy.com/ попробуйте это. Легко ставится, избавляет от выше описанных проблем. Может полностью проксировать все пакеты или же использоваться только для приватных репозиториев. Имеет веб интерфейс для добавления новых приватных репозиториев, что очень удобно.
    Ответ написан
    1 комментарий
  • Как из php попинговать ip и вывести статистику?

    alexxxst
    @alexxxst
    exec(«ping ya.ru», $out);
    в $out будет массив строк с результатами
    Ответ написан
    2 комментария
  • Трансляция звука напрямую в микрофон?

    Slayer_nn
    @Slayer_nn Куратор тега Windows
    Гугол, памаги!
    hesy, трансляция заранее записанного звука из файла

    В винде это работало через микшер в устройствах звука5c03544a187d8174646579.png
    так я мог музыку транслировать в скайп

    далее в проге указываем этот микшер в качестве микрофона
    ну и найти то, что передаст звук на этот микшер

    по типу winamp> даем звук на какой-то свободный динамик (например по TV Hdmi) (не подключенный)
    а с микшера прослушиваем этот динамик (галка не обязательна)

    если не устроит
    то вот ответ
    https://superuser.com/questions/117625/how-to-crea...
    Есть еще вариант спаять кабель 3.5 Jack to Mic (для тех, кто не ищет легких путей)
    Ответ написан
    Комментировать
  • Могут ли возникнуть дубли хешей?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Решение отвратительное. Это уже что-то из серии про архиватор Бабушкина.

    Ну разумеется, коллизии будут.

    Лучше оставить MD5 (у которого вероятность коллизий вполне в пределех допустимого), но перевести его из неэффективного base16 в более короткую форму. Base64 вполне подойдёт, поскольку кодировщик есть в пхп из коробки. Вот только оба не буквенно-цифровых символа там не подходят для передачи через урл - лучше их заменить:
    $base64 =  substr(strtr(base64_encode(hex2bin($md5)),'+/',"_-"),0,-2);

    Итого экономим 10 символов из 32-х. Конечно, 22 хуже чем 8, но тут надо выбирать - или достаточная длина, или коллизии и отсутствие безопасности вообще.
    Ответ написан
    Комментировать
  • Секреты написания отличных статей на Хабре

    track
    @track
    Пост должен начинаться с картинки-eyestopper-а.

    В тексте нужно вначале немножко повилять хвостом и поприседать перед могущественным хабражителем, он это любит.
    Хорошо идут либо статьи из серии «на пальцах» (о, даже мне понятно стало!), или, другая, несколько парадоксальная крайность — чрезмерно заумные (о, круто! Хабр — торт! Ничо не понял, но плюсану!").
    Есть темы, которые гарантированно набирают плюсы (хабрасрач против копирастов и «михалкова», например). Не рекомендуется, особенно новенькому, писать на фанатские темы («Apple — круто» или «Apple — гавно» — в равной мере). Реакция может быть непредсказуема, в зависимости от того, какая клака в тред придет первой. Не стоит выступать в защиту тем-изгоев. Сольют и ее и вас.
    Хабрастадо любит следовать за вожаком. Если пост явно плюсуется — будут плюсовать. Если минусуется — минусовать.

    Любят статьи про мелкие компании, стартапы, самоделки, особенно компьютерные, гаджеты, даже бесполезные. Не любят — про корпорации (Google это, HP или Microsoft — неважно), и все связанное с ними.

    Также периодически стихийно организуются «топики добра» или «топики зла», появление их, и то, какой вариант будет выбран — непредсказуемо.

    Если видите, что в первые несколько минут пост ушел «в минус» (хотя бы в минус 5), и у вас нет компании друзей, которые его могут быстро из минуса вывести, то задача безнадежна, убирайте его «в черновики».
    Ответ написан
    5 комментариев
  • Что такое РОЛИ в PostgreSQL?

    Melkij
    @Melkij
    PostgreSQL DBA
    объясните, пожалуйста, смысл ролей в постгрес

    Пользователь - это алиас для системы ролей.

    необходимо создать базу данных с тем же именем, что и имя роли, к которой можно будет осуществлять доступ с помощью этой роли

    Это ложь. Необходимости нет.

    Поэтому для созданного нами ранее пользователя с именем sammy соответствующая роль будет по умолчанию пытаться соединиться с базой данных sammy

    А это верно. Но только если имя базы для подключения не переопределено, например, переменной окружения PGDATABASE. Ну и конечно его можно просто задавать аргументом подключения.

    можно ли так: несколько ролей и одна база данных?

    Разумеется. Хоть дерево со множественным наследованием ролей.

    Только важный момент - роли глобальны в пределах кластера. Вы не можете сделать пользователя user в базе foo с одним паролем и пользователя user в базе bar с другим паролем. А вот дать readonly на одну базу и полные права на другую - это пожалуйста.
    Ответ написан
    1 комментарий
  • Как реализовать аналог статического конструктора в классе PHP?

    27cm
    @27cm
    TODO: Написать статус
    Вот в C# есть кроме обычного конструктора статический конструктор. суть его в том что при любом ПЕРВОМ обращении к статическим свойствам класса перед этим обращением выполняется статический конструктор. В котором определяются свойства для класса.


    Похоже, что никак. Чтобы перед обращением к статическому свойству отработал какой-либо метод (статический конструктор), нужен аналог "магического" метода __get() для статических свойств, а такой в PHP отсутствует. Более того, даже если бы такой метод был, он бы не срабатывал если статическое свойство уже определено в классе, пришлось бы принудильно делать unset() для всех статических свойств, что приведёт к ошибке.

    Поэтому вижу только один выход: обращайтесь к статическим свойствам через статические get-методы, в которых уже и вызывайте "статический конструктор".

    <?php
    
    class Test
    {
        static public $foo = 1;
        static public $bar = 1;
    
        static public function getFoo()
        {
            return static::__getStatic('foo');
        }
        
        static public function getBar()
        {
            return static::__getStatic('bar');
        }
        
        /**
         * Вызывает __constructorStatic() при первом обращении
         * и возвращает значение статического свойства $name.
         *
         * @param string $name Имя статического свойства класса.
         */ 
        static protected function __getStatic($name)
        {
            static $called = false;
            if (!$called) {
                $called = true;
                self::__constructorStatic();
            }
            return static::${$name};
        }
    
        /**
         * "Статический конструктор" класса.
         */
        static private function __constructorStatic()
        {
            static::$bar++;
            static::$foo++;
        }
    }
    Ответ написан
    1 комментарий
  • Как сделать связь в MySQL?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Если я правильно понял, то здесь у вас связь один-ко многим, поле `post_content`.`parent_id` указывает на `post`.`id`.
    Для того, чтобы создать такую связь (внешний ключ, FOREIGN KEY) в MySQL сначала необходимо убедиться, что оба этих поля имеют одинаковый тип и размер и в колонке `post_content`.`parent_id` нет значений, отсутствующих в `post`.`id`.
    Затем надо создать саму связь
    ALTER TABLE `post_content`
      ADD CONSTRAINT FOREIGN KEY `fk_parent_id` (`parent_id`)
        REFERENCES `post` (`id`)
        ON DELETE CASCADE;

    Этот запрос добавляет внешний ключ `fk_parent_id` с поля `parent_id` на `post`.`id` и говорит, что при удалении записи из таблицы `post` будут удалены связанные записи из `post_content`.
    Ответ написан
    3 комментария
  • Как добавить свои библиотеки в Composer для использования в разных проектах?

    mendler
    @mendler
    Senior Web Developer
    https://github.com/composer/satis

    ну а вообще проще указать git репозиторий напрямую:
    "repositories": [
        {
          "type": "git",
          "url": "....git"
        }
    ]
    Ответ написан
    2 комментария
  • Как добавить свои библиотеки в Composer для использования в разных проектах?

    @D3lphi
    Выполняем команду:
    composer init

    Следуем инструкциям. В результате, получим частично сконфигурированный файл composer.json. Прописываем в этот файл неймспейсы для автозагрузки классов:
    {
    // Другие опции...
        "autoload": {
            "psr-4": {
                "MySuperApp\\": "src/"
            }
        }
    // Другие опции...
    }


    Это означает, что классы, имеющие неймспейс MySuperApp\ будут находится в папке src. То есть, класс MySuperApp\First должен лежать прямо в папке src, а класс MySuperApp\Test\Second в папке src/Test. Надеюсь, понятно.

    Теперь, нам нужно выложить свой проект на гитхаб. Для этого, создаем там репозиторий и пушим файлы проекта.

    Далее, переходим на сайт packagist.com, регистрируемся там. В настройках профиля следуем инструкциям и привязываем аккаунт к github'у. Переходим во вкладку submit, вставляем в инпут ссылку на наш github репозиторий, жмем check (В этот момент packagist проверит, что данный репозиторий принадлежит именно нам), затем, снова check, чтобы подтвердить наш выбор. Вот, собственно, и все! Осталось прикрутить автообновление пакета. Информация об этом тоже есть на сайте.
    Ответ написан
    Комментировать
  • Запрос XPath без дочерних элементов?

    glebovgin
    @glebovgin
    Full Stack Web Developer
    Если структура html одинакова, то сработает такой вариант
    //div[contains(@class, "some-class")]/div/span[1]/following-sibling::text()

    А вот такой вариант
    //div[contains(@class, "some-class")]/div/text()[normalize-space()]

    выберет все текстовые элементы, исключая пробелы. В конкретно вашем случае в item(0)->nodeValue будет значение между двумя span. Если нужны все текстовые элементу внутри div, то просто пройти foreach по результатам.
    Ответ написан
    2 комментария
  • Для чего нужна ORM?

    Вы не путаете ORM с DBAL? ORM это не технология замены SELECT * FROM goods WHERE cost < 100.00 на $db->select()->from('goods')->where('cost < 100.00'). ORM это способ задания связи объектов и РСУБД. По сути позволяет абстрагироваться от способа хранения объектов вообще, с лёгкостью переходя от SQL к NoSQL, memcache, файлам или REST/RPC API на удалённом сервере, оперируя на уровне модели (если говорить о MVC и т. п.) простыми plain old objects, а их персистентность отдать контроллеру. Не $db->select()->from('goods'),, не mysql_query('SELECT * FROM goods'), а $goodsRepository->findAll(), а уж будет репозиторий формировать SQL запрос, читать файлы или память, а может стучаться на Гугл и парсить его вывод — его, репозитория, личное дело (а также разработчика(ов), отвечающих за подсистему хранения).

    Кроме того ORM, как правило не исключает обращение к БД на уровне произвольных SQL запросов, оно лишь преобразуют результаты этих запросов в объекты модели предметной области (и наоборот), которые ничего не знают (в идеале) о таблицах, WHERE, HAVING и т. п.

    ORM это не только инструмент архитектурного разделения областей ответственности объектов и классов приложения, а также инструмент облегчения разделения труда разработчиков: кто хорошо шарит в SQL вообще и особенностях конкретного движка в частности — работает по «ту сторону» ORM, оптимизирует его как хочет, может нормализовывать и денормализовывать, например; кто хорошо разбирается в дебетах и кредитах — работает с plain old objects в терминах предметной области и может вообще ничего не зная об SQL, ему лишь нужно знать, что он всегда может получить объект или их коллекцию обратившись к методам вроде findById() или findAll() и сохранить результат работы методом save() или flush().
    Ответ написан
    3 комментария
  • В чем отличие DBAL от ORM?

    muzikant777
    @muzikant777
    PHP/Vue разработчик
    Некорректно сравнивать тёплое с мягким. Так и здесь: DBAL, как вы правильно написали - слой абстракции, представляющий единый интерфейс для работы с различными реализациями БД.
    ORM - штука, которая позволяет работать с объектами и связями в БД как с сущностями, не заботясь о том, из каких именно таблиц и полей заполняется сущность.

    У вышеупомянутой Doctrine тоже есть свой DBAL, но это не мешает ей быть ORM :)
    Ответ написан
    Комментировать
  • StdClass. Зачем это нужно?

    @Quieteroks
    php программист
    stdClass - это объект, а объект передается по ссылке в функции/методы, в отличии от массива.
    По сути это тот же массив, только в виде класса. Что Вам удобнее, то и берите.
    Если же Вам возвращается stdClass от каких либо библиотек, то просто вытащите из него данные в массив:
    $arr = get_object_vars($std);
    Ответ написан
    1 комментарий
  • PDO - полный отладочный запрос?

    AlexTest
    @AlexTest
    Исходя из логики работы PDO c БД — для нормальной отладки таки придется писать свой велосипед, т.к. сначала хочется полную строку запроса посмотреть, потом узнать где был вызван запрос, сколько он выполнялся и т.д. и т.п.
    Самый правильный способ — отнаследоваться от PDO и PDOStatement, а своей обертке уже сделать «блекджек со шлюхами» например как здесь daveyshafik.com/archives/605-debugging-pdo-prepared-statements.html
    По ссылке выше далеко не самое лучшее решение, я бы перекрыл метод execute в PDOStatement и другие подобные методы так, чтобы например при включенной опции отладки они сами бы складывали нужную мне информацию в нужное место, а при выключенной отладке просто сквозняком пропускали запросы к PDO.
    Ответ написан
    1 комментарий
  • Где взять готовый образ для виртуалки?

    @bondbig
    Ответ написан
    Комментировать
  • Получение номер столбца в Excel с помощью библиотеки phpspreadsheet?

    gromdron
    @gromdron
    Работаю с Bitrix24
    Есть почти то, что Вы хотите, но без указания номера строки. т.е. если отделить строку от столбца, то получается нижеследующее:
    use \PhpOffice\PhpSpreadsheet\Cell\Coordinate;
    
    // Выведет: Z
    var_dump(Coordinate::stringFromColumnIndex(26));
    
    // Выведет: R
    var_dump(Coordinate::stringFromColumnIndex(18));
    
    // Выведет 2
    var_dump(Coordinate::columnIndexFromString('B'));
    
    // Выведет 26
    var_dump(Coordinate::columnIndexFromString('Z'));

    См. https://phpspreadsheet.readthedocs.io/en/develop/t...
    Ответ написан
    Комментировать