• Yii2 tinymce загрузка изображений. Как?

    @maxyc_webber
    Web-программист
    если есть возможность, ставь CKEDITOR и ckfinder

    "iutbay/yii2-kcfinder": "*",
    "2amigos/yii2-ckeditor-widget": "~1.0@dev",

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

    Audiophile
    @Audiophile Автор вопроса
    Оказывается, надо было прописать полный путь к папке ext.

    extension_dir = c:\php\ext\
    Ответ написан
    Комментировать
  • Как валидировать абсурдные суждения/предложения?

    @Dmtm
    Android
    только статистикой, при распознавании мы вынуждены предполагать что текст для говорящего имеет смысл, а делать вывод об абсурдности - только через накопление типичных использованных свойств
    т.е. после обучения на 10000 текстов - для объектов будут выделены типичные свойства
    и если скажем обучать на авангардных стихах то исходный пример - будет осмысленным, это нормально
    абсурдность = мнение большинства, т.е. статистика
    Ответ написан
    Комментировать
  • Что делать, если нужно получить часть данных сущности?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Для отображения используйте DTO и доставайте их из репозитория. Для логики отображения негоже сущности из бизнес-слоя вытягивать.

    1 способ — заюзать Доктрину
    сразу не увидел, что вы без нее работаете

    Доктрина умеет создавать дтошки из коробки
    class PostDTO
    <?php
    
    namespace App\DTO;
    
    class PostDTO
    {
        /** @var string */
        private $name;
        
        /** @var string */
        private $description;
        
        /** @var string */
        private $text;
        
        public function __construct(string $name, string $description, string $text)
        {
            $this->name = $name;
            $this->description = $description;
            $this->text = $text;
        }
    
        public function getName()
        {
            return $this->name;
        }
    
        public function getDescription()
        {
            return $this->description;
        }
    
        public function getText()
        {
            return $this->text;
        }
    }

    И используя синтаксис NEW DQL создаем наши DTO :
    $query = $em->createQuery('SELECT NEW App\DTO\PostDTO(p.name, p.description, p.text) FROM App\Entity\Post p');
    $users = $query->getResult(); // array of PostDTO

    Источник: https://www.doctrine-project.org/projects/doctrine...

    2 способ — заюзать DBAL/PDO
    Сделать запросы через более низкую прослойку без ORM (например через Doctrine DBAL или PDO) и результат фетчить в те же самые PostDTO в репе
    Ответ написан
    2 комментария
  • Doctrine does not have a property named "mappedBy"?

    @Flying
    Всё очень просто: В коде Product в строке 123 вы используете
    @ORM\ManyToOne(targetEntity="Category", mappedBy="product")

    тогда как для ManyToOne необходимо использовать inversedBy, это прямо описано в документации и видно в коде этой аннотации.
    Ответ написан
    Комментировать
  • Как сделать unit test метода в котором нужен заполненный массив?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    По-хорошему $this->solutions должно устанавливаться через конструктор, потому вам не составит труда заинжектить это состояние в тестируемый объект.

    Если у вас "пришлось", то можете заюзать некий хак, например через рефлексию/closure::bind установить состояние в тестируемый объект.

    Вот на скорую руку накидал (Разместите его в своем TestCase или прямо в тесте)
    protected function setPrivateProperty(object $object, string $propertyName, $value): void
    {
        $reflectionClass = new \ReflectionClass(get_class($object));
        $property = $reflectionClass->getProperty($propertyName);
        
        $property->setAccessible(true);
        $property->setValue($object, $value);
        $property->setAccessible(false);
    }


    ПРИМЕР
    Класс и метод, который нужно протестить и приватная переменная которого заполняется не через конструктор
    class System 
    {
        // Не важно, как оно будет заполнено, важно, 
        // что в методе мы проверяем некоторые значения  
        // и мы создадим ниже в тестах эти ситуации разными тест-кейсами
        private $solutions;
    
        public function checkRecords(): string
        {
            if (count($this->solutions) === 3) {
                return 'full';
            }
    
            if (count($this->solutions) === 6) {
                return 'overflow';
            }
    
            throw new IncorrectCountException('Incorrect solutions count.');
        }
    }


    Тесты
    public function testCheckRecordsFull(): void
        {
            // 3 элемента
            $data = [1, 2, 3];
            $system = new System();
            $this->setPrivateProperty($system, 'solutions',  $data);
    
            $status = $system->checkRecords();
    
            $this->assertEquals('full', $status);
        }
    
        public function testCheckRecordsOverFlow(): void
        {
            // 6 элементов
            $data = [1, 2, 3, 4, 5, 6];
            $system = new System();
            $this->setPrivateProperty($system, 'solutions',  $data);
    
            $status = $system->checkRecords();
    
            $this->assertEquals('overflow', $status);
        }
    
        public function testCheckRecordsIncorrectCOunt(): void
        {
            // сколько-то элементов, но не 3 и не 6
            $data = [1];
            $system = new System();
            $this->setPrivateProperty($system, 'solutions',  $data);
    
            $this->expectException(IncorrectCountException::class);
            $system->checkRecords();
        }

    Код тестовый, просто отобразить принцип, возможно у вас в классе зависимости -- нужно будет сделать моки и т.д. Тут некоторые повторения можно вынести в setUp().
    Также хочу обратить внимание, что тесты построены по принципу ААА (Arrange, Act, Assert).
    Как итог, 3 ситуации, все протестированы, методу не важно, как заполнлась приватная переменная, но вся его логика протестирована. Все легко и просто.
    Ответ написан
    7 комментариев
  • Dependency Injection Container, попробовал на практике - не понял смысла?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Контейнер
    Главная задача контейнера — переиспользовать сервисы более одного раза, например некий провайдер более чем в 1 месте или некий Sender в 20 местах по всему приложению. И упростить к ним доступ.

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

    Взаимодействие относительно простых объектов/сущностей в рамках одного слоя лучше делать вашим способом — оно логичное и понятное и вообще контейнер будет только мешать, даже больше — не к месту в этой задаче. Это вам в ответе на том форуме и отметили.

    Современные контейнеры предоставляют на самом деле еще ооочень много фишек: автовайринг, когда вам и конфиг писать не нужно, просто в конструкторе написали класс, а контейнер если нашел такой класс, то сам и сконфигурирует (и также учтет его параметры конструктора), то есть разработчику остается работа только с уникальными и не стандартными ситуациями.
    Или дает упрощенные фабрики/билдеры/декораторы.

    Dependency Injection
    И в будущем удобно будет тестировать ?

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

    Главное не объединяйте эти два понятия. Сам паттерн — просто частный случай инверсии зависимости, класс получил зависимость через конструктор/сеттер, и все, он не знает деталей, потому и тестить проще — просто подменил на пустышку.
    А контейнер — средство для работы со сложным приложением, которое внедряет как раз таки, то есть выполняет работу внедрения. Центральное в нем — слово контейнер.

    Несколько точек входа
    По поводу ваших точек входа: несколько точек входи = несколько иницализаций.
    Как-бы они разные по своей сути приложения уже по определению получаются.
    Но вы можете упростить, и вынести инициализацию контейнера в абстракцию — в некий класс App/Kernel и там это делать, а в точке входа инициализировать не контейнер раз за разом, а именно конкретное приложение.
    Ответ написан
    7 комментариев
  • Где лучше качество кода?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    Все плохо
    • Глобальные переменные — зло
    • На лицо некий код, который и с сессией работает и с БД — явное нарушение общепринятных принципов, например SRP
    • $dao как инициализирована? Явно не через конструктор
    • Использование цифры, вот сиди гадай по ней — это плохо, используйте именованную константу. Например 3 — это некий статус для desktop, вот и назовите ее STATUS_DESKTOP, хотя далее...
    • вы обращаетесь к одному методу, который шибко умный — работает с флагами, тем самым нарушая SRP и сам содержит if/else, сделайте просто 2 раздельных метода:
      getMobileOpinionList()
      getDefaultOpinionList()

    • Предикат лучше вынести в отдельный метод isMobileOnly(), тк условия могут поменяться в нем, не будете же везде в if менять по всему проекту
    Ответ написан
    33 комментария
  • Почему всем так нужен Doctrine, если он много не умеет?

    @Flying
    Doctrine реализует концептуально другой подход к работе с данными, именно в этом её большое преимущество и именно из этого следуют её ограничения.

    Если вы когда-нибудь сталкивались с паттернами проектирования то, возможно, слышали о таком человеке как Мартин Фаулер и о его книге "Patterns of Enterprise Application Architecture". В ней описываются паттерны проектирования enterprise level приложений. В этой книге Фаулер предложил набор паттернов, организующих работу с источниками данных через представление этих данных в виде связанных между собой объектов. В этот набор входят Data Mapper, Identity Map, Unit of Work и множество других паттернов.

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

    Попробуйте представить себе большой бизнес-проект над которым работают множество людей, в котором есть сотни видов данных, взаимодействующих друг с другом и определены сложные процессы вовлекающие множество видов данных. Разумеется это все можно написать и поддерживать вручную, таких примеров много, вопрос в стоимости подобной работы. Представьте себе необходимость вручную описывать последовательность запросов для сохранения данных в 20 таблиц и необходимость поддерживать корректность этого кода при всех следующих изменений бизнес-требований проекта. Уверен, если после полугода подобной работы вам предложат заменить всё это на одну строку $em->flush() - вы с радостью согласитесь и, возможно, тогда поймёте что даёт Doctrine разработчику.

    Именно из идеи перевода фокуса разработчика с деталей реализации хранилища данных на детали реализации бизнес-логики проекта рождаются ограничения Doctrine. Они могут восприниматься негативно если пытаться воспринимать Doctrine и DQL как урезанный SQL, почему-то возвращающий объекты, а не массивы. Да, разумеется какие-то сложные аналитические запросы вы на DQL не построите, но это только потому что у Doctrine другая цель. Если посмотреть на DQL чуть пристальнее (к примеру на то как в нём описываются join'ы) то можно заметить что Doctrine отталкивается не от того как данные разложены по таблицам, а от того как данные представлены в entities. Это не самое заметное, но очень важное отличие т.к. оно определяет пространство операций над данными. Грубо говоря приведённый вами ifnull() в DQL становится довольно бессмысленной конструкцией т.к. эта функция довольно слабо применима к объектам.

    Разумеется в реальных проектах зачастую бывают задачи которые требуют работы с данными в базе данных за пределами Doctrine, это нормально, ни один инструмент не является всеобъемлющим. Однако описываемые вами "недостатки" Doctrine проистекают скорее от непонимания того что это за инструмент и зачем он нужен, какие задачи он призван решить. Это непонимание устраняется через изучение того с чем вы работаете на более глубоком уровне. Если вы решите устранить его - вы получите в свои руки один из лучших инструментов для работы с данными в бизнес-проектах который только есть в мире PHP и тогда, надеюсь, сможете оценить его по достоинству.
    Ответ написан
    Комментировать
  • Как работает подход 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 комментарий
  • Как работает подход 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 комментариев
  • Где symfony DI собирает все зависимости?

    @Flying
    Если говорить именно об аргументах контроллера, то они собираются в ArgumentResolver::getArguments() на основании метаданных (получаемых через reflection) из ArgumentMetadataFactory::createArgumentMetadata. Передача аргументов в action контроллера идёт при его вызове здесь.

    Если же речь идёт об общем случае то там схема существенно сложнее т.к. непосредственно инициализация сервисов очень сильно отличается в зависимости от настроек контейнера в отношении конкретного сервиса (вспоминаем про factories, абстрактные сервисы и т.п.), но в общем случае все варианты приводят к генерации соответствующего метода в контейнере.
    Ответ написан
    Комментировать
  • Зачем в web пишут src="blob: путь"?

    v_decadence
    @v_decadence
    Затем, чтобы указать путь к данным, которые находятся не на сервере, а в памяти Вашего браузера.
    Получить его можно через URL.createObjectURL(file).

    A blob: URL does not refer to data the exists on the server, it refers to data that your browser currently has in memory, for the current page. It will not be available on other pages, it will not be available in other browsers, and it will not be available from other computers


    Convert blob URL to normal URL
    Ответ написан
    Комментировать
  • Какой корректный share url в Одноклассниках?

    @ange007
    Программист, просто программист.
    Если речь о шаринге ссылки на свою страницу ОД:
    http://www.odnoklassniki.ru/dk?st.cmd=addShare&st.s=1&st._surl={ссылка}&st.comments={комментарий}
    Ответ написан
    1 комментарий
  • Где найти внятный пример построения графиков на php или js?

    @axeax
    например, получаем с сервера данные в виде
    [{day: 1, visitors: 10},{day: 2, visitors: 20},{day: 3, visitors: 15}]

    и в js рисуем svg линию с координатами
    x - день
    y - посещения
    какие еще правила то? Для работы с svg в js лично я использую svgjs.com
    Ответ написан
    2 комментария
  • Будет ли выполняться сценарий в расширении вне фокуса вкладки?

    Будет, есть определённые тонкости в работе таймеров в фоновых вкладках хрома, но в целом все будет работать.
    Если открыты две одинаковые вкладки, то они вместе будут работать, и выполнять один и тот же код.
    Можно использовать master slave механизмы для организации работы нескольких вкладок, если требуется выполнение кода только на одной открытой вкладке.
    Ответ написан
    3 комментария
  • Где бы взять внятную понятную информацию с практической частью про ИИ?

    dimonchik2013
    @dimonchik2013
    non progredi est regredi
    вот тут neuralnet.info + видик на Ютубе

    там не все "типа как принято", да и про конечные автоматы, кажется, не очень говорит, но для понимания принципа этого достаточно

    и да, никакого ИИ нет. Есть просто масив инфы и алгоритмы извлечения из него обобщенной информации
    Ответ написан
    2 комментария
  • Почему гугл карты загружаются не сразу?

    Falseclock
    @Falseclock
    решаю нестандартные задачи
    а если так?

    document.observe
    (
    	"dom:loaded", 
    	function()
    	{
    		// put your code here
    	} 
    );
    Ответ написан
    5 комментариев