Pull to refresh

Comments 58

UFO just landed and posted this here
Зенд скромнее, он не говорит, почему ты ему не нравишься и что лишнее в тебе!
UFO just landed and posted this here
Желательно, чтобы это мнение хоть чуточку было обосновано. Основное приимущество зенда, что почти любой компонент можно использовать отдельно. И почти любой компонент можно заменить сторонним.
UFO just landed and posted this here
Сколько раз смотрел на зенд, приходит в голову мысль, что без него можно все написать проще и логичней.
Надо было не смотреть, а писать на нем ;)
UFO just landed and posted this here
Главный мусор — это Zend_Application и вся архитектура, которую он навязывает. А по — отдельности да, вполне независимые удобные либы.
никто не тянет Zend_Application, он даже не обязателен, это просто способ запустить приложение одной строкой
Это имхо и является одной из двух главных проблем фреймворка — излишне скурпулезная декомпозиция, какая-нибудь жалкая пара общих операторов — уже дополнительный базовый класс куда они вынесены, а там один класс агрегирует другой класс, оба тянут за собой цепочку наследований родительских классов и интерфейсов, в итоге каждый пук подключает 20-30 файлов с большим количеством балластного кода, на чем конкретно буксует интерпретатор. И казалось-бы — есть-же интерфейсы, можно написать реализацию самому! Но тут вылезает вторая проблема, довольно-таки известный антипаттерн — bloated interface, половина интерфейсов зенда — это хреновы миллионы однотипных методов, с псевдополиморфизмом методов (setOptions(array $options), setConfig(Zend_Config $options)), аксессорами (__get => getOption, __set => setOption) и т.д. и т.п., что выливается в человекогода их реализации.
UFO just landed and posted this here
UFO just landed and posted this 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 just landed and posted this here
ZF очень мощный и гибкий фреймворк, единственным его недостатком является высокой порог вхождения. Именно поэтому я и начал писать этот цикл, чтобы облегчить старт для тех кто только начал изучать фреймворк. Спасибо, за отзыв!
Да не сказал бы что высокий порог вхождения — он довольно прост и логичен, вполне в духе PHP.

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

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

А обосновать? И чем кстати архитектура то плоха?
UFO just landed and posted this here
Ок, давайте пруффлинк на аналогичный по потенциальной функциональности код написанный без фреймворка.

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

И тащемта никто не мешает же под конкретные нужды расширить функциональность стандартных классов…
UFO just landed and posted this here
> По текущему функционалу, без фреймворка получится десяток строк.

Ок. Ловим на слове: 10-ки строк — Acl + Auth.
UFO just landed and posted this here
За 10 строк — 1$ устроит?
Но только функционал должен полностью поглощать систему контроля доступа для сайтов средней сложности.
А ловить на слове есть смысл — вы же не хотите быть голословным?
UFO just landed and posted this here
Увы, но ваши комментарии абсолютно не соответствуют теме топика. Вот если бы он назывался: «Использовать ZF или нет»…
UFO just landed and posted this here
Давайте посмотрим на первый ваш комментарий:
>> Вот именно поэтому мне и не нравится zend — куча лишнего кода…
UFO just landed and posted this here
Не вижу причин обсуждать это в данном посте, как я уже утверждал ранее:
>> назывался: «Использовать ZF или нет»…
Наш разговор зацикливается, по-этому предлагаю завершить его
UFO just landed and posted this here
Давайте не «на словах» и без лишних запросов к базе при каждом открытии любой страницы.
Жду код…
UFO just landed and posted this here
Да такой функционал на каком-нибудь 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 должно находиться только то, что привязано к текущему проекту. А расширения библиотек я как правило переношу из одного проекта в другой, с незначительными изменениями.
Вполне вероятно, что так лучше. Возьму на вооружение, спс
Sign up to leave a comment.

Articles