Pull to refresh

Comments 58

Вот именно поэтому мне и не нравится zend — куча лишнего кода…
Зенд скромнее, он не говорит, почему ты ему не нравишься и что лишнее в тебе!
=)) Вам пора отдохнуть, раз Вы считаете, что абстрактный код должен что-то говорить.
А у любого человека есть такое свойство — высказывать свое мнение.
Желательно, чтобы это мнение хоть чуточку было обосновано. Основное приимущество зенда, что почти любой компонент можно использовать отдельно. И почти любой компонент можно заменить сторонним.
Я про это ниже написал: «На самом деле, некоторые либы в zend довольно удобные. Правда большинство из них тянет за собой кучу мусора =( » ;)
Сколько раз смотрел на зенд, приходит в голову мысль, что без него можно все написать проще и логичней.
Надо было не смотреть, а писать на нем ;)
На самом деле, некоторые либы в zend довольно удобные. Правда большинство из них тянет за собой кучу мусора =(
Главный мусор — это Zend_Application и вся архитектура, которую он навязывает. А по — отдельности да, вполне независимые удобные либы.
никто не тянет Zend_Application, он даже не обязателен, это просто способ запустить приложение одной строкой
Это имхо и является одной из двух главных проблем фреймворка — излишне скурпулезная декомпозиция, какая-нибудь жалкая пара общих операторов — уже дополнительный базовый класс куда они вынесены, а там один класс агрегирует другой класс, оба тянут за собой цепочку наследований родительских классов и интерфейсов, в итоге каждый пук подключает 20-30 файлов с большим количеством балластного кода, на чем конкретно буксует интерпретатор. И казалось-бы — есть-же интерфейсы, можно написать реализацию самому! Но тут вылезает вторая проблема, довольно-таки известный антипаттерн — bloated interface, половина интерфейсов зенда — это хреновы миллионы однотипных методов, с псевдополиморфизмом методов (setOptions(array $options), setConfig(Zend_Config $options)), аксессорами (__get => getOption, __set => setOption) и т.д. и т.п., что выливается в человекогода их реализации.
UFO landed and left these words here
UFO landed and left these words here
Т.н. простой пример аутентификации кроме того еще является примером объединения логики управления (контроллер) и бизнес-логики (модель), что противоречит принципу MVC. Я для себя в конце концов пришел к такому решению:
class Model_User extends Skaya_Model_Abstract implements Zend_Auth_Adapter_Interface {

	const USER_STATE_ACTIVE = 'active';
	const USER_STATE_DEACTIVE = 'deactive';

	const USER_ROLE_GUEST = 'guest';
	const USER_ROLE_USER = 'user';
	const USER_ROLE_ADMIN = 'admin';

	public function getRole() {
		if (empty($this->_data['role'])) {
			$this->_data['role'] = self::USER_ROLE_GUEST;
		}
		return $this->_data['role'];
	}

	public function authenticate() {
		/**
		 * @var Model_User $user
		 */
		$user = $this->getMapper()->getUserByEmail($this->email);
		if (is_array($user) &&
			!empty($user) &&
			!empty($this->email) && $user['email'] == $this->email &&
			$user['password'] == md5($this->password) &&
			$user['status'] == self::USER_STATE_ACTIVE
		) {
			if (empty($user['role'])) {
				$user['role'] = self::USER_ROLE_USER;
			}
			$this->populate($user);
			unset($this->password);
			$result = new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $this);
		}
		else {
			$code = Zend_Auth_Result::FAILURE;
			if (!is_array($user) ||
				empty($user) ||
				$user['username'] != $this->email
			) {
				$code = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
			}
			elseif ($user['password'] != $this->password) {
				$code = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
			}
			$result = new Zend_Auth_Result($code, null, array('loginFailed' => 'Incorrect Email & Password'));
		}
		return $result;
	}
}

Код контроллера:
class Admin_UsersController extends Zend_Controller_Action {

	/**
	 * @var Model_User
	 */
	protected $_user;

	public function loginAction() {
		$request = $this->getRequest();

		$loginForm = new Admin_Form_Login(array(
			'name' => 'loginForm',
			'action' => $this->_helper->url('login')
		));

		if ($request->isPost()) {
			if ($loginForm->isValid($request->getPost())) {
				$user = Service_User::create(array(
					'email' => $loginForm->email->getValue(),
					'password' => $loginForm->password->getValue()
				));
				$auth = Zend_Auth::getInstance();
				$authResult = $auth->authenticate($user);
				if ($authResult->isValid()) {
					$user->lastLoginDate = time();
					$user->save();
				}
			}
		}
		$this->view->loginForm = $loginForm->prepareDecorators();
	}

	public function logoutAction() {
		Zend_Auth::getInstance()->clearIdentity();
		$this->_redirect('/admin');
	}
}
Да, действительно происходит некоторое смешивание и это не очень хорошо. Особенно мне не нравится что в моем случае возникает дублирование кода, если вход нужно выполнять в нескольких местах (например автоматически после регистрации). Однако, для небольших проектов мне кажется это не критично.
Второй год все проекты пишу с использованием Zend. До этого пробовал разные framework'и. Zend понравился больше всего, хотя ему не хватает некоторых сторон Kohana и Yii. А в остальном — наиболее универсальный и мощный.

Спасибо за статью, до сих пор нормально не смог разобраться с acl, для меня это тёмный лес. Надеюсь, ваша статья поможет.
Данная статья не описывает в достаточном объеме Zend_Acl. Наверное мне стоит написать отдельный пост и рассмотреть какой-либо расширенный пример использования Acl.
Ок, надеюсь что это случится. Просто хочется не тупой теории и элементарных примеров, как в мануалах, где даже не описывается как потом применять заданные роли, а чего-то более серьёзного, с более-менее приличными примерами. Буду очень благодарен, да и не я только, думаю, если такой топик будет
За два года, при желании, могли бы и поискать, Acl довольно таки популярная тема, по нему уйма статей.
Второй год пишете проекты на Zend и не можете разобраться с Zend_Acl? Боюсь смотреть в ваш код.
Сам вот иногда думаю: блин, это ж по-любому проще можно сделать.
UFO landed and left these words here
ZF очень мощный и гибкий фреймворк, единственным его недостатком является высокой порог вхождения. Именно поэтому я и начал писать этот цикл, чтобы облегчить старт для тех кто только начал изучать фреймворк. Спасибо, за отзыв!
Да не сказал бы что высокий порог вхождения — он довольно прост и логичен, вполне в духе PHP.

Не сочтите за флуд, но судя по голосованию за комменты — многих читателей топика в детстве насиловали ZF`ом.

>Главный мусор — это Zend_Application и вся архитектура, которую он навязывает. А по — >отдельности да, вполне независимые удобные либы.

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

Конечно, примеры сами по себе, вырванные из контекста, выглядят как реактивный двигатель на велосипеде — но ZF великолепен в сложных проектах, это многого стоит. К тому же это один из немногих фреймворков, который чуть ли не силой приучает к написанию Хорошего кода.

И тащемта никто не мешает же под конкретные нужды расширить функциональность стандартных классов…
>Ок, давайте пруффлинк на аналогичный по потенциальной функциональности код написанный без фреймворка.

Потенциально, echo 'Hello world' полностью заменяет пост. Но это потенциально, верно ;).
По текущему функционалу, без фреймворка получится десяток строк.

>Конечно, примеры сами по себе, вырванные из контекста, выглядят как реактивный двигатель на велосипеде — но ZF великолепен в сложных проектах, это многого стоит.

Именно поэтому, чаще всего, используют отдельные либы zf, а не весь фреймворк. Очень уж он тормозной и тянет кучу лишнего кода и зависимостей…

>К тому же это один из немногих фреймворков, который чуть ли не силой приучает к написанию Хорошего кода.

Эммм… Если код выше — показатель «Хорошего кода»… В общем, проще и удобнее использовать только либы, а не писать «в стиле zf».
> По текущему функционалу, без фреймворка получится десяток строк.

Ок. Ловим на слове: 10-ки строк — Acl + Auth.
Могу даже в одну сделать, но длинно получится.
А ловить на слове нет смысла — оплатите работу или нет?
За 10 строк — 1$ устроит?
Но только функционал должен полностью поглощать систему контроля доступа для сайтов средней сложности.
А ловить на слове есть смысл — вы же не хотите быть голословным?
Не, не устроит. И функционал должен поглощать только то, что в посте, верно ;)
Ниже отписал, чтобы не быть голословным. А минус вы зря поставили — всегда есть разные способы решения задачи… Например, в данном случае, вообще можно было обойтись только масками, без acl вообще.

P.S.: ух ты, не поленились и прошлись по всем комментам моим в топике =)))))))
Увы, но ваши комментарии абсолютно не соответствуют теме топика. Вот если бы он назывался: «Использовать ZF или нет»…
С этим и не спорю. Когда вы ставили минусы комментам — могли бы увидеть, что я сам иногда использую либы zf. Вы же сами попросили в 10 строк без zf — я привел возможные способы решения. А теперь вы говорите «не соответствуют теме топика»…
Давайте посмотрим на первый ваш комментарий:
>> Вот именно поэтому мне и не нравится zend — куча лишнего кода…
И второй:
>>На самом деле, некоторые либы в zend довольно удобные. Правда большинство из них тянет за собой кучу мусора =(

Оба верные, от и до… Zend заставляет писать кучу лишнего кода, а некоторые (именно некоторые) либы удобные.
Не вижу причин обсуждать это в данном посте, как я уже утверждал ранее:
>> назывался: «Использовать ZF или нет»…
Наш разговор зацикливается, по-этому предлагаю завершить его
Без кода на словах могу объяснить, как бы сделал — хранил зависимости в базе, одним запросом получал бы практически полный acl и остался бы auth, который можно реализовать в несколько строк. ;)
Давайте не «на словах» и без лишних запросов к базе при каждом открытии любой страницы.
Жду код…
Будет код, когда будет предоплата в 300$ и оплата после еще 300.
Тогда будет 10 строк с acl и auth. И запросы будут не при каждом открытии страницы — для этого кеширование придумали ;) Даже без базы сделаю, на тех же масках скорее всего.

А работать на вас, доказывая вам же, что в данном случае это куча лишнего кода, да еще и за 1$ — я не нанимался и не собираюсь наниматься…
Да такой функционал на каком-нибудь Yii вообще сам генериться, но как было замечено ниже ZF великолепен в сложных проектах.
Такой функционал нигде не генерится, ручками надо указывать куда можно ходить а куда нельзя
простите, шаблон данного функционала))) конкретику понятное дело, что прописывает программист.
Ну не скажите. В Symfony2 такое делается парой строк в конфиге и декларативным объявлянием перед методом контроллера
/**
 * @Security("has_role('ROLE_ADMIN')")
*/
Иногда необходимо хранить в сторидже дополнительную информацию, которая может хранится в других талицах, например информацию о компании пользователя. Можно ли при стандартной аутентификации сделать запрос по нескольким таблицам? Или придется делать второй запрос и добавлять информацию в сторидж?

Для себя нашел более простой способ аутентификации — stackoverflow.com/questions/468863/zend-auth-and-acl — делаю в модели один запрос по необходимы таблицам и требуемую информацию складываю в сторидж
можно из dbadapter'а для Zend_Auth взять объект Zend_Db_Select, и с join'ом добавить таблицы, которые нужны.
конкретно метод Zend_Auth_Adapter_DbTable::getDbSelect()
Спасибо, обязательно посмотрю
что мешает расширить существующий, либо написать отдельный?
Я обычно делаю дополнительный запрос в таком случае. Вы ведь расширяете zend_auth, я правильно понял?
Получать данные можно так:
$auth->getIdentity(), там есть дополнительноя проверка на пустоту хранилища, не нужно самому вызывать hasIdentity(). Имхо, плохой тон работать напрямую с хранилищем Zend_Auth и хранить там что-то помимо ID, максимум — модель типа User иначе потом сам замахаешься выбгербать оттуда кучу данных непонятной структуры.

Брать данные из запросов, имхо, правильнее так:
$this->getRequest()->getParams(), перед этим проверив какого типа запрос: $this->getRequest()->isPost(), тогда мы можем определить открыта страница GETом или пришла форма POSTом.
А так же в случае неуспешной валидации выводить форму заново, это покажет пользователю его ошибки в форме автоматически.
отвечу своим имхо:
> $auth->getIdentity()
всегда использую
if (Zend_Auth::getInstance()->hasIdentity()) {

$user_info = Zend_Auth::getInstance()->getStorage()->read();

} else {GUEST}

> $this->getRequest()
$this->_request, $this->_request->isPost()
и по параметрам $this->_request->param1; $this->_request->param2;
в последнейм случае можно использовать поля ВНЕ зависимости от ПОСТ и/или ГЕТ. да и скобочек меньше.
1. Не понимаю зачем лезть в хранилище и вводить дополнительные проверки, если код написан за тебя. Посмотрите код методов, всё поймете.
2. Думаю, что прямое обращение к _request немного плохой тон. Если вдруг нужно обратиться к полю извне экземпляра/потомка, то доступа мы туда не получим, т.к. поле protected. Для этого и сделали getRequest(). Кстати, его код:
public function getRequest()
{
return $this->_request;
}

Так что можно написать $this->getRequest()->param1; $this->getRequest()->param2; без проблем :)
>Разместите этот код в файле application/classes/Acl.php.
Может быть это и не плохо, но насколько мне известно, расширяемые классы принято складывать в ./library/%ProjectName%

В случае с Acl, получаем (пусть название проэкта, будет My):
./library/My/Acl.php
имя класса: My_Acl
В application.ini добавляем:
autoloaderNamespaces.my = «My»
Как вариант. Мне просто удобнее, когда весь код находится в application
А по-моему в Application должно находиться только то, что привязано к текущему проекту. А расширения библиотек я как правило переношу из одного проекта в другой, с незначительными изменениями.
Вполне вероятно, что так лучше. Возьму на вооружение, спс
Only those users with full accounts are able to leave comments. Log in, please.