Использование интерфейсов в Kohana 3.1.3 - PullRequest
14 голосов
/ 29 мая 2011

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

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

Имеет ли этот подход смысл? Если да, то как, черт возьми, я это делаю (как мне лучше структурировать файловую систему?)

Вот грубое начало, над которым я работал:

<?php defined('SYSPATH') or die('No direct script access.');

/**
* Project_Builder @state
* Step_One @state
* Step_Two @state
**/

interface Project_Builder 
{
    public function do_this_first();
    public function validate();
    public function do_this_after();
}

class Step_One implements Project_Builder {

    public function __construct
    {
        parent::__construct();

        // Do validation and set a partial variable if valid

    }

    public function do_this_first() 
    {
        echo 'First thing done';
        // This should be used to set the session step variable, validate and add project data, and return the new view body.
            $session->set('step', '2');


    }
    public function do_this_after()
    {
        throw new LogicException('Have to do the other thing first!');
    }

}

class Step_Two implements Project_Builder {
    public function do_this_first()
    {
        throw new LogicException('Already did this first!');
    }
    public function do_this_after()
    {
        echo 'Did this after the first!';
        return $this;
    }
}

class Project implements Project_Builder {
    protected $state;
    protected $user_step;
    protected $project_data

    public function __construct()
    {
        // Check the SESSION for a "step" entry. If it does not find one, it creates it, and sets it to "1".
        $session = Session::instance('database');

        if ( ! $session->get('step'))
        {
            $session->set('step', '1');
        }

        // Get the step that was requested by the client.
        $this->user_step = $this->request->param('param1');

        // Validate that the step is authorized by the session.
        if ($session->get('step') !== $this->user_step)
        {
            throw new HTTP_Exception_404('You cannot skip a step!');
        }

        // Check if there is user data posted, and if so, clean it.
        if (HTTP_Request::POST == $this->request->method())
        {
            foreach ($this->request->post() as $name => $value)
            {
                $this->project_data["$name"] = HTML::chars($value);
            }
        }   

        // Trigger the proper state to use based on the authorized session step (should I do this?)
        $this->state = new Step_One;
    }
    public function doThisFirst()
    {
        $this->state = $this->state->do_this_first();
    }
    public function doThisAfter()
    {
        $this->state = $this->state->do_this_after();
    }
}

$project = new Project;
try
{
    $project->do_this_after(); //throws exception
}
catch(LogicException $e)
{
    echo $e->getMessage();
}

$project = new Project;
$project->do_this_first();
$project->validate();
$project->do_this_after();
//$project->update();

1 Ответ

1 голос
/ 15 августа 2011

Ваш путь, безусловно, выглядит возможным, однако я бы соблазнился сделать его проще и использовать некоторые встроенные функции Kohanas, чтобы позаботиться о том, что вы хотите. Например, я бы использовал Kostache (усы) и имел отдельные классы View (и, возможно, шаблоны) для каждого шага. Тогда контроллер становится довольно простым. Смотрите пример ниже (пропущенный материал сеанса и проверка номера шага). Все проверки обрабатываются в модели. Если есть ошибка проверки, может быть сгенерировано исключение, которое затем может передавать сообщения об ошибках обратно в представление.

<?php

class Wizard_Controller {

    function action_step($step_number = 1)
    {
        $view = new View_Step('step_' + $step_number);

        if ($_POST)
        {
            try
            {
                $model = new Model_Steps;
                $model->step_number = $step_number;
                if ($model->save($_POST))
                {
                    // Go to the next step
                    $step_number++;
                    Request::current()->redirect('wizard/step/'.$step_number);    
                }
            }
            catch (Some_Kind_Of_Exception $e)
            {
                $view->post = $_POST;
                $view->errors = $e->errors();
            }
        }

        $view->render();
    }
}
?>

Надеюсь, это имеет смысл.

...