CodeIgniter中的Fat Model Skinny Controller

时间:2011-09-25 20:09:16

标签: php model-view-controller codeigniter

我一直在使用CodeIgniter,并且对MVC,PHP等有很好的了解。

然而,我发现很难坚持Fat Model Skinny Controller的精神。

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

我发现很难将表单逻辑移动到模型中。例如,我正在为我的auth系统使用自定义库,它有自己的模型。我是否应该建立一个站点用户模型来登录用户?或者我应该制作一个网站模型来做到这一点?或表格模型?

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

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();
}

提前致谢!

1 个答案:

答案 0 :(得分:3)

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

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

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,这是保持方法简短的有力论据。