Relaciones ActiveRecord en Yii: Conectar Libros y Autores

Clase 14 de 35Curso de Desarrollo Web con PHP y Yii2

Contenido del curso

Modelos, vistas y controladores

Enlaces, navegación y tablas intermedias

Resumen

Conectar modelos de base de datos sin escribir joins manuales es una de las ventajas más poderosas de trabajar con Active Record en Yii. A través de funciones como hasOne y hasMany, puedes establecer relaciones entre tablas de forma declarativa, limpia y con muy pocas líneas de código.

¿Cómo se relacionan los modelos Book y Author en Active Record?

En este ejemplo práctico se trabaja con dos modelos: Book (libro) y Author (autor). En la tabla de book existe una columna llamada author_id, que conecta cada libro con su autor correspondiente. Esa columna es la clave foránea que permite establecer la relación inversa: un autor tiene muchos libros (hasMany), y un libro tiene un autor (hasOne) [01:00].

Normalmente, en una base de datos relacional tendrías que escribir un SELECT con un INNER JOIN o un LEFT JOIN para cruzar ambas tablas. Sin embargo, el framework Yii simplifica todo esto con dos funciones del Active Record: hasOne y hasMany [01:23].

¿Cómo implementar hasOne para obtener el autor de un libro?

Dentro del modelo Book, se crea una función pública llamada getAuthor. Su contenido es sorprendentemente breve [01:45]:

php public function getAuthor() { return $this->hasOne(Author::class, ['author_id' => 'author_id'])->one(); }

Esta función recibe tres elementos clave:

  • La clase relacionada: Author::class, que se instancia dinámicamente a partir del string de la clase.
  • El primer valor del arreglo: corresponde al author_id de la tabla author, es decir, su llave primaria.
  • El segundo valor del arreglo: corresponde al author_id de la tabla book, la clave foránea que establece el vínculo.

Al final se encadena el método ->one() para indicar que de todos los posibles resultados, solo se necesita un registro [02:18].

¿Qué significa cada parámetro de hasOne?

El primer elemento del arreglo asociativo ('author_id') representa la columna de la tabla destino (author). El segundo ('author_id') es la columna de la tabla origen (book). Cuando ambas columnas comparten el mismo nombre, puede parecer confuso, pero la lógica es clara: "el ID del autor en su propia tabla debe coincidir con el ID del autor almacenado en la tabla del libro".

¿Cómo se consume la relación desde una acción del controlador?

Se crea una acción llamada actionBook que recibe un bookId como parámetro [03:05]:

php public function actionBook($bookId) { $book = Book::findOne($bookId); if (empty($book)) { print("No existe el libro"); return ExitCode::DATAERR; } printf("%s - %s", $book, $book->getAuthor()->name); return ExitCode::OK; }

El flujo es directo:

  • Se busca el libro por su ID con findOne.
  • Si no existe, se imprime un mensaje de error y se retorna un código de error.
  • Si existe, se imprime el resultado del método toString del libro junto con el nombre del autor.

¿Por qué funciona pedir el name del autor sin definirlo explícitamente?

Aquí está la verdadera magia del Active Record. La propiedad name no está declarada como atributo en el modelo Author. Sin embargo, Yii mapea automáticamente las columnas de la tabla de base de datos como propiedades del objeto [05:05]. Cuando ejecutas $book->getAuthor()->name, el framework realiza internamente la consulta necesaria y te devuelve el valor de la columna name de la tabla author.

Al ejecutar el comando en consola con el ID del libro 1, el resultado es inmediato: "El libro del desasosiego - Fernando Pessoa" (nombre y libro provenientes de tablas diferentes) [05:30].

La potencia de este enfoque radica en que no fue necesario escribir ningún SELECT con JOIN. Basta con declarar la relación una vez en el modelo y el Active Record se encarga del resto. Esto reduce errores, mejora la legibilidad del código y acelera el desarrollo.

¿Has utilizado relaciones hasOne o hasMany en tus proyectos? Comparte tu experiencia en los comentarios.