A lo largo de este tutorial, crearemos una aplicación con un simple formulario de registro, mientras introducimos los principales aspectos de diseños de Phalcon.
Este tutorial cubre la implementación de una aplicación MVC simple, mostrando cuán rápido y fácil se puede hacer con Phalcon. Una vez desarrollado, puede usar esta aplicación y extenderla para satisfacer sus necesidades. El código en este tutorial también se puede usar como campo de juego para aprender otros conceptos e ideas específicas de Phalcon. <iframe width="560" height="315" src="https://www.youtube.com/embed/75W-emM4wNQ" frameborder="0" allowfullscreen mark="crwd-mark"></iframe>
Si sólo quiere empezar, puede saltarse esto y crear automáticamente un proyecto Phalcon con nuestras herramientas de desarrollador.
La mejor manera de usar esta guía es seguirla y tratar de divertirse. You can get the complete code here. If you get stuck or have questions, please visit us on Discord or in our Forum.
Una de las características clave de Phalcon es que está débilmente acoplado. Por eso, puede usar cualquier estructura de directorios que le convenga. In this tutorial we will use a standard directory structure, commonly used in MVC applications.
.
└── tutorial
├── app
│ ├── controllers
│ │ ├── IndexController.php
│ │ └── SignupController.php
│ ├── models
│ │ └── Users.php
│ └── views
└── public
├── css
├── img
├── index.php
└── js
NOTE: Since all the code that Phalcon exposes is encapsulated in the extension (that you have loaded on your web server), you will not see
vendor
directory containing Phalcon code. Todo lo que necesita está en memoria. Si todavía no ha instalado la aplicación, vaya a la página instalación y complete la instalación antes de continuar con este tutorial.
Si todo esto es nuevo, se recomienda que instale también las Phalcon Devtools. Las DevTools aprovechan el servidor web integrado de PHP, lo que le permite ejecutar su aplicación casi inmediatamente. Si elige esta opción, necesitará un fichero .htrouter.php
en la raíz de su proyecto con los siguientes contenidos:
<?php
$uri = urldecode(
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
);
if ($uri !== '/' && file_exists(__DIR__ . '/public' . $uri)) {
return false;
}
$_GET['_url'] = $_SERVER['REQUEST_URI'];
require_once __DIR__ . '/public/index.php';
En el caso de nuestro tutorial, este fichero debe ubicarse en el directorio tutorial
.
También puede usar nginX, apache, cherokee u otros servidores web. Puede consultar la página configuración del servidor web para las instrucciones.
El primer fichero que necesita crear es el fichero de arranque. Este fichero actúa como punto de entrada y configuración de su aplicación. En este fichero, puede implementar la inicialización de componentes, así como definir el comportamiento de la aplicación.
Este fichero gestiona 3 cosas:
We are going to use Phalcon\Loader a PSR-4 compliant file loader. Cosas comunes que se deberían añadir al autocargador son sus controladores y modelos. También puede registrar directorios, que serán escaneados por los ficheros requeridos por la aplicación.
Para empezar, vamos a registrar nuestros directorios de la aplicación controllers
y models
usando Phalcon\Loader:
public/index.php
<?php
use Phalcon\Loader;
define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');
// ...
$loader = new Loader();
$loader->registerDirs(
[
APP_PATH . '/controllers/',
APP_PATH . '/models/',
]
);
$loader->register();
Since Phalcon is loosely coupled, services are registered with the frameworks Dependency Manager so they can be injected automatically to components and services wrapped in the IoC container. Frecuentemente, encontrará el término DI que significa Inyección de Dependencias. Inyección de Dependencias e Inversión de Control (IoC) puede sonar complejo pero Phalcon asegura que su uso sea simple, práctico y eficiente. El contenedor IoC de Phalcon consiste en los siguientes conceptos:
Cada vez que el framework requiere un componente o servicio, lo solicitará al contenedor usando un nombre acordado para el servicio. De esta manera tenemos una forma fácil de recuperar objetos necesarios para nuestra aplicación, como el registrador, conexión a base de datos, etc.
NOTE: If you are still interested in the details please see this article by Martin Fowler. También tenemos un gran tutorial que cubre muchos casos de uso.
The Phalcon\Di\FactoryDefault is a variant of Phalcon\Di. Para hacer las cosas más fáciles, automáticamente registrará la mayoría de los componentes que requiere una aplicación y vienen con Phalcon como estándar. Although it is recommended to set up services manually, you can use the Phalcon\Di\FactoryDefault container initially and later on customize it to fit your needs.
Services can be registered in several ways, but for our tutorial, we will use an anonymous function:
public/index.php
<?php
use Phalcon\Di\FactoryDefault;
// Create a DI
$container = new FactoryDefault();
Now we need to register the view service, setting the directory where the framework will find the view files. Ya que las vistas no corresponden a clases, no se pueden cargar automáticamente por nuestro autocargador.
public/index.php
<?php
use Phalcon\Mvc\View;
// ...
$container->set(
'view',
function () {
$view = new View();
$view->setViewsDir(APP_PATH . '/views/');
return $view;
}
);
Ahora necesitamos registrar una URI base, que ofrecerá la funcionalidad para crear todas las URIs por Phalcon. El componente se asegurará de que tanto si ejecuta su aplicación a través del directorio superior como un subdirectorio, todas las URIs serán correctas. Para este tutorial, nuestra ruta base es /
. Esto será importante más tarde en este tutorial cuando usemos la clase Phalcon\Tag
para generar hiperenlaces.
public/index.php
<?php
use Phalcon\Url;
// ...
$container->set(
'url',
function () {
$url = new Url();
$url->setBaseUri('/');
return $url;
}
);
Para poder gestionar cualquier petición, se usa el objeto Phalcon\Mvc\Application para hacer todo el trabajo pesado por nosotros. El componente aceptará la petición del usuario, detecta las rutas, despacha el controlador y renderiza la vista devolviendo los resultados.
public/index.php
<?php
use Phalcon\Mvc\Application;
// ...
$application = new Application($container);
$response = $application->handle(
$_SERVER["REQUEST_URI"]
);
$response->send();
El fichero tutorial/public/index.php
debería verse como:
public/index.php
<?php
use Phalcon\Di\FactoryDefault;
use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Application;
use Phalcon\Url;
// Define some absolute path constants to aid in locating resources
define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');
// Register an autoloader
$loader = new Loader();
$loader->registerDirs(
[
APP_PATH . '/controllers/',
APP_PATH . '/models/',
]
);
$loader->register();
$container = new FactoryDefault();
$container->set(
'view',
function () {
$view = new View();
$view->setViewsDir(APP_PATH . '/views/');
return $view;
}
);
$container->set(
'url',
function () {
$url = new Url();
$url->setBaseUri('/');
return $url;
}
);
$application = new Application($container);
try {
// Handle the request
$response = $application->handle(
$_SERVER["REQUEST_URI"]
);
$response->send();
} catch (\Exception $e) {
echo 'Exception: ', $e->getMessage();
}
Como puede ver, el fichero de arranque es muy corto y no necesitamos incluir ningún fichero adicional. Estás de camino a crear una aplicación MVC flexible en menos de 30 líneas de código.
Por defecto, Phalcon buscará un controlador llamado IndexController
. It is the starting point when no controller or action has been added in the request (eg. https://localhost/
). Un IndexController
y su IndexAction
deberían parecerse al siguiente ejemplo:
app/controllers/IndexController.php
<?php
use Phalcon\Mvc\Controller;
class IndexController extends Controller
{
public function indexAction()
{
return '<h1>Hello!</h1>';
}
}
Las clases controlador deben tener el sufijo Controller
y las acciones del controlador deben tener el sufijo Action
. Para más información puede leer nuestro documento sobre controladores. Si accede a la aplicación desde su navegador, debería ver algo similar a:
Congratulations, you are Phlying with Phalcon!
A veces es necesario enviar la salida por pantalla desde el controlador, pero no deseable como confirmarán la mayoría de puristas de la comunidad MVC. Todo debe pasarse a la vista, que es responsable de la salida de datos en pantalla. Phalcon buscará una vista con el mismo nombre que la última acción ejecutada dentro de un directorio llamado como el último controlador ejecutado.
Por lo tanto, en nuestro caso la URL es:
http://localhost/
invocará IndexController
y indexAction
, y buscará la vista:
/views/index/index.phtml
Si la encuentra, la analizará y enviará la salida a la pantalla. Nuestra vista tendrá entonces el siguiente contenido:
app/views/index/index.phtml
<?php echo "<h1>Hello!</h1>";
y ya que movimos el echo
de nuestra acción del controlador a la vista, estará vacía ahora:
app/controllers/IndexController.php
<?php
use Phalcon\Mvc\Controller;
class IndexController extends Controller
{
public function indexAction()
{
}
}
La salida del navegador seguirá siendo la misma. El componente Phalcon\Mvc\View
se crea automáticamente cuando la ejecución de la acción ha finalizado. Puede leer más sobre vistas en Phalcon aquí.
Now we will change the index.phtml
view file, to add a link to a new controller named signup. El objeto es permitir a los usuarios registrarse en nuestra aplicación.
app/views/index/index.phtml
<?php
echo "<h1>Hello!</h1>";
echo PHP_EOL;
echo PHP_EOL;
echo $this->tag->linkTo(
'signup',
'Sign Up Here!'
);
El código HTML generado muestra un etiqueta HTML ancla (<a>
) enlazando a un nuevo controlador:
app/views/index/index.phtml
(renderizado)
<h1>Hello!</h1>
<a href="/signup">Sign Up Here!</a>
Para generar el enlace para la etiqueta <a>
, usamos el componente Phalcon\Tag. Es una clase de utilidad que ofrece una forma fácil de construir etiquetas HTML con las convenciones del framework en mente. Esta clase también es un servicio registrado en el Inyector de Dependencias por lo que podemos usar $this->tag
para acceder a su funcionalidad.
NOTE:
Phalcon\Tag
is already registered in the DI container since we have used thePhalcon\Di\FactoryDefault
container. Si registra todos los registros por su cuenta, necesitará registrar este componente en su contenedor para que esté disponible en su aplicación.
El componente Phalcon\Tag también usa el componente Phalcon\Uri previamente registrado para generar correctamente URIs. Un artículo más detallado sobre generación de HTML se puede encontrar aquí.
Y el controlador Signup es (app/controllers/SignupController.php
):
app/controllers/SignupController.php
<?php
use Phalcon\Mvc\Controller;
class SignupController extends Controller
{
public function indexAction()
{
}
}
La acción index vacía da el paso limpio a una vista con la definición del formulario (app/views/signup/index.phtml
):
app/views/signup/index.phtml
<h2>Sign up using this form</h2>
<?php echo $this->tag->form("signup/register"); ?>
<p>
<label for="name">Name</label>
<?php echo $this->tag->textField("name"); ?>
</p>
<p>
<label for="email">E-Mail</label>
<?php echo $this->tag->textField("email"); ?>
</p>
<p>
<?php echo $this->tag->submitButton("Register"); ?>
</p>
</form>
Viendo el formulario en su navegador mostrará lo siguiente:
Como se ha mencionado antes, la clase de utilidad Phalcon\Tag, expone métodos útiles que le permiten construir elementos HTML de formulario con facilidad. El método Phalcon\Tag::form()
recibe sólo un parámetro por instancia, una URI relativa al controlador/acción en la aplicación. Phalcon\Tag::textField()
crea un elemento HTML de texto con el nombre como parámetro pasado, mientras que Phalcon\Tag::submitButton()
crea un botón de envío HTML.
By clicking the Register button, you will notice an exception thrown from the framework, indicating that we are missing the register
action in the controller signup
. Nuestro fichero public/index.php
lanza esta excepción:
Exception: Action "register" was not found on handler "signup"
Implementar ese método eliminará la excepción:
app/controllers/SignupController.php
<?php
use Phalcon\Mvc\Controller;
class SignupController extends Controller
{
public function indexAction()
{
}
public function registerAction()
{
}
}
If you click the Register button again, you will see a blank page. Vamos a añadir una vista un poco más tarde que proporciona retroalimentación útil. Pero primero, deberíamos trabajar en el código para almacenar la entrada del usuario en una base de datos.
Según las directrices MVC, las interacciones de base de datos se deben hacer a través de modelos para asegurar un código limpio y orientado a objetos.
Phalcon ofrece el primer ORM para PHP escrito completamente en lenguaje C. En vez de incrementar la complejidad de desarrollo, la simplifica.
Antes de crear nuestro primer modelo, necesitamos crear una tabla de base de datos usando una herramienta de acceso a base de datos o la utilidad de línea de comandos de la base de datos. Para este tutorial usamos MySQL como nuestra base de datos, una única tabla para almacenar usuarios registrados se puede crear como sigue:
create_users_table.sql
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(70) NOT NULL,
`email` varchar(70) NOT NULL,
PRIMARY KEY (`id`)
);
Un modelo debería ubicarse en el directorio app/models
(app/models/Users.php
). The model maps to the users table:
app/models/Users.php
<?php
use Phalcon\Mvc\Model;
class Users extends Model
{
public $id;
public $name;
public $email;
}
NOTE: Note that the public properties of the model correspond to the names of the fields in our table.
Para usar una conexión de base de datos y posteriormente acceder a los datos a través de nuestros modelos, necesitamos especificarlo en nuestro proceso de arranque. Una conexión de base de datos sólo es otro servicio que nuestra aplicación tiene, que se puede usar a lo largo de nuestra aplicación:
public/index.php
<?php
use Phalcon\Db\Adapter\Pdo\Mysql;
$container->set(
'db',
function () {
return new Mysql(
[
'host' => '127.0.0.1',
'username' => 'root',
'password' => 'secret',
'dbname' => 'tutorial',
]
);
}
);
Ajuste el fragmento de código anterior apropiadamente para su base de datos.
Con los parámetros de base de datos correctos, nuestro modelo está listo para interactuar con el resto de la aplicación, con lo que podemos guardar la entrada del usuario. First, let’s take a moment and create a view for SignupController::registerAction()
that will display a message letting the user know the outcome of the save operation.
app/views/signup/register.phtml
<div class="alert alert-<?php echo $success === true ? 'success' : 'danger'; ?>">
<?php echo $message; ?>
</div>
<?php echo $this->tag->linkTo(['/', 'Go back', 'class' => 'btn btn-primary']); ?>
Tenga en cuenta que hemos añadido algunos estilos css en el código anterior. Cubriremos incluyendo la hoja de estilos en la sección Estilo a continuación.
app/controllers/SignupController.php
<?php
use Phalcon\Mvc\Controller;
class SignupController extends Controller
{
public function indexAction()
{
}
public function registerAction()
{
$user = new Users();
//assign value from the form to $user
$user->assign(
$this->request->getPost(),
[
'name',
'email'
]
);
// Store and check for errors
$success = $user->save();
// passing the result to the view
$this->view->success = $success;
if ($success) {
$message = "Thanks for registering!";
} else {
$message = "Sorry, the following problems were generated:<br>"
. implode('<br>', $user->getMessages());
}
// passing a message to the view
$this->view->message = $message;
}
}
Al principio de registerAction
creamos un objeto usuario vacío, usando la clase Users
que creamos anteriormente. Usaremos esta clase para gestionar el registro de un usuario. Como hemos mencionado antes, las propiedades públicas de la clase mapean a los campos de la tabla users
de nuestra base de datos. Establecer los valores relevantes en el registro nuevo y llamar a save()
almacenará los datos en la base de datos para ese registro. El método save()
devuelve un valor booleano
que indica si el guardado ha ido bien o no.
El ORM escapará automáticamente la entrada evitando inyecciones SQL, por lo que sólo necesitamos pasar la petición al método save()
.
Hay validaciones adicionales que ocurren automáticamente sobre los campos que están definidos como no nulos (requeridos). Si no hemos introducido alguno de los campos requeridos en el formulario de registro nuestra pantalla se parecerá a esta:
Ahora necesitaremos obtener y mostrar todos los usuarios registrados en nuestra base de datos
Lo primero que vamos a hacer en nuestro indexAction
de IndexController
es mostrar el resultado de la búsqueda de todos los usuarios, que se hace básicamente llamando al método estático find()
de nuestro modelo (Users::find()
).
indexAction
cambiaría como sigue:
app/controllers/IndexController.php
<?php
use Phalcon\Mvc\Controller;
class IndexController extends Controller
{
/**
* Welcome and user list
*/
public function indexAction()
{
$this->view->users = Users::find();
}
}
NOTE: We assign the results of the
find
to a magic property on theview
object. This sets this variable with the assigned data and makes it available in our view
En nuestro fichero de vista views/index/index.phtml
podemos usar la variable $users
como sigue:
La vista se parecerá a esto:
views/index/index.phtml
<?php
echo "<h1>Hello!</h1>";
echo $this->tag->linkTo(["signup", "Sign Up Here!", 'class' => 'btn btn-primary']);
if ($users->count() > 0) {
?>
<table class="table table-bordered table-hover">
<thead class="thead-light">
<tr>
<th>#</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3">Users quantity: <?php echo $users->count(); ?></td>
</tr>
</tfoot>
<tbody>
<?php foreach ($users as $user) { ?>
<tr>
<td><?php echo $user->id; ?></td>
<td><?php echo $user->name; ?></td>
<td><?php echo $user->email; ?></td>
</tr>
<?php } ?>
</tbody>
</table>
<?php
}
Como puede ver, nuestra variable $users
se puede iterar y contar. Puede obtener más información de cómo operar con modelos en nuestro documento sobre modelos.
Ahora podemos añadir un pequeño toque de diseño a nuestra aplicación. We can add the Bootstrap CSS in our code so that it is used throughout our views. Añadiremos un fichero index.phtml
en la carpeta views
, con el siguiente contenido:
app/views/index.phtml
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Phalcon Tutorial</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<?php echo $this->getContent(); ?>
</div>
</body>
</html>
En la plantilla anterior, la línea más importante es la llamada al método getContent()
. Este método devuelve todo el contenido que se ha generado desde nuestra vista. Nuestra aplicación ahora mostrará:
Como puede ver, es fácil empezar a construir una aplicación usando Phalcon. Dado que Phalcon es una extensión cargada en memoria, la huella de su proyecto será mínima, mientras que al mismo tiempo disfrutará de un buen aumento del rendimiento.
Si está listo para aprender más, consulte el Tutorial Vökuró siguiente.