Comments 75
UFO just landed and posted this here
Профессионализм в пропаганде анти-паттерна Singleton? Идут лесом такие «профессионалы».
Чем плох Singleton конкретно в PHP? И все компоненты в Laravel работают через фасады: App, View, Queue, Mail, Route, Filter, Session, Cookie.
Тот магический вариант DI, которым хвастается статья, работает только, когда указан класс в качестве типа, а не интерфейс, что само по себе редкость.
Можно передавать, например, UserRepositoryInterface, но фреймворку (а конкретно IoC контейнеру) нужно указать, какой класс использовать для этого интерфейса, например:
App::bind('UserRepositoryInterface', 'DbUserRepository');
+2
Скрывать работу с экземпляром за вызовом статических методов очень плохо, по той причине, что это ломает полностью ООП подход. Соответственно мы не можем уже полагаться на SOLID в проекте.
К тому, если попытаться подключить класс, который использует подобную зависимость где-либо вне Фреймворка, он рухнет и что бы восстановить его функциональность, придётся писать статические Mock-объекты.
На самом деле, я не понял, зачем прятаться за такими «фасадами»
, если всё сводится к
p.s.
С Фреймворком не работал, знания лишь почерпнул из статьи и комментариев к ней.
К тому, если попытаться подключить класс, который использует подобную зависимость где-либо вне Фреймворка, он рухнет и что бы восстановить его функциональность, придётся писать статические Mock-объекты.
На самом деле, я не понял, зачем прятаться за такими «фасадами»
class Cache extends Facade {
protected static function getFacadeAccessor() { return 'cache'; }
}
, если всё сводится к
App::container->get("cache")
p.s.
С Фреймворком не работал, знания лишь почерпнул из статьи и комментариев к ней.
+1
Фасад является унифицированным интерфейсом, который скрывает всю логику и сложность имплементации функционала. Он является единственной точкой входа. Так, например если внутри фасада что-то изменится — использование его не изменится. То есть он служит упрощенным интерфейсом сложной реализации.
Для того чтобы использовать Mock фасады в Laravel достаточно написать
или
фасады так же работают через IoC контейнер. Если вы ознакомитесь подробнее с документацией то увидите, что эти фасады еще и легко конфигурировать и писать собственный драйвера для них.
P.S. Спасибо за интересный комментарий
Для того чтобы использовать Mock фасады в Laravel достаточно написать
Cache::shouldReceive('get');
или
Event::shouldReceive('fire');
фасады так же работают через IoC контейнер. Если вы ознакомитесь подробнее с документацией то увидите, что эти фасады еще и легко конфигурировать и писать собственный драйвера для них.
P.S. Спасибо за интересный комментарий
0
Он является единственной точкой входа. Так, например если внутри фасада что-то изменится — использование его не изменится.
Как бы, когда вы публикуете интерфейс, то он так и работает. Вы можете подменять реализацию данного интерфейса, но если он реализован, то работать будет так как надо.
К тому же, я пока не понимаю, как набор статических методов воспринимать как интерфейс?
0
Там нет Singleton, там используются фасады, о них вы можете прочитать на wiki или тут.
Откуда такая информация? В документации есть примеры использования интерфейсов.
Тот магический вариант DI, которым хвастается статья, работает только, когда указан класс в качестве типа, а не интерфейс, что само по себе редкость.
Откуда такая информация? В документации есть примеры использования интерфейсов.
0
Опа, про анти-паттерн Singleton по подробнее, пожалуйста, а то, как говорится «А ребята не в курсе».
+1
Если статья носит пропагандистский характер, то не получилось. Перейти с yii на laravel не захотелось.
+5
Жаль, что цель статьи или итог получился пропагандистским. Из заголовка, я ожидал сравнение возможностей нескольких популярных (или не очень), полноценных или микрофреймворков. В котором автор позволяет сделать вывод, на что стоит посмотреть или обратить внимание.
+4
Возможности всех фреймворков почти одинаковы. Отличия, в основном, лишь в том, что у всех разный подход.
0
Еще один простой фреймворк с низким порогом вхождения, но понравился стиль изложения статьи :) Остался с чуством, что этот фреймворк для ленивых топтать клаву и он такой умный что версия 5 будет писать сайты сама, если версия 4 уже умееть решать за разработчика какие данные и какими запросами ей выбирать и какой структуры будет JSON после сериализации.
0
Ваш комментарий напомнил habrahabr.ru/post/202460/ ;)
0
Меня в Laravel убивает то, что вообще все, что только можно, сделано статическими методами классов.
Где-то статика используется как пространство имен для обычных функций (не понимаю этого стремления избегать функций, они тоже пространства имен поддерживают вообще), где-то фасады со статическими вызовами. В итоге, все делается через статические методы, если не лезть внутрь.
Где-то статика используется как пространство имен для обычных функций (не понимаю этого стремления избегать функций, они тоже пространства имен поддерживают вообще), где-то фасады со статическими вызовами. В итоге, все делается через статические методы, если не лезть внутрь.
+1
Полгода назад поддался пиару на Хабре и попробовал Laravel. Не понравилось. С Yii почему-то начало было приятнее.
-2
Господа вы может мне объясните зачем в динамическом языке DI?
+1
Что бы параметры подтягивать из настроек и переопределять / расширять поведение модулей 3ей стороны
Других usecase'ов не вижу. А пример DI в статье, так вообще смешной, не понятно зачем он там %)
Других usecase'ов не вижу. А пример DI в статье, так вообще смешной, не понятно зачем он там %)
0
А пример DI в статье, так вообще смешной, не понятно зачем он там %)
Там же все зависимости «автомагически» создаются, ничего руками делать не надо. Или Вы не об этом?
0
Зачем создавать авоматически и придумывать магию, в том месте где она не нужна. Из комментариев людей, которые с Фреймворком работали, я понял что создаётся зависимость, если в хинте указан не интерфейс, а конкретный класс.
Что это за внедрение зависимости такое?
Явное лучше чем неявное(магия).
Что это за внедрение зависимости такое?
class A {
function __construct(B b=null) [
if (b === null) {
b = new B();
}
}
}
Явное лучше чем неявное(магия).
0
Ваш пример кода мне не понятен. Это так в Laravel сделано? Тут совсем другое написано: laravel.com/docs/ioc
0
Вообще говоря такой «хак» довольно удобен (если немного изменить). Особенно если DI на 92,486% вводится только для кошерности целей тестирования. В тестовом коде можем подсунуть любой стаб или мок без труда, а в боевом писать без этого.
0
Это делается без IoC, но во фрейморке он есть и просовывается класс или интерфейс, в случае интерфейса контейнеру нужно указать какой класс в этом случае просунуть
0
Можете пояснить свою мысль? Почему он не нужен?
0
Язык у нас динамический. Как бе особых проблем создать на лету все что надо проблемы нет. В случае статически компилируемого языка заката солнца в ручную будет существенно больше.
0
То есть по вашему главной фишкой di является автоматическое создание объектов и в этом вся суть? А то что мы можем быстро заменить имлементацию какого-то сервиса, от которого зависят наши, это так, бонус? В этих ваших «статически компилируемых» тоже никаких проблем нету сделать new MySuperClass или что-то в этом духе. java вот тоже динамический (управляемый код, jit-компилятор, байткод и все такое прочее), и c#.
0
То есть по вашему главной фишкой di является автоматическое создание объектов и в этом вся суть? А то что мы можем быстро заменить имлементацию какого-то сервиса, от которого зависят наши, это так, бонус?
В случае динамического языка быстро заменить имплементацию вы можете и так. И DI для этого вам особо будет не нужен. И да как-то я всегда думал, что основная цель DI как раз упросить создание окружения.
new MySuperClass или что-то в этом духе.
В java я не могу на лету добавить еще одно значение или функцию. В динамических запросто.
0
Что-то не улавливаю. Приведите, пожалуйста, пример код с DI и без.
0
вы не путаете php и js? да, в php есть определенный уровень интроспекции, но даже там заменить имплементацию метода в рантайме довольно проблематично. Даже более того, в java есть возможность подобного изменения кода в рантайме. но… Зачем?
По сути разницы нету, динамический язык или нет. Суть та же что и для java/c++. Имея интерфейс A и сервис B зависящий от имплементации интерфейса A, мы сможем когда угодно подменить реализацию этого интерфейса A глобально для всего проекта. И к слову, подмена имплементации не происходит в рантайме, только во время разработки.
опять же как бы ни было тяжело или легко создавать объекты и передавать им нужные зависимости, с DiC это проще.
По сути разницы нету, динамический язык или нет. Суть та же что и для java/c++. Имея интерфейс A и сервис B зависящий от имплементации интерфейса A, мы сможем когда угодно подменить реализацию этого интерфейса A глобально для всего проекта. И к слову, подмена имплементации не происходит в рантайме, только во время разработки.
опять же как бы ни было тяжело или легко создавать объекты и передавать им нужные зависимости, с DiC это проще.
+1
вы не путаете php и js? да, в php есть определенный уровень интроспекции, но даже там заменить имплементацию метода в рантайме довольно проблематично.
Вообще нет. eval всегда есть в наличии.
Даже более того, в java есть возможность подобного изменения кода в рантайме. но… Зачем?
Есть и даже широко используется в случае AOP.
Имея интерфейс A и сервис B зависящий от имплементации интерфейса A, мы сможем когда угодно подменить реализацию этого интерфейса A глобально для всего проекта. И к слову, подмена имплементации не происходит в рантайме, только во время разработки.
В динамическом языке вы сами понимаете это можно и без DI сделать. По этой причине в случае динамического языка можно и не использовать DI там где в статическом придется.
опять же как бы ни было тяжело или легко создавать объекты и передавать им нужные зависимости, с DiC это проще.
Ну вот разве что. А так я не могу сказать что DI популярен в динамических языках.
-1
ну inversion of control все же лучше применять. будь то динамический язык или статически компилируемый.
0
В динамическом языке вы сами понимаете это можно и без DI сделать
Можно, а нужно ли? собирать имплементацию интерфейса в строке и запускать её через eval чем лучше обычного DI контейнера?
0
Это уже другой вопрос. Но обычно в чистом виде вот у нас тут DI в фреймворках динамических языков я не встречал.
0
Чистый вид это какой?
0
Четкое выделение DI внутри фреймворка. Это я видел только в статически компилируемых языках.
0
Пример кода можно?
0
что вы подразумеваете под «четко выделенным di»? отдельный dependency injection фреймворк? Так есть, и даже не один. symfony использует symfony/dependency injection, который можно юзать отдельно в любом другом проекте. Если брать какой silex то можно опять же подключить отдельно dic и работать через него.
По поводу классического di, где в конфигах прописываются только соответствия интерфейса реализации, а выбор зависимостей идет исключительно по тайп хинтам в создаваемых сервисах я пока не встречал, ибо почти все реализации DiC рассчитаны еще и на передачу параметров, и подмена реализации обычно осуществляется переопределением параметров (пусть к классам, названия сервисов выносятся как параметры).
По поводу классического di, где в конфигах прописываются только соответствия интерфейса реализации, а выбор зависимостей идет исключительно по тайп хинтам в создаваемых сервисах я пока не встречал, ибо почти все реализации DiC рассчитаны еще и на передачу параметров, и подмена реализации обычно осуществляется переопределением параметров (пусть к классам, названия сервисов выносятся как параметры).
+1
что вы подразумеваете под «четко выделенным di»? отдельный dependency injection фреймворк? Так есть, и даже не один.
Именно его. То что он есть я вполне верю. Но вот в динамических языках я как-то явной работы с ним почти не где не видел. Возможно связано с тем что мне просто они не попадались.
По поводу классического di, где в конфигах прописываются только соответствия интерфейса реализации, а выбор зависимостей идет исключительно по тайп хинтам в создаваемых сервисах я пока не встречал,
В java именно так. Когда идет использование DI идет указание интерфейса и далее аннотация на связывание.
0
Когда DI осуществляется конфигом типа
А работа с ним происходит по типу:
это достаточно выделено?
<parameters>
<!-- ... -->
<parameter key="mailer.transport">sendmail</parameter>
</parameters>
<services>
<service id="mailer" class="Mailer">
<argument>%mailer.transport%</argument>
</service>
<service id="newsletter_manager" class="NewsletterManager">
<call method="setMailer">
<argument type="service" id="mailer" />
</call>
</service>
</services>
А работа с ним происходит по типу:
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
$container = new ContainerBuilder();
$loader = new XmlFileLoader($container, new FileLocator(__DIR__));
$loader->load('services.xml');
// ...
$newsletterManager = $container->get('newsletter_manager');
это достаточно выделено?
0
Да. Только в этом случае очень много заката солнца в ручную которое в динамическом языке можно и не делать. В статически же типизированных языках DI хорош при наличии аннотаций. Иначе очень много вспомогательного кода.
0
А тут сложный компромисс между явностью задания зависимостей и использованием динамичности. Как правило динамичность сильно уменьшает понятность, сложно удержаться от перевода его в магию.
Вроде и аннотациями можно, но я их не очень люблю.
Вроде и аннотациями можно, но я их не очень люблю.
0
Как правило динамичность сильно уменьшает понятность, сложно удержаться от перевода его в магию.
Ну DI с аннотациями тоже магией попахивает. При этом довольно сильно. Тут больше вопрос в том чтобы динамичность была единообразна.
Вроде и аннотациями можно, но я их не очень люблю.
Вот когда когда много все же лучше делать аннотациями. Проще объяснять и проще читать. Достаточно воспринимать все объявления как декларативное программирование. Чем оно по сути и является.
0
Статика должна умереть. То что на самом деле это не статика а фасад никак не влияет на тот факт что программист использует как раз статику и поэтому учится плохим подходам.
Фреймворк в первую очередь должен быть написан так чтобы учить новичка как надо делать лучше
Фреймворк в первую очередь должен быть написан так чтобы учить новичка как надо делать лучше
0
Вы забыли о главном плюсе — огромном количестве хороших пакетов с расширениями. Печально только что главное расширение — это IDE helper, без которого писать код придётся без автокомплита.
Мне уже довелось видеть примеры плохого кода на laravel — без пакетов, без миграций, со своими велосипедами, которые ломают возможность пользоваться пакетами и вовсе консоль. Так что laravel — это не для всех.
Мне уже довелось видеть примеры плохого кода на laravel — без пакетов, без миграций, со своими велосипедами, которые ломают возможность пользоваться пакетами и вовсе консоль. Так что laravel — это не для всех.
0
Плюсов, на самом деле, очень много, описывать их очень долго. Проще и полезней заглянуть в документацию и своими глазами все увидеть. В стиле Laravel еще нужно научиться писать т.к. другие фреймворки не имели такой философии. Некоторые не считают Laravel чем-то таким особенным, однако если приглядеться и попробовать что либо написать на нем используя все возможности — влюбляешься в процесс.
0
То же самое могу написать про symfony2 или zend. Только для того что бы оценить возможности фреймворка — его нужно знать. С большими фреймворками, порог вхождения в которые по выше, это проще, так как человек походу дела разбирается с возможностями фреймворка и использует их по максимуму, либо сдается и выбирает что-то по проще (yii/laravel тому пример). Если же брать yii с их философией «мы не навязываем все эти fancy-паттерны» можно наблюдать кучу говнокода в проекте. Во всяком случае сколько проектов видел, везде какие-то кастыли да встретишь, причем такие что аж дух захватывает. Laravel мне в этом плане напоминает yii на компонентах симфони.
0
В говнокоде на yii и тем более laravel — можно легко разобраться, а вот эпик на zf или sf лучше переписывать с нуля. Кстати, показательно, что на недавно fw дне все рассказывали о фичах фреймворков, а symfony-сты о косяках и типичных ошибках.
Фреймворк ни от чего не спасает, другое дело что он может сделать ошибки фатальными.
Фреймворк ни от чего не спасает, другое дело что он может сделать ошибки фатальными.
0
А может кто-то объяснить мне про фасады?
Насколько я понимаю, они решают задачу тестирования (т.е. подмены реализации), на которую ссылаются все противники статических вызовов.
Но как быть с тем, что использование статических членов очень неявно? Пример:
Экземпляры:
Статика:
Т.е. если я дописываю что-то «вокруг» существующего кода, мне нужно «копать в глубь» этого кода чтобы быть уверенным, что я ничего не сломаю и существующий код не влияет на мой.
А если я дописываю что-то где-то глубоко внутри вызовов, мне необходимо изучить все, что «снаружи», чтобы ничего не поломать.
Или везде на всякий случай устанавливать нужные мне значения.
Или я ошибаюсь?
Насколько я понимаю, они решают задачу тестирования (т.е. подмены реализации), на которую ссылаются все противники статических вызовов.
Но как быть с тем, что использование статических членов очень неявно? Пример:
Экземпляры:
$foo = new Foo;
$foo->prop = 10;
do_something($foo); // явная передача экземпляра
var_dump($foo->prop); // очевидно, что здесь может быть не 10
Статика:
Foo::prop = 10;
do_something(); // внутри делает Foo::prop = 20
var_dump(Foo:prop); // я ожидаю увидеть 10
Т.е. если я дописываю что-то «вокруг» существующего кода, мне нужно «копать в глубь» этого кода чтобы быть уверенным, что я ничего не сломаю и существующий код не влияет на мой.
А если я дописываю что-то где-то глубоко внутри вызовов, мне необходимо изучить все, что «снаружи», чтобы ничего не поломать.
Или везде на всякий случай устанавливать нужные мне значения.
Или я ошибаюсь?
0
Нет, фасады существует не для этого.
Прочитайте про них в wiki.
Прочитайте про них в wiki.
0
Я говорю о статических фасадах в контексте Laravel.
Обычно разговор об этом фреймворке происходит так:
Тестируется? Ок. Но мне не ясно как быть с этим:
Кеш возвращает не то, что я ожидаю. Мне надо перерыть все вызовы от
Мне одному кажется, что это проблема?
Обычно разговор об этом фреймворке происходит так:
Ларавельцы: зацените клевый фреймворк!
Толпа: там статика, фуууууу!
Ларавельцы: а что с ней не так?
Толпа: ее нельзя тестировать (куча ссылок на статьи)
Ларавельцы: так у нас же фасады! смотрите, как они клево тестируются! (пример)
Толпа: о, класс! и вправду круто!
Тестируется? Ок. Но мне не ясно как быть с этим:
Cache::put('foo', 'bar', $minutes);
do_something1();
do_something2();
do_something3();
do_something4();
var_dump(Cache::get('foo')); // baz
Кеш возвращает не то, что я ожидаю. Мне надо перерыть все вызовы от
Cache::put
до Cache::get
.Мне одному кажется, что это проблема?
0
Проблема статиков в том, что они полностью игнорируют ООП при проектировании. Статики, по сути — это функции объеденные в namespace. Соответственно используя везде статики, мы не можем полагаться на SOLID.
Если при использовании ООП, у многих хоть как то сложилось в голове своя методика, как писать структурированный код, то в данном случае, очень большая вероятность понаписать кода, который очень тяжело будет поддерживать, т.к. ООП — это в первую очередь рамки, которые позволяют другим программистам понимать ваш код.
Если при использовании ООП, у многих хоть как то сложилось в голове своя методика, как писать структурированный код, то в данном случае, очень большая вероятность понаписать кода, который очень тяжело будет поддерживать, т.к. ООП — это в первую очередь рамки, которые позволяют другим программистам понимать ваш код.
+1
Лайфхак: если встречается код, где много статиков, то можно думать о таких классах как об экземплярах метакласса и считать код типа:
аналогом кода:
что позволяет оперировать принципами SOLID при проектировании, реализации и рефакторинге.
User::init();
$user = User::findById($id);
аналогом кода:
$userMeta = new UserMetа();
$userMeta->init();
$user = $userMeta->findById($id);
что позволяет оперировать принципами SOLID при проектировании, реализации и рефакторинге.
0
Эм, простите, но не соглашусь абсолютно.
Я хочу показать всем, какую показать в каком месте мой класс может быть расширен (за счет protected) — тут я этого сделать не могу.
Что-то сделать с интерфейсами со статиками вообще невозможно. Аналога со статиками нет, тут просто спрячется зависимость внутри метода, что не хорошо.
Я не могу не думать о целостности данных.
Всё, тут я уже не могу гарантировать, что findById будет работать так же, как если бы не было кода в месте, указанном комментарием. Если же использовать экземпляры, то я явно увижу, куда экземпляр передается.
На самом деле — статики, это не только невозможность тестирования — это глобальный факап на уровне архитектуры системы. Статик — это упрощение, когда не охота думать о идеологии построения приложения.
В Yii это «упрощение» сделано лишь для того, что бы можно было просто оперировать с теми сущностями, которые в веб-разработке точно являются singleton. Например — приложение. Когда вы в любом месте программы, у вас точно есть одно и только одно приложение. За счёт этого Yii очень сильно выигрывает в простоте при проектировке over 95% приложений для web, где они за счет «упрощения», ввели аспект единого приложения для всего кода.
Я хочу показать всем, какую показать в каком месте мой класс может быть расширен (за счет protected) — тут я этого сделать не могу.
class UserMeta {
protected function getFields() {
/* какой то код */
return $fields;
}
}
Что-то сделать с интерфейсами со статиками вообще невозможно. Аналога со статиками нет, тут просто спрячется зависимость внутри метода, что не хорошо.
public function setUserMeta(UserMetaInterface $userMeta) {}
Я не могу не думать о целостности данных.
User::init();
/* тут может быть вызов любой функции или любого статика */
$user = User::findById($id);
Всё, тут я уже не могу гарантировать, что findById будет работать так же, как если бы не было кода в месте, указанном комментарием. Если же использовать экземпляры, то я явно увижу, куда экземпляр передается.
На самом деле — статики, это не только невозможность тестирования — это глобальный факап на уровне архитектуры системы. Статик — это упрощение, когда не охота думать о идеологии построения приложения.
В Yii это «упрощение» сделано лишь для того, что бы можно было просто оперировать с теми сущностями, которые в веб-разработке точно являются singleton. Например — приложение. Когда вы в любом месте программы, у вас точно есть одно и только одно приложение. За счёт этого Yii очень сильно выигрывает в простоте при проектировке over 95% приложений для web, где они за счет «упрощения», ввели аспект единого приложения для всего кода.
-1
Ковырял Laravel всю последнюю неделю.
Не понравилось отсутствие Identity Map, т.е. следующее:
Как вы считаете, важно ли наличие этого паттерна в используемом фреймворке?
Не понравилось отсутствие Identity Map, т.е. следующее:
class User extends Eloquent {}
$user1 = User::findOrFail(1);
$user2 = User::findOrFail(1);
print_r($user1 === $user2); // false
Как вы считаете, важно ли наличие этого паттерна в используемом фреймворке?
0
Имхо, это удобно, но не критично, если об этом предупрежден. Куда больше напрягает отсутствие UnitOfWork, когда за каждой сущностью нужно следить «руками» и не забывать её сохранять.
0
Ошибся веткой, продублирую здесь.
А где это реализовано? Symfony?
Правильно понимаю, что в этом случае не нужно явно вызывать метод save() у модели т.к. фреймворк не забудет сделать все сам?
А где это реализовано? Symfony?
Правильно понимаю, что в этом случае не нужно явно вызывать метод save() у модели т.к. фреймворк не забудет сделать все сам?
0
В Doctrine 2 ORM — в Symfony 2 она входит по умолчанию, но вообще друг от друга независимы, часто прикручивают её и к другим фреймворкам.
Не нужно вызывать save() у каждой сущности, но один раз вызвать метод типа flush() всё же придется, но там уже uow пройдется по всем сущностям и сохранит всё что нужно (если надо и в одну транзакцию обернет). Может даже можно сделать автоматический вызов flush(), но лично я предпочитаю такие вещи на автоматику не перекладывать.
Не нужно вызывать save() у каждой сущности, но один раз вызвать метод типа flush() всё же придется, но там уже uow пройдется по всем сущностям и сохранит всё что нужно (если надо и в одну транзакцию обернет). Может даже можно сделать автоматический вызов flush(), но лично я предпочитаю такие вещи на автоматику не перекладывать.
0
не совсем все так. persist сущностей вы всеравно делаете. Просто записываются они в базу только по flush. Для связанных сущьностей можно настроить каскадный персист, и тогда uow сам все сделает за вас. Но опять же этот подход не особо рекомендован.
С другой стороны удобнее штуки чем doctrine (во всяком случае в контексте реляционных баз) я не встречал.
С другой стороны удобнее штуки чем doctrine (во всяком случае в контексте реляционных баз) я не встречал.
0
Да, но persist это не сохранение как таковое. Это сообщение менеджеру, что с данного момента он отвечает за новую POPO сущность. Касается это только новых сущностей, создаваемых обычно через new Entity(); в Create действиях, об уже существующих (читай — полученных из базы) менеджер и так знает, собственно он их оттуда и достал и передал приложению.
Пишу не столько для вас, сколько для незнакомых с Doctrine 2 людей вообще, и aazon в частности.
P.S. В Python есть нечто подобное Doctrine 2, а в Ruby вроде как нет :)
Пишу не столько для вас, сколько для незнакомых с Doctrine 2 людей вообще, и aazon в частности.
P.S. В Python есть нечто подобное Doctrine 2, а в Ruby вроде как нет :)
0
А где это реализовано? Symfony?
Правильно понимаю, что в этом случае не нужно явно вызывать метод save() у модели т.к. фреймворк не забудет сделать все сам?
Правильно понимаю, что в этом случае не нужно явно вызывать метод save() у модели т.к. фреймворк не забудет сделать все сам?
0
Only those users with full accounts are able to leave comments. Log in, please.
Фреймворк вашего следующего веб-приложения