Spanish (Español) translation by Steven (you can also view the original English article)
Gracias a la clase fieldset de FuelPHP, trabajar con formularios no podría ser más fácil. Con unas pocas líneas de código, puedes generar y validar fácilmente un formulario. ¡Hoy vamos a aprender cómo hacerlo!
La clase
Fieldsetse usa para crear un formulario y manejar su validación de forma orientada a objetos. Utiliza las clasesFormyValidation. Esta clase, en sí misma, solo pretende modelar el conjunto de campos y sus campos, mientras que las otras dos clases realizan la mayor parte del trabajo.
Configurar Fuel
Necesitamos una instalación FuelPHP con un paquete RM habilitado. Voy a usar una base de datos MySQL con una tabla de muestra. Si bien la clase Fieldset se puede configurar para usar un modelo normal, usar un ORM nos ahorrará algo de tiempo.
Si no has revisado las primeras partes de la serie FuelPHP aquí en Nettuts+, ahora es un buen momento para ver las partes uno y dos, por Phil Sturgeon.
Configura una conexión de base de datos en fuel/app/config/development/db.php.
1 |
return array( |
2 |
'default' => array( |
3 |
'connection' => array( |
4 |
'dsn' => 'mysql:host=localhost;dbname=blog', |
5 |
'username' => 'root', |
6 |
'password' => 'root', |
7 |
),
|
8 |
),
|
9 |
);
|
Habilita el paquete ORM a través de fuel/app/config.php
1 |
'packages' => array( |
2 |
'orm', |
3 |
),
|
Y, finalmente, aquí está el SQL para la tabla que estoy usando para este tutorial.
1 |
CREATE TABLE `blog`.`posts` ( |
2 |
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , |
3 |
`post_title` VARCHAR( 100 ) NOT NULL , |
4 |
`post_content` TEXT NOT NULL , |
5 |
`author_name` VARCHAR( 65 ) NOT NULL , |
6 |
`author_email` VARCHAR( 80 ) NOT NULL , |
7 |
`author_website` VARCHAR( 60 ) NULL, |
8 |
`post_status` TINYINT NULL |
9 |
) ENGINE = INNODB; |
Modelo
Necesitamos un modelo para que nuestro controlador interactúe con la tabla de publicaciones. Continúa y crea un archivo llamado post.php dentro de app/classes/model/. Crea una clase Model_Post y asegúrate de que se extienda de \Orm\Model. El ORM usará automáticamente la tabla posts en nuestra base de datos, ya que hemos utilizado el singular de "posts". Si deseas establecer una tabla diferente, configura una propiedad estática llamada $_table_name.
1 |
class Model_Post extends \Orm\Model |
2 |
{
|
3 |
protected static $_table_name = 'posts'; //set the table name manually |
4 |
}
|
Configurar las propiedades
Deberíamos especificar las columnas de nuestra tabla posts dentro de nuestro modelo. Al mismo tiempo, también podemos configurar etiquetas, reglas de validación de formularios para usar con nuestra clase de conjunto de campos para generar el formulario. Todos estos van en una matriz asociativa, llamada $_properies. Con todo en su lugar, nuestro modelo final debería verse así:
1 |
class Model_Post extends \Orm\Model |
2 |
{
|
3 |
protected static $_table_name = 'posts'; |
4 |
|
5 |
protected static $_properties = array( |
6 |
'id', |
7 |
'post_title' => array( //column name |
8 |
'data_type' => 'string', |
9 |
'label' => 'Post Title', //label for the input field |
10 |
'validation' => array('required', 'max_length'=>array(100), 'min_length'=>array(10)) //validation rules |
11 |
),
|
12 |
'post_content' => array( |
13 |
'data_type' => 'string', |
14 |
'label' => 'Post Content', |
15 |
'validation' => array('required') |
16 |
),
|
17 |
'author_name' => array( |
18 |
'data_type' => 'string', |
19 |
'label' => 'Author Name', |
20 |
'validation' => array('required', 'max_length'=>array(65), 'min_length'=>array(2)) |
21 |
),
|
22 |
'author_email' => array( |
23 |
'data_type' => 'string', |
24 |
'label' => 'Author Email', |
25 |
'validation' => array('required', 'valid_email') |
26 |
),
|
27 |
'author_website' => array( |
28 |
'data_type' => 'string', |
29 |
'label' => 'Author Website', |
30 |
'validation' => array('required', 'valid_url', 'max_length'=>array(60)) |
31 |
),
|
32 |
'post_status' => array( |
33 |
'data_type' => 'string', |
34 |
'label' => 'Post Status', |
35 |
'validation' => array('required'), |
36 |
'form' => array('type' => 'select', 'options' => array(1=>'Published', 2=>'Draft')), |
37 |
)
|
38 |
|
39 |
|
40 |
);
|
41 |
}
|
Examinemos qué opciones podemos usar. data_type simplemente contiene el tipo de campo. Puede ser string, integer o mysql_date. El valor de la propiedad label se mostrará como la etiqueta del campo una vez que se genere el formulario (será el título del campo). validation acepta una variedad de reglas de validación. Por defecto, estos campos serán campos de entrada de texto. Usando form, puedes convertirlo en select o textarea.
El ORM trata la columna denominada id como primaria y no se mostrará al generar un formulario. Si la columna de clave primaria de tu tabla es diferente, usa la propiedad $_primary_key para especificarla.
1 |
/**
|
2 |
* Post Model
|
3 |
*/
|
4 |
class Model_Post extends \Orm\Model |
5 |
{
|
6 |
protected static $_table_name = 'posts'; |
7 |
|
8 |
protected static $_primary_key = array('id'); //you can set up multiple columns, .. $_primary_key => array('id', 'user_id') |
9 |
}
|
Controlador
Ahora que el modelo está listo, creemos el controlador. Los controladores deben ubicarse dentro de fuel/app/classes/controller/. Creé un controlador, llamado Controller_Posts (posts.php) y lo extendí desde Controller_Template.
1 |
/**
|
2 |
* Post Controller fuel/app/classes/controller/posts.php
|
3 |
*/
|
4 |
class Controller_Posts extends \Controller_Template |
5 |
{
|
6 |
//list posts
|
7 |
function action_index() |
8 |
{
|
9 |
|
10 |
}
|
11 |
|
12 |
//add new one
|
13 |
function action_add() |
14 |
{
|
15 |
|
16 |
}
|
17 |
|
18 |
//edit
|
19 |
function action_edit($id) |
20 |
{
|
21 |
|
22 |
}
|
23 |
}
|
Los usuarios podrán ver una lista de publicaciones, agregar nuevas o editar una existente. Debido a que estoy usando el controlador de plantilla, puedo usar un archivo de plantilla base para trabajar. Las plantillas van en fuel/app/views/template.php
1 |
<!DOCTYPE html>
|
2 |
<html>
|
3 |
<head>
|
4 |
<meta http-equiv="Content-type" content="text/html; charset=utf-8" /> |
5 |
<?php echo Asset::css('bootstrap.css'); ?>
|
6 |
</head>
|
7 |
|
8 |
<body>
|
9 |
|
10 |
<div id="content"> |
11 |
|
12 |
<p>
|
13 |
<?php
|
14 |
echo \Html::anchor('posts/index', 'Listing'), ' ', \Html::anchor('posts/add', 'Add');
|
15 |
?>
|
16 |
</p>
|
17 |
|
18 |
<?php if(isset($messages) and count($messages)>0): ?>
|
19 |
<div class="message"> |
20 |
<ul>
|
21 |
<?php
|
22 |
foreach($messages as $message)
|
23 |
{
|
24 |
echo '<li>', $message,'</li>';
|
25 |
}
|
26 |
?>
|
27 |
</ul>
|
28 |
</div>
|
29 |
<?php endif; ?>
|
30 |
|
31 |
<?php echo $content; ?>
|
32 |
</div>
|
33 |
|
34 |
</body>
|
35 |
</html>
|
Esto es simplemente un marcado HTML estándar con el bootstrap de Twitter. La variable $content tendrá el contenido. Podemos configurar una serie de mensajes y, si lo hacemos, se imprimirá como una lista desordenada.
Agregar nuevas publicaciones
Aquí es donde comienza la diversión. Vamos a generar el formulario para agregar nuevas publicaciones. Como habrás adivinado, trabajaremos con el método action_add(). Generemos el formulario y pasémoslo a nuestra plantilla.
1 |
//add new one
|
2 |
function action_add() |
3 |
{
|
4 |
$fieldset = Fieldset::forge()->add_model('Model_Post'); |
5 |
$form = $fieldset->form(); |
6 |
|
7 |
$this->template->set('content', $form->build(), false); //false will tell fuel not to convert the html tags to safe string. |
8 |
}
|
Fieldset::forge() devolverá una nueva instancia de la clase fieldset. Es lo mismo que hacer un new Fieldset. Sin embargo, usando el método forge aquí, podemos nombrar nuestras instancias. Si llamamos a una instancia dos veces con el mismo nombre, se devolverá una instancia existente si está disponible [el patrón Factory]. Para nombrar tu instancia, pasa el nombre al método forge. Fieldset::forge('new_post')
Usando el método add_model, pasamos el modelo desde el que queremos que se generen los formularios. Fieldset tomará los datos de $_properties para generar el formulario. Llamar al método form() desde el objeto fieldset devolverá una instancia de la clase Form, y al llamar al método build(), podemos obtener una salida html (string) del formulario.
1 |
$this->template->set('content', $form, false); |
Finalmente, pasamos el formulario mediante la variable $form a la plantilla como contenido. Otro método para pasar variables a una plantilla es $this->template->content = $form.
Abre tu navegador y ve a http://path_to_site/index.php/posts/add. Deberías ver una forma idéntica a esta.


¿Sin botón de enviar? Vamos a arreglar eso. Necesitamos agregar un nuevo campo a nuestro objeto de formulario.
1 |
$form->add('submit', '', array('type' => 'submit', 'value' => 'Add', 'class' => 'btn medium primary')); |
Usando el método add podemos agregar campos adicionales a nuestro formulario. El primer parámetro es el nombre de nuestro nuevo campo, el segundo es para la etiqueta, para el tercer parámetro pasamos una matriz de atributos.
Después de agregar esto, nuestro action_add() se verá así.
1 |
function action_add() |
2 |
{
|
3 |
$fieldset = Fieldset::forge()->add_model('Model_Post'); |
4 |
$form = $fieldset->form(); |
5 |
$form->add('submit', '', array('type' => 'submit', 'value' => 'Add', 'class' => 'btn medium primary')); |
6 |
|
7 |
$this->template->set('content', $form->build(), false); |
8 |
}
|
Y nuestro formulario...


Validando y Guardando
Ahora que tenemos un buen formulario, validemos y guardemos en la base de datos. El objeto fieldset incluye una instancia de la clase de validación de FuelPHP. Todas las reglas se han aplicado y están listas para funcionar.
1 |
function action_add() |
2 |
{
|
3 |
$fieldset = Fieldset::forge()->add_model('Model_Post'); |
4 |
$form = $fieldset->form(); |
5 |
$form->add('submit', '', array('type' => 'submit', 'value' => 'Add', 'class' => 'btn medium primary')); |
6 |
|
7 |
if($fieldset->validation()->run() == true) |
8 |
{
|
9 |
$fields = $fieldset->validated(); |
10 |
|
11 |
$post = new Model_Post; |
12 |
$post->post_title = $fields['post_title']; |
13 |
$post->post_content = $fields['post_content']; |
14 |
$post->author_name = $fields['author_name']; |
15 |
$post->author_email = $fields['author_email']; |
16 |
$post->author_website = $fields['author_website']; |
17 |
$post->post_status = $fields['post_status']; |
18 |
|
19 |
if($post->save()) |
20 |
{
|
21 |
\Response::redirect('posts/edit/'.$post->id); |
22 |
}
|
23 |
}
|
24 |
else
|
25 |
{
|
26 |
$this->template->messages = $fieldset->validation()->errors(); |
27 |
}
|
28 |
|
29 |
$this->template->set('content', $form->build(), false); |
30 |
}
|
$fieldset->validation() devuelve una instancia de la clase 'validation' y al acceder a su método run() podemos verificar si se pasa la validación. Si es así, agregamos una nueva publicación a nuestra base de datos. $fieldset->validated() devolverá una matriz de campos validados. Si se aprueba la validación y se guarda la publicación, el usuario será redirigido a la página de edición; de lo contrario, se pasarán los errores de validación a nuestra plantilla dentro de la variable $message.
Si intentas enviar algunos datos no válidos, obtendrás una salida como esta:


Todo parece estar bien, excepto por un problema: los datos que enviamos no aparecen después de la actualización de la página. No te preocupes, llama a un método y ya está.
1 |
$fieldset = Fieldset::forge()->add_model('Model_Post')->repopulate(); //repopulate method will populate your form with posted data |
Genial, ¿eh? Agrega algunos datos válidos y esto te va a redirigir al método action_edit(), que aún no está listo.
Editando una publicación
Editar una sección es más o menos lo mismo que nuestra sección de agregar publicación. Excepto que necesitamos llenar los datos con una publicación existente. Voy a duplicar el código action_add.
1 |
|
2 |
function action_edit($id) |
3 |
{
|
4 |
$post = \Model_Post::find($id); |
5 |
|
6 |
$fieldset = Fieldset::forge()->add_model('Model_Post')->populate($post); //model post object is passed to the populate method |
7 |
$form = $fieldset->form(); |
8 |
$form->add('submit', '', array('type' => 'submit', 'value' => 'Save', 'class' => 'btn medium primary')); |
9 |
|
10 |
if($fieldset->validation()->run() == true) |
11 |
{
|
12 |
$fields = $fieldset->validated(); |
13 |
|
14 |
//$post = new Model_Post;
|
15 |
$post->post_title = $fields['post_title']; |
16 |
$post->post_content = $fields['post_content']; |
17 |
$post->author_name = $fields['author_name']; |
18 |
$post->author_email = $fields['author_email']; |
19 |
$post->author_website = $fields['author_website']; |
20 |
$post->post_status = $fields['post_status']; |
21 |
|
22 |
if($post->save()) |
23 |
{
|
24 |
\Response::redirect('posts/edit/'.$id); |
25 |
}
|
26 |
}
|
27 |
else
|
28 |
{
|
29 |
$this->template->messages = $fieldset->validation()->errors(); |
30 |
}
|
31 |
|
32 |
$this->template->set('content', $form->build(), false); |
33 |
}
|
Con algunas pequeñas modificaciones a nuestro método action_add(), tenemos nuestro método de edición. El método repopulate() ha sido reemplazado por el método populate(). Con el método populate, podemos rellenar un formulario con los datos de una publicación existente.
En este caso, tomamos la publicación de nuestra base de datos usando el parámetro $id, luego lo pasamos al método requerido. Y ya no necesitamos $post = new Model_Post; porque no estamos agregando nada a la base de datos. El objeto $post que creamos al principio se usa para asignar los nuevos valores. Una vez editado, esto te redirigirá a su pantalla de edición. ¡Ya hemos terminado! Agrega algunas publicaciones e intenta editarlas.
Listando las páginas
Construyamos la sección de listado para que los usuarios puedan ver todas las publicaciones en un solo lugar.
El listado se maneja mediante el método action_index()
1 |
//list posts
|
2 |
function action_index() |
3 |
{
|
4 |
$posts = \Model_Post::find('all'); |
5 |
|
6 |
$view = \View::forge('listing'); |
7 |
$view->set('posts', $posts, false); |
8 |
|
9 |
$this->template->content = $view; //In config file View objects are whitelisted so Fuelphp will not escape the html. |
10 |
}
|
Model_Post::find('all') devolverá una matriz de objetos con todas las publicaciones que tenemos en la base de datos. Usando View::forge(), se crea una instancia de un nuevo objeto de vista. El parámetro para View::forge() es el nombre de nuestra vista específica. Se encuentra en app/views/listing.php. El conjunto de objetos de publicaciones ($posts) luego se pasa a nuestra vista. La vista "Listing" se encargará del listado, y finalmente asignaremos la vista a $this->template->content.
En la vista, recorremos todas las publicaciones a través de la variable $posts y generamos la lista.
1 |
<?php
|
2 |
/**
|
3 |
* Listing view, views/listing.php
|
4 |
*/
|
5 |
if($posts):
|
6 |
foreach($posts as $post):
|
7 |
?>
|
8 |
|
9 |
<div class="post"> |
10 |
<h2><?php echo $post->post_title; ?> <small><?php echo \Html::anchor('posts/edit/'.$post->id, '[Edit]');?></small></h2> |
11 |
<p><?php echo $post->post_content; ?></p> |
12 |
<p>
|
13 |
<small>By <?php echo $post->author_name; ?></small><br /> |
14 |
<small><?php echo $post->author_email; ?></small><br /> |
15 |
<small><?php echo $post->author_website; ?></small><br /> |
16 |
</p>
|
17 |
</div>
|
18 |
|
19 |
<?php
|
20 |
endforeach;
|
21 |
endif;
|
22 |
?>
|
Si tienes alguna publicación en la base de datos, se verá más o menos así.


Algunas modificaciones finales
Todo parece estar funcionando correctamente; Sin embargo, hay algunos problemas menores. El formulario generado tiene un campo de texto para el contenido de la publicación, que sería mejor como un área de texto.
1 |
//Model_Post
|
2 |
'post_content' => array( |
3 |
'data_type' => 'string', |
4 |
'label' => 'Post Content', |
5 |
'validation' => array('required'), |
6 |
'form' => array('type' => 'textarea') //will give us a textarea |
7 |
),
|
Puedes pasar todos los tipos de campo: ttext, textarea, select, radio, etcétera. Para los elementos 'select' o 'radio', puedes configurar las opciones. También es posible establecer opciones para una selección usando otra tabla. Si deseas cambiar el diseño predeterminado, coloca un archivo de configuración de formulario en fuel/app/config/form.php. Si no estás seguro de qué poner allí, copia cosas de fuel/core/config/form.php. Fuel utiliza este archivo para generar los formularios.
Resumen
Espero que ahora tengas una comprensión clara de la clase fieldset. Si tienes alguna pregunta, házmelo saber en los comentarios a continuación. ¡Muchas gracias por leer!



