【问题标题】:Fat Model Skinny Controller in CodeIgniterCodeIgniter 中的 Fat Model Skinny 控制器
【发布时间】:2011-11-24 18:49:50
【问题描述】:

我使用 CodeIgniter 已经有一段时间了,对 MVC、PHP 等有一定的了解。

但是,我发现很难坚持 Fat Model Skinny Controller 精神。

我已经看过很多了;包括在每个文件中包含哪些伪代码,但没有实际示例。 (如果我遗漏了任何明显的文章,请链接到一些文章!)

我发现很难将表单逻辑移动到模型中。例如,我为我的身份验证系统使用了一个自定义库,它有自己的模型。然后我应该制作一个站点用户模型来登录用户吗?还是我应该只制作一个站点模型来做到这一点?还是表单模型?

为了帮助我,任何人都可以告诉我如何对这个控制器进行皮肤化吗?我意识到这是很多代码,但简单的指针会很棒。 (请注意,我只是写了这段代码,所以它没有被太多重构,但它应该是一个很好的例子,说明我的一些方法是如何失控的。)

public function register()
{
    session_start();
    if ($this->tf_login->logged_in())
    {
        redirect('profile');
    }
    if ($_GET['oauth'] == 'true')
    {
        $type = $_GET['type'];
        try 
        {
            $token = $this->tf_login->oauth($type, '', 'email');
        }
        catch (TFLoginCSRFMismatchException $e)
        {
            $this->tf_assets->add_data('error_message', $e->getMessage());
        }
        catch (TFLoginOAuthErrorException $e)
        {
            $this->tf_assets->add_data('error_message', $e->getMessage());
        }
        if ($token)
        {
            $user_details = $this->tf_login->call('https://graph.facebook.com/me?fields=email,first_name,last_name,username&access_token=' . $token);
            $user_details_decoded = json_decode($user_details);
            if ($user_details_decoded->email)
            {
                try 
                {
                    $id = $this->tf_login->create_user($user_details_decoded->username,
                    md5($user_details_decoded->username . time()),
                    $user_details_decoded->email,
                    '',
                    TRUE,
                    TRUE);
                }
                catch (TFLoginUserExistsException $e)
                {
                    try
                    {
                        if ($this->tf_login->oauth_login($type, $user_details_decoded->email, $token))
                        {
                            $this->session->set_flashdata('success_message', 'You have successfully logged in.');
                            redirect('profile');
                        }
                        else
                        {
                            $this->session->set_flashdata('error_message', 'An account with these details exists, but currently isn\'t synced with ' . $type . '. Please log in to sync the account.');
                        }
                    }
                    catch (Exception $e)
                    {
                        $this->session->set_flashdata('error_message', $e->getMessage());
                    }
                }
                catch (TFLoginUserNotCreated $e)
                {
                    $this->tf_assets->add_data('error_message', 'You could not be registered, please try again.');
                }
                if ($id)
                {
                    $this->tf_login->add_user_meta($id, 'first_name', $user_details_decoded->first_name);
                    $this->tf_login->add_user_meta($id, 'surname', $user_details_decoded->last_name);
                    $this->tf_login->sync_accounts($id, $type, $token);
                    $this->session->set_flashdata('success_message', 'Welcome ' . $this->input->post('first_name', TRUE) . ' ' . $this->input->post('surname', TRUE) . '. Your account has been sucessfully created. You will shortly receive an email with a verification link in.');
                    redirect('login');
                }
            }
            else
            {
                $this->session->set_flash_data('error_message', 'You could not be logged in, please try again.');
            }
        }
        // Redirect to clear URL
        redirect(current_url());
    }

    if ($this->form_validation->run() !== FALSE)
    {
        try
        {
            $id = $this->tf_login->create_user($_POST['username'], $_POST['password'], $_POST['email'], '', FALSE);
        }
        catch (Exception $e)
        {
            $this->tf_assets->add_data('error_message', $e->getMessage());
        }
        if ($id)
        {
            $this->tf_login->add_user_meta($id, 'first_name', $_POST['first_name']);
            $this->tf_login->add_user_meta($id, 'surname', $_POST['surname']);
            if ($this->tf_login->register_verification_email())
            {
                $this->session->set_flashdata('success_message', 'Welcome ' . $this->input->post('first_name', TRUE) . ' ' . $this->input->post('surname', TRUE) . '. Your account has been sucessfully created. You will shortly receive an email with a verification link in.');
                redirect('login');
            }
            else
            {
                $this->tf_login->login_user($id);
                $this->session->set_flashdata('success_message','Your account has been sucessfully created.');
                redirect('profile');
            }
        }
        else
        {
            $this->tf_assets->add_data('error_message', $this->tf_login->get_errors());
        }
    }
    if (validation_errors())
    {
        $this->tf_assets->add_data('error_message', validation_errors());
    }
    $this->tf_assets->set_content('public/register');
    $this->tf_assets->add_data('page_title', "Register");
    $this->tf_assets->render_layout();
}

提前致谢!

【问题讨论】:

  • “胖模型”讲道适用于原始的 MVC 模式。 It's not what the PHP frameworks do。 CI对你也没有多大好处。把 Controller 当作表单处理接口,其实并没有什么实际问题。
  • 当我搜索以前没有出现的问题时。我会通读一遍,干杯:)
  • 只做必要的事情,不要担心别人的完美想法。记住,控制器(函数)、模型(函数)和视图都是页面的一部分。框架应该可以加快速度,而不是让您担心每段代码应该或不应该在哪里。
  • 非常真实,我确实经常陷入做事的最佳方式,而不是仅仅完成它们!

标签: php model-view-controller codeigniter


【解决方案1】:

据我所知,大部分或全部代码都属于控制器或组件,所以我不认为您的问题是模型/控制器混淆。

但是,由于嵌套结构很深,并且无法将特定任务分解为自己的方法,因此代码难以阅读。您将从这里受益的主要重构是创建新的私有方法来分离您正在执行的离散子任务。这还有一个重要的好处,那就是澄清当前方法的高级结构。所以你最终会得到一些看起来像的东西(只是给你一个粗略的例子):

public function register()
{
    session_start();
    if ($this->tf_login->logged_in())
    {
        redirect('profile');
    }
    if ($_GET['oauth'] == 'true')
    {
        $this->oauthRegister();
    }

    $this->normalRegister();
}

同样,oatuhRegister 方法和normalRegister 方法本身会被分解成更小的方法,这样当你完全完成时,每个方法都将遵循SRP,并且可能少于 10 行代码。这将极大地提高代码的可读性和可维护性。我还建议您查看Clean Code,它为保持您的方法简短提供了强有力的论据。

【讨论】:

  • 我曾考虑将其拆分为单独的私有方法,但后来我认为这些可以交给模型。然后我认为我真的不喜欢处理重定向、设置错误等的模型。我想我会把它分开,专注于让它更具可读性。我会尽快将此标记为已接受的答案,除非其他人发布了一些启发性的内容,因为到目前为止这是最有意义的。
  • 您的直觉绝对正确,将重定向排除在模型之外。另一件事可能对您有所帮助,当我询问是否应该在模型或控制器中进行身份验证时,我在其他地方收到了一个答案:pastebin.com/SKvpjrk0。因此,虽然您是对的,通常更改模型的代码都放在模型中,但身份验证通常放在控制器中,这是有道理的,因为它实际上是一种“控制”访问的行为。
猜你喜欢
  • 2015-07-13
  • 2019-08-20
  • 2013-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-30
相关资源
最近更新 更多