2011-05-28 12 views
14

Estoy intentando crear un asistente de formulario en Kohana y estoy aprendiendo un poco sobre la marcha. Una de las cosas que he aprendido que podría funcionar mejor es utilizar un patrón de estado en la estructura de mi clase para administrar los diferentes pasos en los que puede estar un usuario durante el proceso del formulario.Uso de interfaces en Kohana 3.1.3

Después de investigar un poco, he estado pensando que el mejor enfoque puede ser utilizar una interfaz y hacer que todos los pasos funcionen como estados que implementan la interfaz. Después de validar un estado, cambiará una variable de sesión al siguiente paso, que se puede leer con la carga inicial de la interfaz y llamar al estado correcto para usar.

¿Este enfoque tiene sentido? Si es así, ¿cómo diablos hago que suceda (¿Cómo trato mejor la estructura del sistema de archivos?)

Aquí es el comienzo difícil que he estado trabajando en:

<?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

Básicamente está utilizando el [patrón de estado] (http://en.wikipedia.org/wiki/State_pattern) como podría haber averiguado. ¿Aún necesitas ayuda con esta pregunta? – Ikke

+0

Definitivamente estaría interesado en escuchar diferentes enfoques. –

Respuesta

1

Su forma ciertamente parece posible, Sin embargo, me sentiría tentado a simplificarlo y utilizar algunas de las características de Kohanas para que se encargue de lo que desea. Por ejemplo, usaría Kostache (bigote) y tendría clases de vista separadas (y potencialmente plantillas) para cada paso. Entonces el controlador se vuelve bastante simple. Vea el ejemplo a continuación (material de sesión faltante y validación del step_number). Toda la validación se maneja en el modelo. Si hay un error de validación, se puede lanzar una excepción que luego puede pasar mensajes de error a la Vista.

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

la esperanza que esto tiene sentido.

+0

Esto tiene sentido, y he estado pensando más en estas líneas, pero agregar los elementos a la sesión después de la validación en mi controlador realmente ha hinchado mi controlador. Aún pensando que tiene que haber una manera más limpia de hacer las cosas ... –