Я это делал, но не понимаю как загрузить Entity из БД. В примерах везде используют EntityManager, но как до него добраться не пойму. примеры смотрел тут http://symfony.com/doc/current/doctrine.html
Такой пример я видел, но $this в каком контексте? Вот мой код
require "/path/to/symfony/vendor/autoload.php";
use AppBundle\Entity\Server;
use Symfony\Component\Console\Application;
$app = new Application();
$app->run();
Мне тупо нужно создать Entity и загрузить в него данные из БД
Это какая то команда создалась... я как понимаю ее ещё запускать нужно, короче бред полный, все это не то. Мне нужно дергать из любого места моего консольного скрипта классы логики(которые лежат в AppBundle), которые общие между сайтом и консольными скриптами, но что толку их дергать, если тупо нет доступа к базе даже
require "/vendor/autoload.php";
class CreateUserCommand extends \Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand
{
// ...
protected function configure()
{
$this
->setName('app:create-user')
->setDescription('Creates a new user.')
->setHelp('This command allows you to create a user...')
;
}
protected function execute()
{
$doctrine = $this->getContainer()->get('doctrine');
var_dump($doctrine);
}
}
new CreateUserCommand()
Так и работой в execute, что мешает? Вообще надо это создавать в контексте AppBundle и не создавать непонятно где еще один файл где все делать непонятно как.
Ну мне кажется это костыль какой то. Создавать какую то команду, потом ее запускать.
Это правильный путь если ты хочешь работать в контексте всего остального кода написанного на Symfony (и не только). Тебе это кажется костылем лишь из-за отсутствия опыта.
Как правильней сделать то?
1.Идешь в папочку src/AppBundle/Command
2. Создаешь класс для своей команды как это делал ранее (просто класс, ничего более не надо)
3. В нем реализовываешь всю логику необходимую для работы команды
4. php bin/console my-command (в корне проекта естественно)
Понятно, спасибо, попробую сделать так. Вообще я думал, что симфонию прикручу к скрипту консольному, а получается нужно наоборот делать, симфония будет запускать, все инициировать
Кстати забыл сказать, скрипт у меня будет работать беспрерывно в режиме ожидания, ну типа демона, для этого я \React\EventLoop использую. Такое будет в симфонии работать?
В примерах его берут в контролерах, а откуда контролеры в консоле?
Ну вообще-то там и должны быть консольные контроллеры. Но вообще взять можно из DI-контейнера, он же ServiceContainer в терминологии symfony. Гляди https://symfony.com/doc/current/service_container.html там прям в качестве примера достают em.
Ну а если тебе контроллеры (т.е. роуты) не нужны, то как я тебе советовал просто накати доктрину через композер и всё. Скаффолдинг и прочие плюшки у доктрины есть свои.
Т.е. в целом сейчас подход такой - композер это и есть фреймворк, накатываем компоненты по вкусу.
Вот этого я тоже хотел добиться с самой первой минуты изучения симфонии )) Потому что это же дурость, что сам Entity не может самого себя загрузить, вместо того что бы делать
\App\Product::load($id)
В доках везде примеры, что нужно сначала какой то EntityManager взять, потом репозитарий, оттуда сделать выборку. Причем $em ещё так неявно получить можно
Так симфония и устанавливается через коспозер, там же есть и доктрина. Но мне то нужно, чтобы было все единый проект, классы то едины что для веба, что для консольного скрипта. В корне проекта лежит composer.json
Я хочу, чтобы классы сами в себя загружали данные из БД, т.е. про EntityManager и прочие специфичные вещи фреймворка я не хочу знать, все должно абстрагироваться в самих классах. Т.е. консольный скрипт берет только часть «бизнес-логики», которая находиться в фреймворке, а сам не должен знать о существовании его(фреймворка). Ну или как сделать то? Нужны разделяемые классы, которые можно использовать где угодно
Я же говорю — инъекция :) У каждой модели указывается класс её бэкенда. То есть каждая модель — законченная сущность и система знает, что с ней делать без прямого привлечения контроллера.
Как я сказал выше, это не чисто академический MVC получается, у меня элементы контроллера много где размазаны, зато в работе получается намного удобнее.
А вот уже в классе Model указывается и бэкенд, типа
<?php
class Model extends \B2\Obj
{
function storage_engine() { return \B2\Storage\Mysql::class; }
function db_name() { return \B2\Cfg::get("MY_DB"); }
}
Бэкенд же уже сам читает конфигурации, обращается к БД или иному источнику данных и инициирует ими объект или объекты.
Скажи как тебе удалось сделать автозагрузку, через injectObjectManager?
У меня не Симфония, у меня свой фреймворк :)
Просто метод ->load($id) каждого объекта (в общем, независимо от того, является он моделью или нет) создаёт экземпляр бэкенда и вызывает у него уже метод ->load_object($object) и этот метод инициирует объект модели нужными данными.
Как я сказал выше, это не чисто академический MVC получается
А в академическом MVC модельки и не завязаны на контекст, который есть в контроллерах. Это отдельный слой. И его можно дергать откуда угодно. Да и про clean architecture php-шные фреймворки вообще не слышали, родовое проклятье-с.
У каждой модели указывается класс её бэкенда. То есть каждая модель — законченная сущность и система знает, что с ней делать без прямого привлечения контроллера.
Это получился ActiveRecord. Самый главный минус с которым я не раз сталкивался - нет возможности сделать массовый insert нескольких моделей.
В EntityManager всё гораздо проще, т.к он выступает контейнером для entity и при flush может оптимизировать запрос.
сначала какой то EntityManager взять, потом репозитарий, оттуда сделать выборку. Причем $em ещё так неявно получить можно
Ещё раз, EntityManager это контейнер для entity, который позволяет получать объекты класса, на который отображаются данные из БД и наоборот, сохранять такие объекты. Репозиторий это просто класс который содержит варианты запросов по которым нужные entity извлекаются из БД, он генерируется автоматически, но можно туда добавить свои сложные запросы если нужно.
Что касается $em, то в симфони EntityManager инстанциируется через DI-контейнер, т.е. фреймворк его инжектит в соответствующие классы (например контоллеры), но можно получить обратившись к ServiceManager напрямую.
Ну, в общем да. Не считая того, что AR — это контекст БД, а у меня источники данных могут быть любыми :)
нет возможности сделать массовый insert нескольких моделей
Сейчас у меня не практикуется, просто нет надобности в массовых вставках, но когда-то, в древних версиях было. Ничто не мешает не делать сохранение базы в момент создания объекта, а сохранять потом разом группу объектов, атомарно, одним запросом.
и при flush может оптимизировать запрос
Обычно у меня изменённые объекты итак сохраняются по завершению работы скрипта, а не в момент изменения. Или по специальному запросу, аналог flush. И при этом, безусловно, можно проводить оптимизацию. От позднего сохранения новых объектов я отказался как из соображения надёжности, так и для упрощения проблемы автоинкрементных идентификаторов. Удобно иметь ID объекта прямо в момент его создания, чтобы использовать тут же для связки с ним иных объектов, а не лепить сложную отложенную логику или пользоваться UUID.
Там есть одна родовая, так сказать, проблема — отсутствие документаци :D При чём движку непосредственно лет 15, а его корни уходят вообще где-то в 1998-й в генератор статики на QBasic :)
Лет 7 назад я делал попытку начать писать документацию, но, поскольку движок в одиночку использую, написание документации так и обломалось на самом старте :) А сейчас то, что начал тогда делать, уже и не актуально. И собственная автозагрузка классов на Composer был заменена, и собственное именование классов, счастливо точно совпавшее с более поздним psr-0, сейчас у меня уже устаревшее в пользу psr-4...
Я начал недавно собирать эдакий мета-пакет для прототипирования и тестирования, который может быть демонстрацией движка и работы его компонентов, но это очень ранняя стадия: