Advertisement
  1. Code
  2. PHP

Desarrolla tu primer paquete de administración para Laravel

Scroll to top
Read Time: 15 min

() translation by (you can also view the original English article)

Es difícil negar el hecho de que la comunidad de PHP está entusiasmada con Laravel 4. Entre otras cosas, el framework aprovecha el poder de Composer, lo que significa que puedes utilizar cualquier paquete o script de Packagist.

Mientras tanto, Laravel ofrece "Paquetes", que nos permiten modular el código para usarlo en futuros proyectos. El directorio de paquetes está lleno de excelentes scripts y paquetes que puedes utilizar en tus aplicaciones. En esta lección, te mostraré cómo construir uno desde cero.


Espera, ¿qué es un paquete?

Los paquetes ofrecen una manera fácil de agrupar código relacionado. Si estás familiarizado con CodeIgniter, los paquetes son muy similares a "Sparks". Esto es evidente cuando echas un vistazo a la estructura de carpetas.

Folder StructureFolder StructureFolder Structure

Crear un paquete es bastante simple. Para ilustrar el proceso, crearemos un panel de control del panel de administración que podremos utilizar en futuros proyectos. En primer lugar, debemos crear un directorio 'admin' dentro de nuestra carpeta 'bundles'. Intenta replicar la estructura de carpetas de la imagen de arriba.

Antes de comenzar a agregar algo a nuestro paquete, primero debemos registrarlo con Laravel. Esto se hace en el archivo bundles.php de tu aplicación. Una vez que abras este archivo, deberías ver una matriz que se devuelve; simplemente necesitamos agregar nuestro paquete y definir un identificador. Esto se convertirá en el URI en el que accedemos a nuestro panel de administración.

1
'admin' => array('handles' => 'admin')

Aquí, he llamado "admin" al mío, pero siéntete libre de llamar al tuyo como desees.

Una vez que tengamos esa configuración, necesitamos crear un archivo start.php. Aquí, vamos a configurar algunas cosas, como nuestros espacios de nombres. Si esto no te molesta, entonces realmente no necesitas un archivo de inicio para que tu paquete funcione, como se esperaba.

La clase autoloader de Laravel nos permite hacer un par de cosas: mapear nuestro controlador base y los espacios de nombres de carga automática.

1
Autoloader::map(array(
2
    'Admin_Base_Controller' => Bundle::path('admin').'controllers/base.php',
3
));
4
5
Autoloader::namespaces(array(
6
    'Admin\Models' => Bundle::path('admin').'models',
7
    'Admin\Libraries' => Bundle::path('admin').'libraries',
8
));

El espacio de nombres asegurará que no estemos en conflicto con otros modelos o bibliotecas que ya están incluidas en nuestra aplicación. Notarás que no hemos optado por no poner espacios de nombres a nuestros controladores para facilitar las cosas.


Publicando Recursos

Para el panel de administración, aprovecharemos el Bootstrap, así que ve a buscar una copia. Podemos colocar esto en una carpeta public dentro de nuestro paquete para poder publicarlo en nuestra aplicación más adelante.

Cuando estés listo para publicarlos, simplemente ejecuta el siguiente comando a través de artisan.

1
php artisan bundle:publish admin

Esto copiará la estructura de la carpeta y los archivos al directorio de paquetes en nuestra carpeta public, dentro de la raíz de la instalación de Laravel. Entonces podemos usar esto en el controlador base de nuestro paquete.


Configuración del controlador base

Siempre es una buena idea configurar un controlador base y extenderlo desde allí. Aquí, podemos configurar controladores tranquilos, definir el diseño e incluir cualquier recurso. Solo necesitamos llamar a este archivo, base.php, y colocarlo en el directorio de nuestro controlador.

En primer lugar, vamos a poner un poco de limpieza fuera del camino. Por supuesto, queremos utilizar los controladores restful de Laravel.

1
public $restful = true;

Y especificaremos un diseño que crearemos en breve. Si no estás acostumbrado a controlar diseños, entonces te espera una sorpresa.

1
public $layout = 'admin::layouts.main';

El nombre del paquete, seguido de dos puntos, es un paradigma en Laravel que veremos más en el futuro, así que mantente atento.

Cuando manejamos recursos dentro de nuestro paquete, podemos hacer las cosas como te esperas y especificar la ruta desde la raíz de la carpeta pública. Afortunadamente, Laravel está ahí para hacer nuestras vidas más fáciles. En nuestro constructor, necesitamos especificar el paquete, antes de agregarlo a nuestros contenedores de recursos.

1
Asset::container('header')->bundle('admin');
2
Asset::container('footer')->bundle('admin');

Si no estás familiarizado con los contenedores de recursos, no te preocupes; son simplemente secciones de una página donde deseas alojar tus recursos. Aquí, incluiremos hojas de estilo en el encabezado y scripts en el pie de página.

Ahora, con eso fuera del camino, podemos incluir nuestros estilos de arranque y scripts fácilmente. Nuestro controlador base completo debe ser similar a:

1
class Admin_Base_Controller extends Controller {
2
3
    public $restful = true;
4
    public $layout = 'admin::layouts.main';
5
6
    public function __construct(){
7
8
        parent::__construct();
9
10
        Asset::container('header')->bundle('admin');
11
        Asset::container('header')->add('bootstrap', 'css/bootstrap.min.css');
12
13
        Asset::container('footer')->bundle('admin');
14
        Asset::container('footer')->add('jquery', 'http://code.jquery.com/jquery-latest.min.js');
15
        Asset::container('footer')->add('bootstrapjs', 'js/bootstrap.min.js');
16
17
    }
18
19
    /**

20
     * Catch-all method for requests that can't be matched.

21
     *

22
     * @param  string    $method

23
     * @param  array     $parameters

24
     * @return Response

25
     */
26
    public function __call($method, $parameters){
27
        return Response::error('404');
28
    }
29
30
}

También hemos traído la solicitud general del controlador base de la aplicación para devolver una respuesta 404, en caso de que no se encuentre una página.

Antes de hacer algo más, hagamos el archivo para ese diseño, views/layout/main.blade.php, para que no encontremos ningún error más adelante.


Asegurando el paquete

Mientras estamos construyendo un panel de administración, vamos a querer mantener a la gente fuera. Afortunadamente, podemos usar la clase Auth integrada de Laravel para lograr esto con facilidad...

Primero, necesitamos crear nuestra tabla; usaré 'admins' como nombre de mi tabla, pero puedes cambiarlo si lo deseas. Artisan generará una migración y la incluirá en el directorio de migraciones de nuestro paquete. Simplemente ejecuta lo siguiente en la línea de comandos.

1
php artisan migrate:make admin::create_admins_table

Desarrollando el esquema

Si no estás familiarizado con el generador de esquemas, te recomiendo que eches un vistazo a la documentación. Vamos a incluir algunas columnas:

  • id - Esto se incrementará automáticamente y se convertirá en nuestra clave principal
  • name
  • username
  • password
  • email
  • role - no aprovecharemos esto hoy, pero te permitirá ampliar el paquete más adelante

También incluiremos las marcas de tiempo predeterminadas para seguir las mejores prácticas.

1
/**

2
 * Make changes to the database.

3
 *

4
 * @return void

5
 */
6
public function up()
7
{
8
    Schema::create('admins', function($table)
9
    {
10
        $table->increments('id');
11
        $table->string('name', 200);
12
        $table->string('username', 32)->unique();
13
        $table->string('password', 64);
14
        $table->string('email', 320)->unique();
15
        $table->string('role', 32);
16
        $table->timestamps();
17
    });
18
}
19
20
/**

21
 * Revert the changes to the database.

22
 *

23
 * @return void

24
 */
25
public function down()
26
{
27
    Schema::drop('admins');
28
}

Ahora que tenemos nuestra estructura de base de datos en su lugar, necesitamos crear un modelo asociado para la tabla. Este proceso es esencialmente idéntico a cómo podríamos lograr esto en nuestra aplicación principal. Creamos el archivo y el modelo, basados en la forma singular de nuestro nombre de tabla, pero necesitamos asegurarnos de que los espacios de nombres sean correctos.

1
namespace Admin\Models;
2
use \Laravel\Database\Eloquent\Model as Eloquent;
3
4
class Admin extends Eloquent {
5
}

Anteriormente, nos hemos asegurado de que estemos usando el espacio de nombres que definimos en start.php. Además, para que podamos hacer referencia a Eloquent correctamente, creamos un alias.

Extendiendo Auth

Para mantener nuestro paquete totalmente autónomo, necesitaremos extender la autenticación. Esto nos permitirá definir una tabla para iniciar sesión en nuestro panel de administración y no interferir con la aplicación principal.

Antes de crear nuestro controlador personalizado, crearemos un archivo de configuración, donde puedes elegir si deseas usar el nombre de usuario o la columna de correo electrónico de la tabla de la base de datos.

1
return array(
2
    'username' => 'username',
3
    'password' => 'password',
4
);

Si deseas modificar las columnas que usaremos, simplemente ajusta los valores aquí.

A continuación necesitamos crear el controlador. Llamémoslo "AdminAuth" e incluyámoslo en nuestra carpeta de bibliotecas. Ya que estamos extendiendo Auth, solo necesitamos sobrescribir un par de métodos para que todo funcione, como pretendíamos.

1
namespace Admin\Libraries;
2
use Admin\Models\Admin as Admin, Laravel\Auth\Drivers\Eloquent as Eloquent, Laravel\Hash, Laravel\Config;
3
4
class AdminAuth extends Eloquent {
5
6
/**

7
 * Get the current user of the application.

8
 *

9
 * If the user is a guest, null should be returned.

10
 *

11
 * @param  int|object  $token

12
 * @return mixed|null

13
 */
14
public function retrieve($token)
15
{
16
    // We return an object here either if the passed token is an integer (ID)

17
    // or if we are passed a model object of the correct type

18
    if (filter_var($token, FILTER_VALIDATE_INT) !== false)
19
    {
20
        return $this->model()->find($token);
21
    }
22
    else if (get_class($token) == new Admin)
23
    {
24
        return $token;
25
    }
26
}
27
28
/**

29
 * Attempt to log a user into the application.

30
 *

31
 * @param  array $arguments

32
 * @return void

33
 */
34
public function attempt($arguments = array())
35
{
36
    $user = $this->model()->where(function($query) use($arguments)
37
    {
38
        $username = Config::get('admin::auth.username');
39
40
        $query->where($username, '=', $arguments['username']);
41
42
        foreach(array_except($arguments, array('username', 'password', 'remember')) as $column => $val)
43
        {
44
            $query->where($column, '=', $val);
45
        }
46
    })->first();
47
48
    // If the credentials match what is in the database, we will just

49
    // log the user into the application and remember them if asked.

50
    $password = $arguments['password'];
51
52
    $password_field = Config::get('admin::auth.password', 'password');
53
54
    if ( ! is_null($user) and Hash::check($password, $user->{$password_field}))
55
    {
56
        return $this->login($user->get_key(), array_get($arguments, 'remember'));
57
    }
58
59
    return false;
60
}
61
62
protected function model(){
63
    return new Admin;
64
}
65
66
}

Ahora que hemos creado el controlador, debemos avisarle a Laravel. Podemos usar el método extend de Auth para hacer esto en nuestro archivo start.php.

1
Auth::extend('adminauth', function() {
2
    return new Admin\Libraries\AdminAuth;
3
});

Una última cosa que debemos hacer es configurar Auth para usar esto en tiempo de ejecución. Podemos hacer esto en el constructor de nuestro controlador base con lo siguiente.

1
Config::set('auth.driver', 'adminauth');

Rutas y Controladores

Antes de que podamos enrutar a cualquier cosa, necesitamos crear un controlador. Vamos a crear nuestro controlador para el 'Dashboard', que es lo que veremos después de iniciar sesión.

Como queremos que se muestre en la raíz de nuestro paquete (es decir, el identificador que definimos anteriormente), deberemos llamar a este home.php. Laravel usa la palabra clave 'home' para establecer lo que deseas mostrar en la raíz de tu aplicación o paquete.

Amplía tu controlador base y crea una vista index. Por ahora, simplemente devuelve 'Hello World' para que podamos asegurarnos de que todo funcione bien.

1
class Admin_Home_Controller extends Admin_Base_Controller {
2
3
    public function get_index(){
4
        return 'Hello World';
5
    }
6
7
}

Ahora que nuestro controlador está configurado, podemos dirigirlo a él. Crea un route.php dentro de tu paquete, si aún no lo has hecho. Similar a nuestra aplicación principal, cada paquete puede tener su propio archivo de rutas que funciona de manera idéntica.

1
Route::controller(array(
2
    'admin::home',
3
));

Aquí, he registrado el controlador homeController, que Laravel asignará automáticamente a /. Más tarde, agregaremos nuestro controlador de inicio de sesión a la matriz.

Si te diriges a /admin (o lo que sea que haya definido anteriormente) en tu navegador, deberías ver 'Hola Mundo'.


Creación del formulario para iniciar sesión

Sin embargo, vamos a crear el controlador de inicio de sesión, en lugar de extender el controlador base, en lugar de eso, extenderemos el controlador principal de Laravel. La razón detrás de esta decisión se hará evidente en breve.

Debido a que no estamos extendiendo, debemos configurar un par de cosas antes de comenzar, a saber, diseños restful, el controlador de autenticación correcto y nuestros recursos.

1
class Admin_Login_Controller extends Controller {
2
3
    public $restful = true;
4
5
    public function __construct(){
6
7
        parent::__construct();
8
9
        Config::set('auth.driver', 'adminauth');
10
11
        Asset::container('header')->bundle('admin');
12
        Asset::container('header')->add('bootstrap', 'css/bootstrap.min.css');
13
14
    }
15
16
}

También creamos nuestra vista. Vamos a utilizar Blade, el motor de plantillas de Laravel, para acelerar un poco las cosas. Dentro de tu directorio de vistas de paquetes, crea un directorio "login" y un archivo "index.blade.php" dentro de él.

Pondremos una estructura de página HTML estándar y retornaremos los recursos.

1
<!DOCTYPE html>
2
<html lang="en">
3
<head>
4
    <meta charset="utf-8">
5
    <title>Login</title>
6
    {{Asset::container('header')->styles()}}
7
    <!--[if lt IE 9]>

8
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>

9
    <![endif]-->
10
</head>
11
<body>
12
13
</body>
14
</html>

Ahora, asegurémonos de que la vista se está creando en el controlador. Como estamos usando controladores restful, podemos aprovechar el verbo "get" en nuestro método.

1
public function get_index(){
2
    return View::make('admin::login.index');
3
}

¡Increíble! Ahora estamos listos para comenzar a crear nuestro formulario, que podemos crear con la clase Form.

1
{{Form::open()}}
2
3
{{Form::label('username', 'Username')}}
4
{{Form::text('username')}}
5
6
{{Form::label('password', 'Password')}}
7
{{Form::password('password')}}
8
9
{{Form::submit('Login', array('class' => 'btn btn-success'))}}
10
11
{{Form::token()}}
12
{{Form::close()}}
Login FormLogin FormLogin Form

Anteriormente, creamos un formulario que se publicará en sí mismo (exactamente lo que queremos), junto con varios elementos de formulario y etiquetas para acompañarlo. El siguiente paso es procesar el formulario.

A medida que publicamos el formulario y utilizamos controladores tranquilos, solo tenemos que crear el método post_index y usarlo para procesar nuestro inicio de sesión. Si nunca has usado Auth, ve y echa un vistazo a la documentación antes de continuar.

1
public function post_index(){
2
3
    $creds = array(
4
        'username' => Input::get('username'),
5
        'password' => Input::get('password'),
6
    );
7
8
    if (Auth::attempt($creds)) {
9
        return Redirect::to(URL::to_action('admin::home@index'));
10
    } else {
11
        return Redirect::back()->with('error', true);
12
    }
13
14
}

Si las credenciales son correctas, el usuario será redirigido al panel de control. De lo contrario, será redirigido nuevamente con un error que podemos verificar en la vista de inicio de sesión. Como solo se trata de datos de sesión y no de errores de validación, solo necesitamos implementar una comprobación simple.

1
@if(Session::get('error'))
2
    Sorry, your username or password was incorrect.
3
@endif

También necesitaremos cerrar la sesión de los usuarios; así que vamos a crear un método get_logout, y agregar lo siguiente. Esto cerrará la sesión de los usuarios y luego los redirigirá cuando visiten /admin/login/logout.

1
public function get_logout(){
2
    Auth::logout();
3
    return Redirect::to(URL::to_action('admin::home@index'));
4
}

Lo último que debemos hacer es agregar el controlador de inicio de sesión a nuestro archivo de rutas.

1
Route::controller(array(
2
    'admin::home',
3
    'admin::login',
4
));

Filtrando rutas

Para evitar que las personas omitan nuestra pantalla de inicio de sesión, necesitamos filtrar nuestras rutas para determinar si son usuarios autorizados. Podemos crear el filtro en el archivo routes.php, y adjuntarlo a nuestro controlador base, para filtrarlo antes de que se muestre la ruta.

1
Route::filter('auth', function() {
2
    if (Auth::guest()) return Redirect::to(URL::to_action('admin::login'));
3
});

En este punto, todo lo que queda por hacer es llamar a esto en el constructor de nuestro controlador base. Si extendiéramos nuestro controlador de inicio de sesión desde nuestra base, tendríamos un bucle infinito que eventualmente se agotaría.

1
$this->filter('before', 'auth');

Configurando las vistas

Anteriormente, creamos nuestro diseño main.blade.php; Ahora, vamos a hacer algo con eso. Vamos a obtener una página HTML y nuestros recursos (archivos de assets) están siendo introducidos.

1
<!DOCTYPE html>
2
<html lang="en">
3
  <head>
4
    <meta charset="utf-8">
5
    <title>{{$title}}</title>
6
    {{Asset::container('header')->styles()}}
7
    <!--[if lt IE 9]>

8
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>

9
    <![endif]-->
10
  </head>
11
  <body>
12
    <div class="container">
13
        {{$content}}
14
    </div>
15
  {{Asset::container('footer')->scripts()}}
16
  </body>
17
  </html>

Notarás que también he repetido un par de variables: $title y $content. Podremos usar métodos mágicos de nuestro controlador para pasar los datos a estos. También he incluido $content dentro del div con la clase 'container' para el cual Bootstrap proporcionará el estilo.

A continuación, vamos a crear la vista para nuestro panel de control. Como anidaremos esto, solo tenemos que colocar el contenido que queremos poner en nuestro contenedor.

1
<h1>Hello</h1>
2
<p class="lead">This is our dashboard view</p>

Guarda esto como index.blade.php dentro del directorio views/dashboard dentro de tu paquete.

Ahora debemos configurar nuestro controlador para aprovechar el diseño y ver los archivos que acabamos de crear. Dentro del método get_index que creamos anteriormente, agrega lo siguiente.

1
$this->layout->title = 'Dashboard';
2
$this->layout->nest('content', 'admin::dashboard.index');

El título es un método mágico que luego podemos repetir como una variable en nuestro diseño. Al usar Nest, podemos incluir una vista dentro del diseño directamente desde nuestro controlador.


Creando una tarea

Para acelerar las cosas, Laravel nos proporciona una forma fácil de ejecutar código desde la línea de comandos. Estos se llaman "Tareas"; es una buena idea crear una para agregar un nuevo usuario a la base de datos fácilmente.

Simplemente debemos asegurarnos de que el archivo tome el nombre de nuestra tarea y colocarlo en el directorio 'tasks' de nuestro paquete. Voy a llamar a este setup.php, ya que lo usaremos justo después de instalar el paquete.

1
use Laravel\CLI\Command as Command;
2
use Admin\Models\Admin as Admin;
3
4
class Admin_Setup_Task {
5
6
public function run($arguments){
7
8
    if(empty($arguments) || count($arguments) < 5){
9
        die("Error: Please enter first name, last name, username, email address and password\n");
10
    }
11
12
    Command::run(array('bundle:publish', 'admin'));
13
14
    $role = (!isset($arguments[5])) ? 'admin' : $arguments[5];
15
16
    $data = array(
17
        'name' => $arguments[0].' '.$arguments[1],
18
        'username' => $arguments[2],
19
        'email' => $arguments[3],
20
        'password' => Hash::make($arguments[4]),
21
        'role' => $role,
22
    );
23
24
    $user = Admin::create($data);
25
26
    echo ($user) ? 'Admin created successfully!' : 'Error creating admin!';
27
28
}
29
30
}

Laravel pasará por una serie de argumentos; podemos contarlos para asegurarnos de que obtenemos exactamente lo que queremos. Si no, retornaremos un error. También notarás que estamos usando la clase Command para ejecutar bundle:publish. Esto te permitirá ejecutar cualquier tarea de línea de comandos integrada en Laravel dentro de tu aplicación o paquete.

Lo principal que hace esta tarea es agarrar los argumentos que se le transmiten, codificar la contraseña e insertar un nuevo administrador en la tabla Admins. Para ejecutar esto, necesitamos usar lo siguiente en la línea de comandos.

1
php artisan admin::setup firstname lastname username email@address.com password

¿Ahora que?

En este tutorial, creamos un panel de administración que es bastante fácil de ampliar. Por ejemplo, la columna roles que creamos podría permitirte limitar lo que tus clientes pueden ver.

Un paquete puede ser cualquier cosa, desde un panel de administración, como el que construimos hoy, hasta los analizadores Markdown, o incluso todo Zend Framework (no estoy bromeando). Todo lo que cubrimos aquí te pondrá en camino a escribir asombrosos paquetes de Laravel, que pueden publicarse en el directorio de paquetes de Laravel.

Obtén más información sobre la creación de paquetes de Laravel aquí en Tuts+.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.