• Как правильно настроить аутентификацию для rest api?

    nokimaro
    @nokimaro
    Меня невозможно остановить, если я смогу начать.
    Как правило если есть некий личный кабинет, то пользователь может авторизоваться в нём и сгенерировать token/api-key который вы привязываете в базе к пользователю и по нему авторизуете клиента при обращении к api. Клиент может использовать этот api-key для работы с api

    1. войдите в кабинет
    2. получите api ключ
    3. используйте этот ключ для работы с api

    p.s. если выберете этот путь, не забудьте дать пользователю возможность перевыпустить api-ключ на случай его утечки или компрометации.
    Ответ написан
    1 комментарий
  • Можно ли использовать сервисы в rich моделях?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    а? Если нет и нужно все равно писать абсолютно всю логику в обьекте модели, то тогда он станет просто god обьектом на 100500 строчек

    Потому что вы все делаете наоборот!

    Пишите по бизнес-процессу ваши UseCase, это некоторый хэндлер к примеру
    Пример
    final class HandleCheckOutShoppingCart
    {
        public function __construct(Carts $carts, PaymentGateway $gateway)
        {
            $this->carts   = $carts;
            $this->gateway = $gateway;
        }
    
        public function __invoke(CheckOutShoppingCart $command) : void
        {
            $shoppingCart = $this->carts->get($command->shoppingCart());
    
            $payment = $this->gateway->captureCharge($command->charge());
    
            $shoppingCart->checkOut($payment);
        }
    }


    Потом у вас вырисовываются границы сущности, и в сущностях уже инварианты, которые контролирует эта сущность. Никаких god object
    Ответ написан
    5 комментариев
  • Как подключиться к Redis с php через docker?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега PHP
    Что у вас docker-compose ps показывает - все ли контейнеры запущены?

    192.168.0.1
    Это ip хоста, там Редиса нет.

    127.0.0.1
    Это локалхост, там Редиса нет.

    0.0.0.0
    Это вообще невалидный ip.

    redis
    А вот по имени он должен бы работать. Вам нужно выяснить имя сети и сделать docker network inspect %name%, чтобы увидеть ip Редиса - с ним должно работать точно.
    Ответ написан
    4 комментария
  • Как правильно применить полиморфизм?

    SilenceOfWinter
    @SilenceOfWinter Куратор тега PHP
    та еще зажигалка...
    реализуй шаблон strategy + decorator
    Ответ написан
    2 комментария
  • Откуда гугл берет картинку для сайта в поисковой выдаче?

    ConstKen
    @ConstKen
    Не знаю как для гугла но ЯША вот что мне ответил )
    Такая картинка формируется автоматически исходя из наличия подходящих картинок на сайте, при этом учитывается множество других факторов, среди которых, например, присутствие картинки на Я.Картинках.

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

    Также вопрос про картинку в сниппете я описал в своем блоге: https://yandex.ru/blog/platon/snippety-populyarnoe
    Ответ написан
    Комментировать
  • Как разделить сессии на разных вкладках браузера(альтернативы сессиям)?

    @AUser0
    Чем больше знаю, тем лучше понимаю, как мало знаю.
    Каждой вкладке присвоить свой уникальный $TAB=uniqid(), и при каждом переходе/загрузке страницы/сабмите формы использовать его во всех URL (site.org/index.php?TAB=$TAB) и во всех формах (<input type=hidden name=TAB value='$TAB'>). Так и дифференцировать.
    Ответ написан
    Комментировать
  • Как разделить сессии на разных вкладках браузера(альтернативы сессиям)?

    solotony
    @solotony
    покоряю пик Балмера
    1) не хранить данные в сессии (только данные идентификации, настройки)
    2) явно ввести в URL тип и идентификатор того с чем ты работаешь (если их несколько - да, значит несколько типов и идентификаторов)
    3) сохранять данные в хранилище привязываясь к типу+идентификатору
    Ответ написан
    Комментировать
  • Почему я не могу получить entity с репозитория в Doctrine?

    BoShurik
    @BoShurik Куратор тега Symfony
    Symfony developer
    https://www.doctrine-project.org/projects/doctrine...

    referencedColumnName: Name of the primary key identifier that is used for joining of this relation.


    /**
     * @OneToMany(targetEntity="Address", mappedBy="customer", cascade={"persist", "remove"})
     * @JoinColumn(name="customer_id", referencedColumnName="customer_id")
     */
    protected $addresses;


    Address::$customer_id - это primary key?

    Не заметил, что вы JoinColumn применяете к OneToMany. Оно не применимо, должно быть что-то вроде этого:
    /**
     * @Entity
     * @Table(name="`address`")
     */
    class Address
    {
        /**
         * @Id
         * @Column(type="integer")
         * @GeneratedValue(strategy="IDENTITY")
         */
        protected $address_id;
        /**
         * @Column(type="string")
         */
        protected $firstname;
        /**
         * @ManyToOne(targetEntity="Customer", inversedBy="address")
         * @JoinColumn(name="customer_id", referencedColumnName="customer_id")
         */
        protected $customer;
    }
    
    /**
     * @Entity(repositoryClass="\Core\Repositories\CustomerRepository")
     * @Table(name="`customer`")
     */
    class Customer
    {
        /**
         * @Id
         * @Column(type="integer")
         * @GeneratedValue(strategy="IDENTITY")
         */
        protected $customer_id;
        
        /**
         * @OneToMany(targetEntity="Address", mappedBy="customer", cascade={"persist", "remove"})
         */
        protected $addresses;
    
        public function __construct()
        {
            $this->addresses = new ArrayCollection();
        }
    }
    Ответ написан
    8 комментариев
  • Почему join column в Doctrine присваивается null перед flush?

    BoShurik
    @BoShurik Куратор тега Symfony
    Symfony developer
    https://www.doctrine-project.org/projects/doctrine...

    referencedColumnName: Name of the primary key identifier that is used for joining of this relation.


    /**
     * @OneToOne(targetEntity="\Core\Entities\Delivery\BoxberryTtn", mappedBy="ttn_boxberry", cascade={"persist", "remove"})
     * @JoinColumn(name="order_code", referencedColumnName="id")
     */
    protected $boxberry_ttn;


    Если хочется, чтоб была связь через order_code, то сделайте его primary key:
    /**
     * @Entity
     * @Table(name="`ttn_boxberry`")
     */
    class BoxberryTtn
    {
        /**
         * @Id
         * @Column(type="string")
         * @GeneratedValue(strategy="NONE")
         */
        protected $id;
        
        public function __construct(string $id)
        {
            $this->id = $tid;
        }
    }


    Плюс, у вас два поля order_code
    /**
     * @Entity
     * @Table(name="`order`")
     */
    class Order
    {
        /**
         * @Id
         * @Column(type="integer")
         */
        protected $order_code;
    
        /**
         * @OneToOne(targetEntity="\Core\Entities\Delivery\BoxberryTtn", mappedBy="ttn_boxberry", cascade={"persist", "remove"})
         * @JoinColumn(name="order_code", referencedColumnName="order_code")
         */
        protected $boxberry_ttn;
    }


    Они так же друг другу могут перезаписывать

    В идеале должно быть что-то вроде этого

    /**
     * @Entity
     * @Table(name="`order`")
     */
    class Order
    {
        /**
         * @Id
         * @Column(type="integer")
         */
        protected $order_id;
    
        /**
         * @Id
         * @Column(type="integer")
         */
        protected $order_code;
    
        /**
         * @Column(type="integer")
         */
        protected $warehouse_id;
    
        /**
         * @OneToOne(targetEntity="\Core\Entities\Delivery\BoxberryTtn", cascade={"persist", "remove"})
         * @JoinColumn(referencedColumnName="order_code")
         */
        protected $boxberry_ttn;
    
        public function __construct(int $order_id, string $order_code)
        {
            $this->order_id = $order_id;
            $this->order_code = $order_code;
        }
    }
    
    /**
     * @Entity
     * @Table(name="`ttn_boxberry`")
     */
    class BoxberryTtn
    {
        /**
         * @Id
         * @Column(type="string")
         * @GeneratedValue(strategy="NONE")
         */
        protected $order_code;
    
        /**
         * @Column(type="string")
         */
        protected $ttn_num;
    
        /**
         * @Column(type="float", scale=2)
         */
        protected $delivery_cost;
    
        public function __construct(Order $order)
        {
            $this->order_code = $order->getOrderCode();
        }
    }

    Ответ написан
    3 комментария
  • Почему через postman возвращается непонятная разметка(document.cookie="CPB=1a3d5fcd20b61d1cfa2fa6efe1e4be0a";document.location.h)?

    dimonchik2013
    @dimonchik2013
    non progredi est regredi
    антискрапер

    еще и переменные любезно назвали чтобы тебе было понятно: attempt
    Ответ написан
    Комментировать
  • Как правильно настроить elasticsearch под неточный поиск?

    leahch
    @leahch
    3D специалист. Dолго, Dорого, Dерьмово.
    Fuzzy здесь не поможет, нужно разбивать слова с цифрами на отдельные термы -
    i007a -> i 007 a
    versioni007plus -> versioni 007 plus
    И т.д.
    Это можно сделать через regexp character filter регулярным выражением, и складывать в отдельное дополнительное поле. Поиск делать по нескольким полям сразу.
    Также можно попробовать char group tokenizer или pattern tokenizer с регуляркой, которая бьет текст и цифры отдельно
    Ответ написан
    3 комментария
  • Почему зависает сервер при shell_exec("mysql -uroot -p -h localhost -D cart_open < F:/OSPanel/domains/test/db_migration/0000_base.sql")?

    tacitus
    @tacitus
    веб-программист
    Подвисает, когда ожидается ввод пустого пароля. Попробуйте так:
    shell_exec("mysql -uroot --password='' -h localhost -D cart_open < F:/OSPanel/domains/test/db_migration/0000_base.sql")
    или
    shell_exec("mysql -uroot -h localhost -D cart_open < F:/OSPanel/domains/test/db_migration/0000_base.sql")
    Ответ написан
    Комментировать
  • Переход с постоянки на фриланс, стоит ли игра свеч?

    search
    @search
    мама говорит что я особенный
    Ох как я вас понимаю. Перейти на фриланс страшно. А вдруг не будет клиентов? А вдруг я получу негативный отзыв? А вдруг меня кинут? В общем куча а вдруг. В 2010 году я осуществил следующие приготовления перед переходом на фриланс на апворке:
    • сдал все профильные тесты на топ 10%. Для этого понадобилось где-то 3 месяца и прочтение нескольких книг. Оно того стоило
    • накопил 2 месячных зарплаты на случай полного провала
    • объяснил начальнику свою ситуацию и договорился что смогу вернуться если ничего не выйдет


    Клиента я нашел дня через 2. Она платила мне фантастические на тот момент 10 баксов в час, а потом подняла до немыслимых 18.

    Общие рекомендации:
    • берите только почасовую работу, если не хотите получить стресс и переработку
    • работайте только с иностранцами, потому что им можно не объяснять что за каждый час работы нужно платить всегда и при любых раскладах
    • объясните заказчику что 8 часов на фрилансе под наблюдением всевидящего ока - это не 8 часов в офисе, прогуливаясь к кофемашине. Вы не сможете долго работать по 8 часов, перегорите. 6 - это в лучшем случае
    • сделайте оплату комиссии проблемой заказчика. Так и говорите "мой рейт, например, 10 баксов в час, комиссия сайта 30%, так что вам это будет стоить 13 долларов". Будет дополнительный фильтр для хитросделанных заказчиков, с которыми работать не нужно


    Посмотрите на биржу Toptal. Это как постоянная работа, только платят хорошо.
    Ответ написан
    2 комментария
  • Знание которые не устареют через 10-20 лет?

    search
    @search
    мама говорит что я особенный
    Существует набор базовых знаний, находящийся в корне любой ИТ-концепции. Эти знания редко применяются программистами напрямую, так как они реализованы непосредственно в библиотеках. Но они оказывают огромное влияние на общий процесс мышления и на способность усваивать новую информацию. Именно поэтому такие успешные компании, как Гугл, Эпл, Амазон, Фейсбук и т.д. прежде всего проверяют базовые знания, а не знание языков/фреймворков/библиотек, потому что это всё вторично и осваивается за пару недель. Да, такие штуки, как:
    • теория вероятностей и математическая статистика
    • теория игр
    • теория информации и кодирования
    • теория тестирования
    • теория систем массового обслуживания
    • теория принятия оптимальных решений

    занимают чуть больше, чем пару недель, но в них нет ничего принципиально невозможного.

    Не стоит обманываться тем что мы редко встречаем специалистов с глубокими базовыми знаниями. Просто подобные люди находятся, чаще всего, не в зоне нашего обитания, а где-нибудь в Калифорнии, работая в компаниях из списка Fortune 500. Такие дела.
    Ответ написан
    Комментировать
  • Правильно ли я использую делегирование?

    dmitriylanets
    @dmitriylanets
    веб-разработчик
    так то User у вас не модель, а репозиторий:
    namespace Repository;
    
    class User {
    
        protected $db;
    
        public function __construct(Adapter $db) {
            $this->db = $db;
        }
    
        public function getUserById($id) {
    
            $sql = "SELECT * FROM user  WHERE id = :id";
            $stmt = $this->db->prepare($sql);
            $stmt->bindParam(':id', $id, PDO::PARAM_INT);
    
            $stmt->execute();
    
            return $stmt->fetch();
        }
    
        public function getImageById($id) {
    
    
            $sql = "SELECT  IF(image IS NULL or image = '','no_image.png',image) as image  FROM `user` WHERE id = :id";
    
    
            $result = $this->db->prepare($sql);
            $result->bindParam(':id', $id, PDO::PARAM_INT);
            $result->execute();
    
            return $result->fetchColumn();
        }
    
        public function updateImageById($imageName, $id) {
    
            $sql = "UPDATE user SET image = '$imageName' WHERE id = $id";
    
            return $this->db->query($sql);
        }
    
    }

    для работы с изображениями я предпочел бы сервис:
    namespace Service;
    
    class Image {
    
        protected $userRepo;
    
        function __construct(Repository\User $userRepo) {
    
            $this->userRepo = $userRepo;
        }
    
        public function UploadImage(array $image) {
    
            $usersImage = $image['userfile']['tmp_name'];
    
            $imageName = $image['userfile']['name'];
    
            if (is_uploaded_file($image['userfile']['tmp_name'])) {
    
                move_uploaded_file($usersImage, $_SERVER['DOCUMENT_ROOT'] . "/template/images/users/" . $image['userfile']['name']);
            }
    
            return $imageName;
        }
    
        public function updateImage(array $image, $id) {
            if($imageName = $this->uploadImage($image, $id)) {
                $this->userRepo->updateImageById($imageName, $id);
                return true;
            }
        }
    
    }

    а теперь самое интересное контроллер:
    class UserController extends BaseController {
    
        protected $imageService;
        protected $userRepo;
    
        function __construct(Service\Image $imageService, Repository\User $userRepo) {
            $this->imageService = $imageService;
            $this->userRepo = $userRepo;
        }
    
        public function actionProfile($id) {
    
            if (isset($_POST['submit_photo'])) {
    
                $this->imageService->updateImage($_FILES, $id);
            }
    
            return $this->render('user/profile.php', [
                        'user' => $this->userRepo->getUserById($id),
                        'image' => $this->userRepo->getImageById($id)
            ]);
        }
    }
    Ответ написан
    2 комментария
  • Правильно ли я использую делегирование?

    edtoken
    @edtoken
    Full-stack Javascript/Python Developer
    Думаю, стоит отделить независимые элементы логики.
    Есть класс для работы с изображениями?
    Пусть с ними и работает, он не должен знать что есть какой-то user_id

    Есть пользователь и у него есть аватарка? Ок, класс пользователя может выдернуть нужный img_id и передать его в Image
    Ответ написан
    Комментировать
  • Правильно ли я использую делегирование?

    search
    @search
    мама говорит что я особенный
    Во-первых, вы молодец, что движетесь в этом направлении. Продолжайте в том же духе.

    По коду есть следующие замечания/предложения по улучшению:
    - Делегирование подразумевает передачу некоторого функционала другому объекту. По сути, когда вы создали объект класса и выполнили метод этого объекта - вы уже делегировали некую функциональность. Например в контроллере задачу по выборке юзера вы делегировали объекту класса User. В случае же с классами User и Image, происходит внедрение класса Image в User (привет Dependency Injection), но дальше Image никак не используется классом User. Т.е. происходит Dependency Injection, но нет делегирования. На том этапе, который я сейчас вижу, я бы не стал внедрять Image в User. Сейчас это выглядет как задел на будущее, но любой опытный программист подтвердит, что композиция, созданная на будущее - ненужная композиция.
    - Глядя на структуру классов, мне не совсем понятно чем они занимаются. Вроде как класс User и Image должны хранить информацию о пользователе и картинке (об этом нам говорит $id в конструкторе). Но в тех же классах есть логика по выборке данных из базы. По-хорошему выборкой должны заниматься другие классы. Лучше разделить задачи выборки и хранения на 2 разных класса. Я очень рекомендую вам ознакомиться с паттерном Data Mapper (наример тут designpatternsphp.readthedocs.io/en/latest/Structu... или тут codeinthehole.com/projects/domain-model-mapper-a-p... На мой взгляд, Data Mapper - это то что вам сейчас нужно реализовать чтоб получить чёткую структуру кода и разделение ответсвенности за выбор/хранени.

    По поводу делегирования. Просто старайтесь чтоб ваши классы были как можно меньше. Критерий 1-3 метода на один класс вполне может подойти (помните, что это не золотое правило). Когда у вас появится желание добавить еще один метод в класс A - спросите себя, а нужен ли там вообще этот метод? Может лучше переложить всю ответственность на новый класс B, в который вы будете передавать объект A (или какое-то из его полей), а сам класс B уже проведёт необходимые преобразования/вычисления? Это и будет делегирование в том виде, в котором его ждёт от нас банда четырёх (если вы еще не читали их книгу, то это must read для любого программиста).

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

    @D3lphi
    Каждый класс должен отвечать только за что-то одно. Об этом говорит буква S в аббревиатуре SOLID (single responsibility, единственная ответственность). Следовательно, ни пользователь, ни класс регистрации не "должен" знать что-то про то как происходит загрузка изображений. Эту функциональность нужно выносить в отдельный класс (сервис).
    Ответ написан
    3 комментария
  • Как проверять даные формы через ajax в MVC?

    coderisimo
    @coderisimo
    А зачем делать вид ? Мы можете просто из метода контроллера вернуть результат проверки.
    Ответ написан
    4 комментария