Usar MongoDB con PHP

En esta parte del tutorial de Bookshelf para PHP, se muestra cómo crear, leer, actualizar y eliminar datos estructurados en una base de datos de MongoDB.

Esta página forma parte de un tutorial de varias páginas. Para empezar en orden y consultar las instrucciones de configuración, ve a la sección relativa a la aplicación Bookshelf para PHP.

Ejecutar MongoDB en Google Compute Engine

Si no has configurado una instancia de Mongo, puedes crear una administrada que se ejecute sobre Google Cloud Platform con mLab. Si prefieres usar una instancia de MongoDB no administrada que se ejecute en Compute Engine, consulta la solución preconfigurada de clic para desplegar de Bitnami.

Para obtener el mejor resultado, asegúrate de que la instancia de MongoDB esté alojada en Google Cloud Platform y ubicada en la misma región que la aplicación.

MongoDB usa el puerto 27017 para la comunicación de forma predeterminada. Después de configurar la instancia de MongoDB, es posible que necesites establecer las reglas de cortafuegos para permitir el tráfico que entra y sale de este puerto. En el caso de las instancias que se ejecutan en Google Cloud Platform, consulta la sección sobre cómo usar las reglas de cortafuegos para obtener instrucciones.

Instalar y habilitar MongoDB para PHP

Si quieres conectarte a MongoDB mientras esta aplicación se ejecuta localmente, sigue las instrucciones para instalar la extensión de MongoDB para PHP. Los usuarios de Linux deben instalarla con PECL.

Una vez hecho esto, debes habilitar la extensión en php.ini:

Linux/macOS X

echo "extension=mongodb.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`

Windows

Añade la siguiente línea al archivo php.ini:

extension=php_mongodb.dll

Ahora que la extensión se ha instalado, también debes añadir la biblioteca de MongoDB al compositor:

composer require "mongodb/mongodb:^1.0.0"

Establecer configuración

  1. Ve al directorio getting-started-php/2-structured-data y copia el archivo settings.yml.dist:

    cp config/settings.yml.dist config/settings.yml
    
  2. Abre config/settings.yml para editarlo.

  3. Sustituye YOUR_PROJECT_ID por el ID del proyecto.

  4. Define el valor de bookshelf_backend como mongodb.

  5. En mongo_url, mongo_database y mongo_collection, establece los valores apropiados para tu instancia de MongoDB. Por ejemplo:

    mongo_url: mongodb://104.197.3.232:27017
    mongo_database: getting_started_php
    mongo_collection: books
    
  6. Guarda y cierra settings.yml.

Instalar dependencias

Introduce el siguiente comando en el directorio 2-structured-data:

composer install

Ejecutar la aplicación en la máquina local

  1. Inicia un servidor web local:

    php -S localhost:8000 -t web
    
  2. Introduce la siguiente dirección en el navegador web:

    http://localhost:8000

Ahora puedes navegar por las páginas web de la aplicación y añadir, editar y eliminar libros.

Desplegar la aplicación en el entorno flexible de App Engine

  1. Despliega la aplicación de muestra:

    gcloud app deploy
    
  2. Introduce la siguiente dirección en el navegador web. Sustituye [YOUR_PROJECT_ID] por el ID del proyecto:

    https://[YOUR_PROJECT_ID].appspot.com
    

    Si actualizas la aplicación, podrás desplegar la versión actualizada con el mismo comando que utilizaste para desplegar la aplicación por primera vez. El nuevo despliegue crea una nueva versión de la aplicación y la establece como la versión predeterminada. No obstante, se conservarán las versiones anteriores, al igual que las instancias de máquina virtual asociadas. Ten en cuenta que todas estas versiones de la aplicación y las instancias de máquina virtual son recursos facturables.

    Si eliminas las versiones no predeterminadas de la aplicación, puedes reducir los costes.

    Para eliminar una versión de la aplicación, sigue las instrucciones que figuran a continuación:

    1. In the GCP Console, go to the Versions page for App Engine.

      Go to the Versions page

    2. Select the checkbox for the non-default app version you want to delete.
    3. Click Delete to delete the app version.

    Consulta la sección sobre cómo eliminar los recursos facturables en el último paso de este tutorial para obtener más información al respecto.

    Estructura de la aplicación

    En el siguiente diagrama, se puede ver cómo están interconectados los componentes de la aplicación de muestra.

    Proceso de despliegue y estructura de la aplicación Bookshelf

    Información sobre el código

    Anteriormente, editaste settings.yml y estableciste el valor de bookshelf_backend como mongodb. Esto indica a la aplicación que cargue la clase MongoDb, que se define en src/DataModel/MongoDb.php. La clase MongoDb encapsula la API de MongoDB y es responsable de almacenar los libros en la base de datos de MongoDB.

    Este código de controllers.php define y registra un controlador para la ruta GET '/books'. La variable $model es una instancia de la clase MongoDb. El método $model->listBooks devuelve una matriz que contiene un conjunto de libros y un cursor. Luego, el motor de plantillas Twig procesa la lista de libros de acuerdo con la plantilla list.html.twig.

    $app->get('/books/', function (Request $request) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        /** @var Twig_Environment $twig */
        $twig = $app['twig'];
        $token = $request->query->get('page_token');
        $bookList = $model->listBooks($app['bookshelf.page_size'], $token);
    
        return $twig->render('list.html.twig', array(
            'books' => $bookList['books'],
            'next_page_token' => $bookList['cursor'],
        ));
    });

    Esta es la plantilla Twig que se usa para mostrar los libros recuperados de la base de datos de Cloud SQL. La plantilla recibe una variable de matriz llamada books. Por cada libro de la matriz, se muestra el título y el autor. La plantilla también recibe una variable next_page_token que determina si se debe mostrar el botón Más.

    {% for book in books %}
    <div class="media">
      <a href="/books/{{book.id}}">
        <div class="media-left">
          <img src="http://placekitten.com/g/128/192">
        </div>
        <div class="media-body">
          <h4>{{book.title}}</h4>
          <p>{{book.author}}</p>
        </div>
      </a>
    </div>
    {% else %}
    <p>No books found</p>
    {% endfor %}

    Este código define y registra un controlador para la ruta GET '/books/{id}', donde {id} es el ID de un libro individual. El controlador llama al método $model->read para obtener el libro especificado de Cloud SQL. El motor de plantillas Twig procesa el libro de acuerdo con la plantilla view.html.twig.

    $app->get('/books/{id}', function ($id) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        $book = $model->read($id);
        if (!$book) {
            return new Response('', Response::HTTP_NOT_FOUND);
        }
        /** @var Twig_Environment $twig */
        $twig = $app['twig'];
    
        return $twig->render('view.html.twig', array('book' => $book));
    });

    La plantilla view.html.twig recibe una variable llamada book y muestra el título, la fecha de publicación, el autor y la descripción del libro.

    <div class="media">
      <div class="media-body">
        <h4 class="book-title">
          {{book.title}}
          <small>{{book.published_date}}</small>
        </h4>
        <h5 class="book-author">By {{book.author|default('Unknown', True)}}</h5>
        <p class="book-description">{{book.description}}</p>
      </div>
    </div>

    Cuando el usuario hace clic en Add book (Añadir libro), el controlador de GET /books/add muestra un formulario para introducir el título, el autor y otra información de un libro. Cuando hace clic en Save (Guardar), el controlador de POST /books/add obtiene el nuevo libro de la petición y llama a $model->create para almacenarlo en Cloud SQL.

    $app->get('/books/add', function () use ($app) {
        /** @var Twig_Environment $twig */
        $twig = $app['twig'];
    
        return $twig->render('form.html.twig', array(
            'action' => 'Add',
            'book' => array(),
        ));
    });
    
    $app->post('/books/add', function (Request $request) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        $book = $request->request->all();
        $id = $model->create($book);
    
        return $app->redirect("/books/$id");
    });

    Esta es la plantilla para el formulario de introducción de libros:

    {% extends "base.html.twig" %}
    
    {% block content %}
    <h3>{{action}} book</h3>
    
    <form method="POST" enctype="multipart/form-data">
    
      <div class="form-group">
        <label for="title">Title</label>
        <input type="text" name="title" id="title" value="{{book.title}}" class="form-control"/>
      </div>
    
      <div class="form-group">
        <label for="author">Author</label>
        <input type="text" name="author" id="author" value="{{book.author}}" class="form-control"/>
      </div>
    
      <div class="form-group">
        <label for="published_date">Date Published</label>
        <input type="text" name="published_date" id="published_date" value="{{book.published_date}}" class="form-control"/>
      </div>
    
      <div class="form-group">
        <label for="description">Description</label>
        <textarea name="description" id="description" class="form-control">{{book.description}}</textarea>
      </div>
    
      <button id="submit" type="submit" class="btn btn-success">Save</button>
    </form>
    
    {% endblock %}

    El código de muestra incluye más controladores para editar y eliminar libros concretos:

    $app->get('/books/{id}/edit', function ($id) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        $book = $model->read($id);
        if (!$book) {
            return new Response('', Response::HTTP_NOT_FOUND);
        }
        /** @var Twig_Environment $twig */
        $twig = $app['twig'];
    
        return $twig->render('form.html.twig', array(
            'action' => 'Edit',
            'book' => $book,
        ));
    });
    
    $app->post('/books/{id}/edit', function (Request $request, $id) use ($app) {
        $book = $request->request->all();
        $book['id'] = $id;
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        if (!$model->read($id)) {
            return new Response('', Response::HTTP_NOT_FOUND);
        }
        if ($model->update($book)) {
            return $app->redirect("/books/$id");
        }
    
        return new Response('Could not update book');
    });
    $app->post('/books/{id}/delete', function ($id) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        $book = $model->read($id);
        if ($book) {
            $model->delete($id);
    
            return $app->redirect('/books/', Response::HTTP_SEE_OTHER);
        }
    
        return new Response('', Response::HTTP_NOT_FOUND);
    });
¿Te ha resultado útil esta página? Enviar comentarios: