• Как работает подход Unit of Work?

    @Flying
    Unit of Work - это паттерн определяющий логическую транзакцию т.е. атомарную синхронизацию изменений в объектах, помещённых в объект UoW с хранилищем (базой данных).

    Если обратиться к исходному описанию этого паттерна у Мартина Фаулера - то видно что объект, реализующий этот паттерн отвечает за накопление информации о том какие объекты входят в транзакцию и каковы их изменния относительно исходных значений в хранилище. Основная работа производится в методе commit() который отвечает за вычисление изменений в сохранённых в UoW объектах и синхронизацию этих изменений с хранилищем (базой данных).

    Паттерн Unit of Work как правило не является полностью самостоятельным, он обычно тесно связан с паттерном Identity Map, задача которого - сохранение карты созданных объектов, взятых из хранилища с тем чтобы гарантировать что одна единица информации из хранилища представлена ровно одним экземпляром объекта данных в приложении. Это позволяет избежать конфликтов изменений т.к. не допускает ситуации когда два объекта, представляющих один и тот же элемент данных в хранилище, изменены по-разному. Информация из Identity Map используется в методе commit() паттерна Unit of Work для вычисления разницы между исходными данными и накопленными изменениями.

    Поскольку для вычисления разницы (и, соответственно, определения того что и каким образом должно быть изменено в хранилище) необходимо знать какие данные и как именно хранятся в объектах - как правило необходима также реализация паттерна Metadata Mapping, описывающего связь между содержимым хранилища (к примеру таблицами и столбцами базы данных) и классами / свойствами объектов.

    Также, если данные в хранилище не являются независимыми (к примеру связи между таблицами в базе данных) - может потребоваться реализации ряда паттернов, отвечающих за сохранение информации о связях между данными (это паттерны раздела Object-Relational Structural Patterns в каталоге паттернов).

    Подводя итог: сам по себе Unit of Work довольно прост в своём внешнем интерфейсе, но реализация его корректной работы требует предоставления множества дополнительных данных, поэтому миниатюрных примеров привести не могу.

    Если говорить о PHP - то лучшей реализацией этих паттернов на PHP безусловно является Doctrine ORM. В частности в разделе Working with Objects документации Doctrine можно найти хорошее описание и множество примеров использования паттернов, описанных выше.
    Ответ написан
    6 комментариев
  • Как работает подход Unit of Work?

    voronkovich
    @voronkovich
    Попробую привести очень примитивный пример. Допустим, мы делаем простое приложение для микроблоггинга. Каждая сущность будет иметь вид:

    class Tweet
    {
        private $id;
        private $content;
    
        public function __construct(int $id, string $content)
        {
            $this->id = $id;
            $this->content = $content;
        }
    
        public function getId(): int
        {
            return $this->id;
        }
    
        public function getContent(): string
        {
            return $this->content;
        }
    
        public function setContent(string $content): void
        {
            $this->content = $content;
        }
    }


    Схема данных:

    CREATE TABLE tweets (
        id INTEGER PRIMARY KEY,
        content VARCHAR(255) NOT NULL
    )


    Следующая реализация UnitOfWork будет иметь несколько ограничений:
    1. Она умеет работать только с Tweet;
    2. Она умеет только загружать сущности и сохранять произведённые в них изменения.
    class UnitOfWork
    {
        private $connection;
        private $identityMap;
        private $data;
    
        public function __construct(\PDO $connection)
        {
            $this->connection = $connection;
            $this->identityMap = [];
            $this->data = [];
        }
    
        public function find(int $id): Tweet
        {
            if (isset($this->identityMap[$id])) {
                return $this->identityMap[$id];
            }
    
            $query = $this->connection->prepare('SELECT * FROM tweets WHERE id = ?');
            $query->execute([ $id ]);
    
            if (false === $data = $query->fetch()) {
                throw new \Exception(\sprintf('Tweet with id "%d" not found.', $id));
            }
    
            $id = (int) $data['id'];
    
            // Исходные данные сохраняются для того, чтобы в дальнейшем вычислить изменения.
            $this->data[$id] = $data;
    
            $tweet = new Tweet($id, $data['content']);
    
            $this->identityMap[$id] = $tweet;
    
            return $tweet;
        }
    
        public function commit(): void
        {
            // Вообще говоря, лучше вычислить все изиенения, создать один "большой" запрос
            // и выполнить его внутри транзакции, но для простоты мы сделаем для каждого
            // изменения отдельный запрос
            $query = $this->connection->prepare('UPDATE tweets SET content = ? WHERE id = ?');
            foreach ($this->identityMap as $tweet) {
                if ($tweet->getContent() !== $this->data[$tweet->getId()]['content']) {
                    $query->execute([ $tweet->getContent(), $tweet->getId() ]);
                }
            }
        }
    }


    Полный пример можете скачить и посмотреть тут: https://gist.github.com/voronkovich/d35cdcdf6eb09e...
    Ответ написан
    1 комментарий
  • Почему в GetList не работает фильтр по IBLOCK_SECTION_ID?

    s_panteleev
    @s_panteleev
    25 yo, Yaroslavl
    В фильтр передавайте 'SECTION_ID' => 4, IBLOCK_SECTION_ID указывается в arOrder
    Ответ написан
    Комментировать
  • Как изменить текст кнопки при клике?

    like-a-boss
    @like-a-boss
    Признайся,тебяТянетНаКодМужика,ты—программный гей
    Например так:
    var readMoreBtn = document.querySelector(".js-btn-readmore"),
        readMoreContent = document.querySelector(".js-description-info");
    
    readMoreBtn.addEventListener("click", function(event) {
        event.preventDefault();
        readMoreContent.classList.toggle("js-readmore-show");
        this.textContent = this.textContent === 'Подробнее' ? 'Скрыть' : 'Подробнее';
    });
    Ответ написан
    7 комментариев
  • Как эффективно выучить технологии для backend'a?

    Нужно понимать, что от новичка (да даже откровенно говоря и от профи), знание вот этого всего не требуется. Поэтому условно делает свой новостной сайт на symfony + html+css+js + БД. Как его доделали, можно идти уже устраиваться на работу.
    Ответ написан
    4 комментария
  • Как сами спецслужбисты пользуются интернетом?

    GavriKos
    @GavriKos
    они пользуется самописными браузерами

    Ага, и Путин, и Навальный сами себе браузеры пишут.

    выкупленные айпи сервера

    Бери круче - выкупленные интернеты. У каждого свой.

    на каком железе сидят спецслужбисты, работники антивирусных компаний типа касперского?


    На процессоре Эльбрус же!

    То есть его нет?

    Не беспокойся, твоя история посещения порнхаба никому неинтересна. Да, товарищ майор?
    Ответ написан
    3 комментария
  • Как сделать простой php маршрутизатор (роутер)?

    devg
    @devg
    I am Yenior software developer
    Очень простой роутер, не без недостатков, но довольно быстрый и легко использовать, дописывать под себя.

    <?php
    /**
     * Простой роутер
     * @devg
     */
    final class RouterLite {
    
      public static $routes = array();
      private static $params = array();
      public static $requestedUrl = '';
    
      /**
       * Добавить маршрут
       */
      public static function addRoute($route, $destination=null) {
        if ($destination != null && !is_array($route)) {
          $route = array($route => $destination);
        }
        self::$routes = array_merge(self::$routes, $route);
      }
    
      /**
       * Разделить переданный URL на компоненты
       */
      public static function splitUrl($url) {
        return preg_split('/\//', $url, -1, PREG_SPLIT_NO_EMPTY);
      }
      
      /**
       * Текущий обработанный URL
       */    
      public static function getCurrentUrl() {
        return (self::$requestedUrl?:'/');
      }
    
      /**
       * Обработка переданного URL
       */
      public static function dispatch($requestedUrl = null) {
    
          // Если URL не передан, берем его из REQUEST_URI
          if ($requestedUrl === null) {
            $uri = reset(explode('?', $_SERVER["REQUEST_URI"]));
            $requestedUrl = urldecode(rtrim($uri, '/'));
          }
    
          self::$requestedUrl = $requestedUrl;
    
          // если URL и маршрут полностью совпадают
          if (isset(self::$routes[$requestedUrl])) {
            self::$params = self::splitUrl(self::$routes[$requestedUrl]);
            return self::executeAction();
          }
    
          foreach (self::$routes as $route => $uri) {
            // Заменяем wildcards на рег. выражения
            if (strpos($route, ':') !== false) {
              $route = str_replace(':any', '(.+)', str_replace(':num', '([0-9]+)', $route));
            }
    
            if (preg_match('#^'.$route.'$#', $requestedUrl)) {
              if (strpos($uri, '$') !== false && strpos($route, '(') !== false) {
                $uri = preg_replace('#^'.$route.'$#', $uri, $requestedUrl);
              }
              self::$params = self::splitUrl($uri);
                
              break; // URL обработан!
            }
          } 
          return self::executeAction();
      } 
    
     /**
       * Запуск соответствующего действия/экшена/метода контроллера
       */
      public static function executeAction() {
        $controller = isset(self::$params[0]) ? self::$params[0]: 'DefaultController';
        $action = isset(self::$params[1]) ? self::$params[1]: 'default_method';
        $params = array_slice(self::$params, 2);
    
        return call_user_func_array(array($controller, $action), $params);
      }
    
    }
    ?>


    Пример использования:
    <?php
    // маршруты (можно хранить в конфиге приложения)
    // можно использовать wildcards (подстановки):
    // :any - любое цифробуквенное сочетание
    // :num - только цифры
    // в результирующее выражение записываются как $1, $2 и т.д. по порядку
    
    $routes = array(
      // 'url' => 'контроллер/действие/параметр1/параметр2/параметр3'
      '/' => 'MainController/index', // главная страница
      '/contacts' => 'MainController/contacts', // страница контактов
      '/blog' => 'BlogController/index', // список постов блога
      '/blog/:num' => 'BlogController/viewPost/$1' // просмотр отдельного поста, например, /blog/123
      '/blog/:any/:num' => 'BlogController/$1/$2' // действия над постом, например, /blog/edit/123 или /blog/dеlete/123
      '/:any' => 'MainController/anyAction' // все остальные запросы обрабатываются здесь
    ));
    
    // добавляем все маршруты за раз
    RouterLite::addRoute($routes);
    
    // а можно добавлять по одному
    RouterLite::addRoute('/about', 'MainController/about');
    
    // непосредственно запуск обработки
    RouterLite::dispatch();
    ?>


    UPDATE (07.08.2017):
    Дальнейшее развитие данного роутера см. в проекте Litero (https://github.com/bit55/litero)
    Ответ написан
    1 комментарий
  • Почему wordpress редиректит на 127.0.0.1 при попытке входа?

    1. Отключите плагины (временно удалите файлы из папки)
    2. Смените тему
    3. Обновите WP (с заменой файлов, но не трогайте базу)

    создайте копию /wp-adminsha >> /wp-admin
    а то при удалении плагинов/темы не зайдете в админку
    Ответ написан
    Комментировать
  • Как Интегрировать amocrm с формой на сайте?

    в файле fields_info.php
    $need=array_flip(array('PHONE','EMAIL'));//,'WEB','IM','POSITION','SCOPE' убрать лишнее, чего нет в amocrm
    Ответ написан
    Комментировать
  • Как в nginx настроить открытие php файла при обращении к txt?

    @mezhuev
    Системный администратор
    Абсолютно так же:
    location / {
        rewrite ^/log\.txt$ /log.php;
    }
    Ответ написан
    Комментировать
  • Можно ли подключить второй SSD и объединить его с первым?

    Jump
    @Jump Куратор тега Windows
    Системный администратор со стажем.
    объединить его с первым SSD чтобы это был как единый логический диск P (Projects) состоящий из 2-х SSD-шников. И можно ли сделать это не очищая первый диск от проектов?

    Да элементарно
    • Вариант 1 монтируете его как папку на первый том.
    • Вариант 2 в диспетчере дисков преобразуете оба диска в динамические, после чего расширяете раздел на первом диске, местом на другом диске. Вот и все дела.


    Это что касается возможности.
    Но есть тонкости - SSD нельзя забивать под завязку, особенно такой SSD как KINGSTON SSDNow и ему подобные.
    Поэтому перед такими действиями оставьте в качестве резерва хотя бы 20-30Гигабайт на обоих дисках.
    Ответ написан
    4 комментария
  • Почему планировщик может не запускать скрипт, который работает при прямом обращении к нему через браузер?

    NeiroNx
    @NeiroNx
    Программист
    потому что скрипт для планировщика должен иметь другое начало
    #!/usr/bin/env php
    пишется в самой первой строке а потом может быть уже <?php
    Ответ написан
    Комментировать
  • Почему header() срабатывает после вывода контента?

    @vyrkmod
    Пишу на php. И не стыдно.
    Читать обязательно. Кратко: буфферизация вывода позволяет добавлять хэдеры "вне очереди", поскольку тело ответа не отправляется без команды. Но на проде буффер, очевидно, отключён. Искать "output-buffering" в php.ini.
    Ответ написан
    Комментировать
  • Как перенести БД сайта Laravel на хостинг?

    @bhu
    избавиться от хостинга
    Ответ написан
    Комментировать
  • Как открывать сайты на веб-сервере в локальной сети?

    Sanes
    @Sanes
    192.168.1.101 example.com www.example.com
    Иногда помогает разделение TAB-ами. Сначала пробуйте в браузере открыть IP адрес, должна быть заглуша веб-сервера. Очистите кеш в браузере или откройте в приватном окне. Очистите кеш DNS. В windows командной строке ipfonfig /flushdns

    В centos остановите файервол.
    service firewalld stop
    Ответ написан
    Комментировать
  • Как быстро и эффективно прокачать скилы в верстке?

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

    Курсы, книги, менторы и т д - это, конечно, хорошо.
    Но самая реальная польза - сверстайте из psd 3-5-10 макетов pixel perfect. И без всяких бутстрапов. После энного макета постигните дзен и все поймете. И чем макеты будут разнообразнее, чем больше в них адаптивности и хитрых элементов - тем лучше. По непонятным моментам спрашивайте на тостере. А так, судя по опыту коллег, иметь "некоторые представления о css" и подгугливать можно до бесконечности.
    Ответ написан
    1 комментарий
  • Как сверстать шестиугольники вокруг цифр?

    delphinpro
    @delphinpro Куратор тега CSS
    frontend developer

    второй варик
    Ответ написан
    Комментировать
  • Какой фреймворк выбрать для создания REST API под мобильное приложение?

    Недавно для небольшого проекта использовал slim . Довольно таки удобная штука.
    Ответ написан
    Комментировать
  • Можно ли как-то обратиться к удалённому серверу подменив свой ip?

    @kudis
    Bitrix developer
    Есть 3 решения:
    1. Открыть доступ для Вашего IP (можно маске, но лучше получить статический)
    2. Можно поднять прокси, тунель, VPN на сервере, локально подключаться к нему и работать от IP сервера
    3. Положить на рабочий сервер "костыльный тунельчик", чторый за Вас будет обращаться к серверу, просто зеркаля Ваши запросы. Типа такого, только, возможно, вам ещё строку запроса нужно будет получать и передавать, чтобы отправлять методы, раз у Вас SOAP
    if (!in_array($_REQUEST['token'],[
        'vremenniitoken' // нужен для ботов и недоброжелателей
    ])) {
        die();
    }
    
    header('Content-Type: application/json');
    echo file_get_contents('http://url/?' . http_build_query($_REQUEST['params']));

    может file_get_contents замените на CURL.
    Ответ написан
    Комментировать
  • Как мне быть в такой ситуации.Куда двигаться дальше?

    Хреновое у тебя настроение, 33 для програмиста не возраст, мне 42 и я несколько раз проходил путь от джуна до синьора, просто для встряски мозгов, последний раз менял специализацию в 39. Делай упор на английский, с хорошим английским работы море, при чем на удаленке платят больше чем на аутстаффе, правда и риски больше, кстати чтобы устроится на мидла, не запись в трудовой нужна "работал джуном год", а фактическое количество собранных граблей на технологии, на которые ты второй раз не наступишь, на собеседованиях просто спрашивают по матрице, поэтому необходимые навыки ты легко можешь узнать, просто регулярно проходя собеседования и подчитывая и реализуя то, на чем завалился. Завалив собеседование ты не ЧСВ должен понижать, а просто понимать, что ты узнал, что нужно доучить и идти на следующее собеседование.
    Ответ написан
    Комментировать