ФорумПрограммированиеPHP для идиотов → Пишу ли я правильно Controller ? (MVC путь)

Пишу ли я правильно Controller ? (MVC путь)

  • tartar

    Сообщения: 186 Репутация: N Группа: Кто попало

    Spritz 28 июня 2012 г. 2:44, спустя 20 минут 5 секунд

    Надо глянуть что за птица этот ларавель.


    Много вкусностей в нем, по мимо официальных доков есть и посторонние + книга
    http://daylerees.com/category/laravel-tutorials/
  • adw0rd

    Сообщения: 22907 Репутация: N Группа: в ухо

    Spritz 28 июня 2012 г. 6:48, спустя 4 часа 4 минуты

    adw0rd
       Но я вижу приведенный код и меня в пот бросает, видимо технологии ушли далеко вперед и мне их не догнать


    Я не пойму, это сарказм или нет? :D

    Если да, то поставьте на путь истинный. Мне важен ответ на вопросы:
    Правильно ли спроектирована часть контроллера в моем примере?
    Есть ли в нем некие моменты которые должны были быть в Модели а не в Контролере?


    Да мне просто не нравится сам lavarel, это я понял исходя из того, что вами написанный код я еле понял вообще про что он.



    пиши на питоне

    Его сейчас изучаю, но знания пока не позволяют переписать на нем проекты.


    Вы видели Django, понятно что есть и дургие фреймворки на которые можно обращаться внимание, но всё-таки?

    В Django всё понятно и красиво структуировано, джанго во много pytonic.
    Я когда только начинал изучать Python/Django, то для меня все казалось настолько интуитивным, что я ими восторгался днями на пролёт, вот и вы попробуйте смоделировать ваше приложение на Django и тогда я смогу вам помочь указать верный путь. А сейчас с lavarel мне кажется это просто фейл
    adw/0
  • tartar

    Сообщения: 186 Репутация: N Группа: Кто попало

    Spritz 28 июня 2012 г. 8:14, спустя 1 час 25 минут 34 секунды

    adw0rd, На Django посмотрю после изучения самого Python, думаю без знании самого языка нет смысла соваться в его фреймворках.
    Когда изучал Laravel, мне тоже все в нем ясно и интуитивно понятно показалось. Думаю в момент когда стану знакомится с Django после изучения Python я буду такого же мнения.
  • adw0rd

    Сообщения: 22907 Репутация: N Группа: в ухо

    Spritz 28 июня 2012 г. 8:56, спустя 41 минуту 58 секунд

    Вообщем я попытался перенести твою логику на Django, по крайней мере как я её понял

    # coding: utf-8
    from django.contrib.auth.models import User
    from django.contrib.sites.models import Site
    from django.views.generic import TemplateView
    from django.core.mail import send_mail
    from django.conf import settings


    class ActionConfirm(TemplateView):
       """
       1) Подтверждение запроса на восстановления пароля
       2) Генерация и изменение старого пароля на новый
       3) Отправка письма пользователю
       """

       def dispatch(self, request, passkey):
           try:
               user = User.objects.get(passkey=passkey)
           except User.DoesNotExist:
               return self.render_to_response('registration/empty_passkey.html')

           # Пользователь подтвердил свой email, обновляем его пароль
           new_password = User.objects.make_random_password()
           user.set_password(new_password)

           if user.check_password(new_password):
               # Возникла ошибка во время обновления данных
               # НЕЗНАЮ ЗАЧЕМ ЭТО ЗДЕСЬ, НО В ОРИГИНАЛЕ БЫЛО, ПОЭТОМУ ПЕРЕНОШУ
               return self.render_to_response('authorization/password_updating_failed.html')
           else:
               # Пароль пользователя успешно изменен
               site = Site.objects.get_current()

               # Отправляем пользователю письмо с его новым паролем
               message = self.render_to_response("emails/successful_password_updating.txt", {
                   'login': user.username,
                   'password': new_password,
                   'domain': site.domain,
                   'ip': request.META.
               })
               # Вообще я бы это выделил в другое место и под Сelery (defferd)
               send_mail("Subject", message, settings.DEFAULT_FROM_EMAIL, [user.email])

               # Рисуем ответ. Вообще, я бы использовал "Django messages framework":
               # > messages.add_message(request, messages.INFO, 'Successful password updating!')
               # А в base.html шаблоне бы выводил в нужном месте эти messages, я так делаю у себя,
               # так как событийным сообщениям не надо иметь свои шаблоны - они однотипны.
               self.render_to_response('authorization/successful_password_updating.html', {
                   'login': user.username,
                   'email': user.email,
                   })

           # return View::make('template')->with('header', Template::seo_header() );
           # А это надо передавать в CONTEXT_PROCESSORS, если оно глобально, если локально, то юзать Mixins

       def render_to_response(self, template_name, context={}):
           self.template_name = template_name
           return self.render_to_response(context)
    adw/0
  • adw0rd

    Сообщения: 22907 Репутация: N Группа: в ухо

    Spritz 28 июня 2012 г. 9:07, спустя 11 минут 26 секунд

    Для себя бы я сделал что-то вроде, urls.py/base.html/context_processors/celery не привожу, так как это будет излишне в примере

    # coding: utf-8
    from django.conf import settings
    from django.contrib import messages
    from django.contrib.auth.models import User
    from django.contrib.sites.models import Site
    from django.core.mail import send_mail
    from django.views.generic import TemplateView


    class ActionConfirm(TemplateView):
       template_name = "auth/confirm.html"

       def dispatch(self, request, confirm_key):
           try:
               user = User.objects.get(confirm_key=confirm_key)
           except User.DoesNotExist:
               messages.add_message(request, messages.INFO, _('Failed ….'))
           else:
               new_password = User.objects.make_random_password()
               user.set_password(new_password)
               user.save()

               messages.add_message(request, messages.INFO, _('Successful password updating!'))
               self.send_email(user=user, password=new_password)

           return self.render_to_response()

       def send_email(self, user, password):
           site = Site.objects.get_current()
           message = self.render_to_response("emails/successful_password_updating.txt", {
               'login': user.username,
               'password': password,
               'domain': site.domain,
               'ip': request.META.
           })
           return send_mail("Subject", message, settings.DEFAULT_FROM_EMAIL, [user.email])

    adw/0
  • adw0rd

    Сообщения: 22907 Репутация: N Группа: в ухо

    Spritz 28 июня 2012 г. 9:16, спустя 8 минут 30 секунд

    По поводу confirm_key (или passkey), то если он только нужен для подтверждения пользователя по email или типа того, то я бы использовал:

    1) Генерация "confirm_key"

    uidb36 = int_to_base36(user.id)
    token = token_generator.make_token(user=user)

    confirm_url = "confirm/{}/{}/".format(uidb36, token)


    2) Подтверждение:

    # urls
    url(r'^confirm/(?P<uidb36>.+)/(?P<token>.+)/$', ConfirmView.as_view(), name='auth-confirm'),

    # views
    class ConfirmView(View):
       def dispatch(self, request, uidb36, token):
           assert None not in (uidb36, token)
           try:
               uid_int = base36_to_int(uidb36)
               user = User.objects.get(id=uid_int)
           except User.DoesNotExist:
               user = None

           if user is not None and token_generator.check_token(user, token):
               messages.add_message(request, messages.INFO, 'Successful')
    adw/0
  • adw0rd

    Сообщения: 22907 Репутация: N Группа: в ухо

    Spritz 28 июня 2012 г. 9:23, спустя 7 минут 1 секунду

    Вопрос:
    1) Правильно ли я делаю структуру контролера?
    т.е. я знаю, что контроллер только получает данные и проверяет их с помощью моделей. Контроллер не в коем случае не должен выполнять какие либо модификации, как я понял он манипулирует результатами из методов Model и в зависимости от них открывает те или иные данные в View.

    2) Правильно я делаю, что полученный результат от методов Моделей я проверяю в Контроллере и выдаю сообщение об ошибке или успехе(т.е. сама структура)?


    1. Раздели свой контроллер на стадии через методы контроллера, например "Проверка ключа", "Неуспешноая проверка", "Успешная проверка" и "Отпрвка письма"
    2. Зачем генерировать $Content? Почему сразу не рисовать в шаблон?
    3. Что такое "lang"? В Template::lang()
    4. Для чего в DisplayResponse 'error' и 'success'?
    5. Что делает иньекция? Section::inject('content', $Content);
    6. $UserRowsValueByPasskey = User::UserRowsValueByPasskey($Passkey); - ты сам создал User::UserRowsValueByPasskey?
    adw/0
  • tartar

    Сообщения: 186 Репутация: N Группа: Кто попало

    Spritz 28 июня 2012 г. 11:44, спустя 2 часа 21 минуту 10 секунд

    1. Раздели свой контроллер на стадии через методы контроллера, например "Проверка ключа", "Неуспешноая проверка", "Успешная проверка" и "Отпрвка письма"
    2. Зачем генерировать $Content? Почему сразу не рисовать в шаблон?
    3. Что такое "lang"? В Template::lang()
    4. Для чего в DisplayResponse 'error' и 'success'?
    5. Что делает иньекция? Section::inject('content', $Content);
    6. $UserRowsValueByPasskey = User::UserRowsValueByPasskey($Passkey); - ты сам создал User::UserRowsValueByPasskey?


    return self.render_to_response('registration/empty_passkey.html') 

    registration.empty_passkey - это не шаблон, это путь до языкового файла разделяемый через запитую
    -> /language/ru/registration -> из массива в файле получаем значение для empty_passkey

    Ответ на №3:
    Сайт многоязычный, родной метод получения нужной мне строки из файла языка мне нужно было сделать более динамичным под смену языка
    static function lang($line, $options=array() ) {
    return Lang::line($line, $options)->get( Template::CurrentLanguage() );
    }


    Родной метод фреймворка
    Lang::line( "Название_файла_из_папки_languages . ключ массива " )->get( папка языка - ru, en )

    http://laravel.com/docs/localization

    Ответ на №2 - 5
    шаблон вызывается внизу через View::make, в фреймворке я могу использовать его шаблонизатор. Шаблонизатор фреймворка устроен на блоках.
    Section::inject('content', $Content); Создает блок Content который заменяет в файле шаблона искусственную переменную @yield('content') на указанные данные из переменной $Content.
    http://daylerees.com/2012/04/07/laravel-blade/

    Ответ на № 4
    Получаю информационный блок в виде HTML с информацией о error - ошибке, success - успехе выполнения, info - важная информация
        static function DisplayResponse($Response, $type='info') {
    $Message = '';
    if(!$Response) {return;}
    if(is_array($Response)) {
    foreach($Response as $line) {
    $Message .= $line.'<br />';
    }
    }

    return View::make('display_message', array(
    'type' => $type,
    'message' => $Message
    ));

    }


    Ответ на №6
    Методы: Template, User мои, остальные фреймворка. С названием подкачал наверное :)
        public static function UserRowsValueByPasskey($passkey) {
    /*
    * Данные о пользователе по его Passkey
    */
    return Registration::where('passkey', '=', $passkey)
    ->first();
    }
    Спустя 149 сек.
    Модели: Template, User **
  • Troy

    Сообщения: 2532 Репутация: N Группа: Джедаи

    Spritz 28 июня 2012 г. 18:05, спустя 6 часов 20 минут 40 секунд

    Примерно так это будет в Yii, если использовать твой алгоритм
    <?php

    class AuthorizationController extends BaseController
    {

       /**
        * Подтверждение запроа на восстановление пароля
        */
       public function actionConfirm($paskey)
       {
           $user = User::model()->findByAttributes(array('paskey' => $paskey));
           if ($user == null)
           {
               $this->render('confirm', array(
                   'msg' => Yii::t('users', 'Empty paskey.')
               ));
           }
           else
           {
               $newPassword = $user->updatePassword();
               if ($newPassword === false)
               {
                   $this->render('confirm', array(
                       'msg' => Yii::t('users', 'Error updating password.')
                   ));
               }
               else
               {
                   $this->render('confirm', array(
                       'msg' => Yii::t('users', 'Password for {email} successful updated.', array('email' => $user->email))
                   ));
                   
                   $user->sendMail($this->renderPartial('successful_password_updating', array(
                       'login' => $user->login,
                       'password' => $newPassword,
                       'ip' => Yii::app()->request->userHostAddress,
                       'domain' => Yii::app()->request->baseUrl,
                   ), true));
               }
           }
       }


    }
  • kostyl

    Сообщения: 5203 Репутация: N Группа: Джедаи

    Spritz 29 июня 2012 г. 11:06, спустя 17 часов 1 минуту 20 секунд

    В юи читаимей. Инфа 100%!
  • adw0rd

    Сообщения: 22907 Репутация: N Группа: в ухо

    Spritz 29 июня 2012 г. 12:13, спустя 1 час 6 минут 45 секунд

    kostyl, не соглашусь, но и спорить не стану, всетаки почти все пхпешники тут
    adw/0
  • adw0rd

    Сообщения: 22907 Репутация: N Группа: в ухо

    Spritz 29 июня 2012 г. 12:40, спустя 26 минут 59 секунд

    Вот копия логики Троя на django
    class AuthorizationController(YiiTemplateMixin, TemplateView):
       """Подтверждение запроа на восстановление пароля
       """

       def dispatch(self, request, paskey):
           try:
               user = User.objects.get(paskey=paskey)
           except User.DoesNotExist:
               return self.render_to_response("confirm", msg='Empty paskey.')
           else:
               new_password = user.update_password()
               if not new_password:
                   return self.render_to_response("confirm", msg='Error updating password.')
               else:
                   user.send_mail('successful_password_updating', dict(
                       login=user.username,
                       password=new_password,
                       ip=request.META['REMOTE_ADDR'],
                       domain=Site.objects.get_current().domain))
                   return self.render_to_response("confirm",
                       msg='Password for {email} successful updated.'.format(email=user.email))


    class YiiTemplateMixin(object):
       """Для того чтобы выглядило также как в Yii
       """

       def render_to_response(template_name, **context):
           self.template_name = template_name.replace('.html', '') + '.html'
           return super(YiiTemplateMixin, self).render_to_response(context)
    Спустя 82 сек.
    Некоторые не пользуются format'ом:
    'Password for {email} successful updated.'.format(email=user.email)

    Предпочитая так:
    'Password for %(email)s successful updated.' % dict(email=user.email)
    Спустя 180 сек.
    Кидать исключение вместо возвращения False/None это более правильно, можете об этом также почитать в книге "Чистый код"
    User.DoesNotExist


    У Троя "domain" это строка из реквеста, у меня "domain" это домен сайта, так как у джанги есть The “sites” framework
    Site.objects.get_current().domain
    adw/0
  • Troy

    Сообщения: 2532 Репутация: N Группа: Джедаи

    Spritz 29 июня 2012 г. 13:46, спустя 1 час 6 минут 17 секунд

    adw0rd, я именно переписал его код на Yii, если менять сам код, то получится примерно то, что ты говоришь. В Yii тоже даже в примерах используются исключения, как более правильное решение.

    Примерно так бы написал я
    <?php 
    class AuthorizationController extends BaseController
    {

    /**
    * Подтверждение запроа на восстановление пароля
    */
    public function actionConfirm($paskey)
    {
    $user = User::model()->findByAttributes(array('paskey' => $paskey));
    if ($user == null)
    throw new CExeption(Yii::t('users', 'Empty paskey.'));

    $newPassword = $user->updatePassword();
    if ($newPassword === false)
    throw new CExeption(Yii::t('users', 'Error updating password.'));

    $user->sendMail($this->renderPartial('successful_password_updating', array(
    'login' => $user->login,
    'password' => $newPassword,
    'ip' => Yii::app()->request->userHostAddress,
    'domain' => Yii::app()->request->baseUrl,
    ), true));

    Yii::app()->user->setFlash('success', Yii::t('users', 'Password successful updated.'));
    $this->redirect(array('profile'));
    }

    }
    Спустя 106 сек.
    adw0rd, Yii::t() это перевод строки на другой язык.
  • tartar

    Сообщения: 186 Репутация: N Группа: Кто попало

    Spritz 29 июня 2012 г. 14:37, спустя 51 минуту 8 секунд

    Как же я ненавижу такие функции аля t(); a(); do(); функции, переменные, массивы… должны быть названы в честь того, что они содержат или выполняют.
  • adw0rd

    Сообщения: 22907 Репутация: N Группа: в ухо

    Spritz 29 июня 2012 г. 17:07, спустя 2 часа 29 минут 48 секунд

    В Yii тоже даже в примерах используются исключения, как более правильное решение.

    ну ты сам гененрируешь исключения, а я его перелавливаю, получается Yii если нет такого пользователя возвращает null?
    Спустя 175 сек.
    adw0rd, Yii::t() это перевод строки на другой язык.

    ясно, в django обычно делается так:

    from django.utils.translation import ugettext as _

    _("Translated text")


    А для шаблонов так:

    {% load i18n %}

    {% trans "Translated text" %}
    или
    {% blocktrans %}Hello {{ username }}!{% endblocktrans %}
    adw/0

Пожалуйста, авторизуйтесь, чтобы написать комментарий!