CodeIgniter中的Fat Model Skinny Controller

Tod*_*ish 6 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();
}
Run Code Online (Sandbox Code Playgroud)

提前致谢!

Jon*_*nah 3

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

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

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

    $this->normalRegister();
}
Run Code Online (Sandbox Code Playgroud)

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