Создание простого блога на MongoDB и PHP

Введение

Если вы хотите создать блог с использованием MongoDB и PHP, то эта статья поможет вам понять, как:

  • Соединяться с базой данных MongoDB;
  • Сохранять документы в коллекцию;
  • Запрашивать документы из коллекции;
  • Выполнять запросы ранжирования;
  • Сортировать и обновлять документы, а также удалять один или более документов из коллекции.

Причина, по которой я выбрал именно блог, заключается в том, что это простейшее CRUD-приложение, позволяющее освоить основы веб-разработки с использованием связки PHP и MongoDB.

Мы создадим простой пользовательский интерфейс с помощью Bootstrap, используя текстовые поля и кнопки. Все данные будут храниться в базе MongoDB.

Вы можете скачать полные исходники, увидеть демо фронтэнда и бэкэнда (имя пользователя и пароль будут duythien).

Что такое MongoDB?

Согласно официальному сайту MongoDB это документо-ориентированная СУБД без SQL, которой свойственна высокая производительность, доступность и легкая масштабируемость. Список остальных СУБД подобного типа вы можете увидеть здесь.

Концепция MongoDB: базы данных, коллекции и документы

  • База данных. MongoDB объединяет информацию в базы данных так же, как это делают реляционные БД. Если вы знакомы с реляционными базами данных, то думайте о документо-ориентированных БД так же. В реляционных СУБД (RDBMS) база данных состоит из таблиц, хранимых процедур, представлений и так далее. В MongoDB база данных состоит из коллекций. База данных MongoDB может включать в себя одну или более коллекций. Например, база данных для блога под именем blog может включать в себя следующие коллекции: статьи, авторы, комментарии, категории и тому подобное;
  • Коллекция эквивалентна таблице в реляционной СУБД. Коллекция создается внутри базы данных. Документы внутри коллекции могут иметь различные поля. Как правило, все документы в коллекции имеют похожее назначение;
  • Документ это запись в коллекции MongoDB и базовый элемент данных в MongoDB. Документы аналогичны объектам JSON, но имеют расширенный формат, известный как BSON. Документ включает в себя набор полей или пар ключ-значение. Думайте о документе, как о многомерном массиве. В массиве у вас есть набор ключей, привязанных к значениям (документ == массив). Смотрите документацию.

Установка MongoDB

MongoDB запускается на большинстве платформ и поддерживает 32- и 64-битную архитектуру. MongoDB доступна, как в исходных кодах, так и виде установочного пакета. В условиях разработки используются исходники MongoDB в 64-битном формате.

В этой части статьи будет рассказано как установить БД на Ubuntu Linux и Windows. Для остальных операционных систем смотрите документацию.

Рассмотрим сначала установку MongoDB на Ubuntu Linux. Откройте терминал и выполните следующие команды:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
#
echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list

Далее следует команда для обновления репозитория и установки крайней стабильной версии MongoDB:

sudo apt-get update
sudo apt-get install mongodb-10gen

После этого установка MongoDB завершена. Теперь перезапустите сервис MongoDB через командную строку так, как показано ниже:

sudo service mongodb start
sudo service mongodb stop

Если при запуске произошла ошибка, то попробуйте выполнить следующую команду:

sudo mongod --fork --logpath /var/log/mongodb/mongodb.log
#or
sudo mongod -f /etc/mongodb.conf

Теперь опишем установку MongoDB на Windows:

Перейдите на страницу загрузок на официальном сайте MongoDB и скачайте крайнюю стабильную версию для Windows.

После окончания загрузки, извлеките и поместите содержимое архива на диск C:. MongoDB требует наличия папки данных, в которой должны содержаться все файлы.

Стандартное расположение для MongoDB это папка данных, находящаяся по адресу C:datadb. Если её не существует, то создайте.

Для запуска MongoDB, наберите в командной строке:

C:> cd mongodbbin
C:mongodbbin> mongod

Итак, MongoDB установлена! Теперь перезапустите сервис MongoDB:

net start MongoDB
net stop  MongoDB

Установка драйвера PHP для MongoDB

Сервер MongoDB уже настроен на работу с текущим веб-сервером, но не поддерживает PHP. Чтобы «рассказать» серверу MongoDB о PHP, нам нужно установить драйвер PHP-MongoDB. Это библиотека для PHP.

Если вы используете Linux, то инсталляция гениально проста:

sudo pecl install mongo

Добавьте строку extension=mongo.so в файл конфигурации php.ini, а затем запустите:

sudo –i
echo 'extension=mongo.so' >> /etc/php5/apache2/php.ini

Перезапустите веб-сервер и выполните:

php -i |grep "mongo"
php --re mongo

Установка драйвера для Windows

Установим драйвер на Windows-машину с PHP 5.4 и сервером Apache (XAMPP):

  • Скачайте ZIP-архив и извлеките его содержимое;
  • Скопируйте файл php_mongo.dll из извлеченных данных в директорию с расширениями PHP (C:xamppphpext);
  • Откройте файл php.ini внутри папки с PHP и добавьте в него следующую строку: extension=php_mongo.dll;
  • Сохраните файл и закройте его. Перезапустите XAMP;
  • Откройте текстовый редактор и добавьте следующий код в новый файл: <?php phpinfo();?>, сохраните файл под именем phpinfo.php внутри DocumentRoot сервера Apache (речь идет о папке htdocs) и откройте данный скрипт в браузере. Если увидите среди выведенной информации mongo, значит установка прошла успешно.

Веб-разработка с Mongo и PHP

Соединение с сервером баз данных MongoDB

Подключение к MongoDB из PHP очень похоже на подключение к любой другой базе данных. Хостом по умолчанию является localhost, а портом - 27017:

$connection = new Mongo();

Подключение к удаленному хосту с определенным логином и портом выполняется так:

$connecting_string =  sprintf('mongodb://%s:%d/%s', $hosts, $port,$database), $connection=  new Mongo($connecting_string,array('username'=>$username,'password'=>$password));

Выбор базы данных

Как только связь с базой данных установлена, мы получаем доступ к базе данных. Сделать это можно так:

$dbname = $connection->selectDB('dbname');

Основы (CRUD-операции)

MongoDB предоставляет хорошие возможности для чтения и манипуляции данными. CRUD расшифровывается как: create - создание, read - чтение, update - обновление и delete - удаление. Эти термины являются основой для взаимодействий с базой данных.

Создание/выбор коллекции

Создание и выбор коллекции очень похож на получение доступа и создание базы данных. Если коллекция не создана, то сделать это можно так:

$collection = $dbname->collection;
//or
$collection = $dbname->selectCollection('collection');

Например, следующая команда создаст коллекцию «posts» в моем блоге:

$posts = $dbname->posts

Создание документа

Создать документ в MongoDB очень просто. Создается массив. Переводится в метод insert для объекта коллекции:

$post = array(
         'title'     => 'Что такое MongoDB',
         'content'   => 'MongoDB это высокопроизводительная документо-ориентированная база данных...',
         'saved_at'  => new MongoDate()
      );
     $posts->insert($post);

Метод insert() сохраняет данные в коллекцию. Массив $post автоматически получает поле с именем _id, содержащее уникальный сгенерированный ObjectId для вставленного BSON-документа.

Вы также можете использовать метод save(), который обновляет существующую запись или создает новую, если её еще не существует.

Чтение документа

Чтобы получить данные из коллекции, я использую метод find(), который получает все данные из коллекции. Метод findOne() возвращает только один документ, удовлетворяющий определенному в запросе критерию.

Следующие примеры показывают, как запросить одну или несколько записей:

// all records
     $result = $posts::find();
     // one record
     $id = '52d68c93cf5dc944128b4567';
     $results = $posts::findOne(array('_id' => new MongoId($id)));

Обновление документа

Перейдем к модификации существующего документа или документа в коллекции. По умолчанию, метод update() обновляет одиночный документ.

Если задана опция multi в значении true, то метод будет обновлять все документы, удовлетворяющие выбранному критерию:

$id = '52d68c93cf5dc944128b4567';
     $posts->update(
     	 array('_id'     => new MongoId($id)),
     	 array('$set'    => array(title'   => Что такое Фалькон?'))
     );

Метод update() принимает два параметра. Первый это критерий, описывающий объекты, которые нужно обновить, а второй – объект, которым нужно заменить объекты удовлетворяющие условиям записи.

Имеется также третий опциональный параметр, через который вы можете передать массив вариантов.

Мини-блог

Вот так будет выглядеть структура нашего будущего проекта:

|-------admin
            |------index.php                    # Это административная панель
            |------auth.php
    |-------view
            |------admin
                    |-------create.view.php     # форма создания статьи
                    |-------dashbroad.view.php
            |------index.view.php               
            |------layout.php       # основной шаблон, используемый для отображения результатов каждого действия приложения
            |------single.view.php              # Это шаблон для одиночной статьи
    |-------config.php                          # Определение параметров БД
    |-------app.php                             #  Подключение multi-php файлов
    |-------db.php                        # Контейнер класса db 
    |-------index.php
    |-------single.php
    |-------static                              # Контейнер css,js...
                |-----css
                |-----js
    |-------vendor
                |----markdown                   # Библиотека, конвертирующая разметку в html

Перед началом работы, создайте структуру файлов и папок, как показано выше.

config.php

Это главный конфигурационный файл проекта, который говорит, как подключаться к базе данных. Здесь также определены имя, логин и пароль пользователя для доступа к базе:

<?php
        define('URL', 'http://duythien.dev/sitepoint/blog-mongodb');
        define('UserAuth', 'duythien');
        define('PasswordAuth', 'duythien');

        $config = array(
            'username' => 'duythien',
            'password' => 'qazwsx2013@',
            'dbname'   => 'blog',
            'connection_string'=> sprintf('mongodb://%s:%d/%s','127.0.0.1','27017','blog')
        );

В этом коде мы определяем параметры UserAuth и PasswordAuth для защиты папки admin через HTTP-аутентификацию.

Здесь мы используем HTTP-аутентификацию для простоты, чтобы сконцентрироваться на главной задаче данной статьи – подключении к MongoDB. Для настройки уровней доступа, можно воспользоваться фреймворком с ACL.

Содержание файла app.php:

<?php
    include 'config.php';
    include 'layout.php';
    include 'db.php';

    use BlogDB,
        BlogLayout;

    // конструктор для db
    $db = new DBDB($config);

    // конструктор для представления
    $layout = new LayoutLayout();

Административная часть

Эта папка включает в себя CRUD-код:

<?php
require_once 'auth.php';
require_once '../app.php';
require_once '../vendor/markdown/Markdown.inc.php';
use MichelfMarkdownExtra,
    MichelfMarkdown;

if ((is_array($_SESSION) && $_SESSION['username'] == UserAuth)) {
    $data = array();
    $status = (empty($_GET['status'])) ? 'dashboard' : $_GET['status'];
    switch ($status) {
        // создание записи
        case 'create':
            break;
        // редактирование записи
        case 'edit':
            break;
        // удаление записи
        case 'delete':
        // отображение всех записей на контрольной панели
        default:
            $currentPage = (isset($_GET['page'])) ? (int)$_GET['page'] : 1;
            $data = $db->get($currentPage, 'posts');

            $layout->view('admin/dashboard', array(
                'currentPage' => $data[0],
                'totalPages' => $data[1],
                'cursor' => $data[2]
            ));
            break;
    }
}

Полный текст файла index.php смотрите здесь. Выше я использовал функцию view, определенную в классе layout.php, которая автоматически загружает dashboard.view.php:

<?php namespace BlogLayout;

Class Layout
{

    /**
     * @var array
     */
    public $data;

    public function view($path, $data)
    {
        if (isset($data)) {
            extract($data);
        }
        $path .= '.view.php';
        include "views/layout.php";
    }
}

GET-параметр status соответствует CRUD-действию. Например, когда статус он имеет значение “create”:

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    $article = array();
    $article['title'] = $_POST['title'];
    $article['content'] = Markdown::defaultTransform($_POST['content']);
    $article['saved_at'] = new MongoDate();

    if (empty($article['title']) || empty($article['content'])) {
        $data['status'] = 'Пожалуйста, заполните оба поля.';
    } else {

// затем создаем новую строку в коллекции posts
        $db->create('posts', $article);
        $data['status'] = 'Строка была успешно вставлена.';
    }
}
$layout->view('admin/create', $data);

Функция view(‘admin/create’, $data) показывает HTML-форму, в которой пользователь может ввести название/содержание нового поста в блоге, которое сохранится в MongoDB. По умолчанию скрипт отображает вот такую форму:

<form action="" method="post">
    <div><label for="Title">Заголовок</label>
        <input type="text" name="title" id="title" required="required"/>
    </div>
    <label for="content">Содержание</label>

    <p><textarea name="content" id="content" cols="40" rows="8" class="span10"></textarea></p>

    <div class="submit"><input type="submit" name="btn_submit" value="Сохранить"/></div>
</form>
Административная часть

Теперь разберемся с файлом db.php, полную версию которого можно найти здесь.

<?php 

namespace BlogDB;

class DB
{

    /**
     * Return db
     * @var object
     */
    private $db;

    /**
     * Results limit.
     * @var integer
     */
    public $limit = 5;


    public function __construct($config)
    {

        $this->connect($config);
    }

    //подключение к mongodb
    private function connect($config)
    {
    }

    //получение всех данных
    public function get($page, $collection)
    {
    }

    //получение данных по id
    public function getById($id, $collection)
    {
    }

    //создание статьи
    public function create($collection, $article)
    {
    }

    //удаление статьи по id
    public function delete($id, $collection)
    {
    }

    //обновление статьи
    public function update($id, $collection, $acticle)
    {
    }

    //создание и обновление комментария
    public function commentId($id, $collection, $comment)
    {
    }
}

Методы-курсоры MongoDB делают постраничную навигацию (пагинацию) достаточно простой. Комбинирование методов limit и skip очень в этом помогает. Также можно скомбинировать с методом order. Например:

public function get($page,$collection){

        $currentPage = $page;
        $articlesPerPage = $this->limit;

        //число статей, которые нужно пропустить сначала
        $skip = ($currentPage - 1) * $articlesPerPage; 

        $table = $this->db->selectCollection($collection);
    $cursor = $table->find();

        //общее число статей в базе данных
        $totalArticles = $cursor->count(); 

        //общее число страниц для отображения
        $totalPages = (int) ceil($totalArticles / $articlesPerPage); 

        $cursor->sort(array('saved_at' => -1))->skip($skip)->limit($articlesPerPage);

        $data=array($currentPage,$totalPages,$cursor);

    return $data;
}

index.php: файлы шаблонов могут быть найдены в папке view; например, index.view.php. Ниже приведен пример файла index.php:

<?php
require 'app.php';

try {
    $currentPage = (isset($_GET['page'])) ? (int)$_GET['page'] : 1; //текущий номер страницы

    $data = $db->get($currentPage, 'posts');
    $layout->view('index', array(
        'currentPage' => $data[0],
        'totalPages' => $data[1],
        'cursor' => $data[2],
        'name' => 'Duy Thien'
    ));
} catch (Exception $e) {
    echo 'Caught exception: ', $e->getMessage(), "n";
}

Откройте браузер и введите в адресной строке http://duythien.dev/sitepoint/blog-mongodb. Это отобразит список всех статей в блоге:

Административная часть - 2

single.php: когда вы просматриваете страницу с постом (нажмите кнопку «Читать далее..»), то используется файл single.view.php из папки views.

Вот логика работы шаблона single.php:

<?php

require 'app.php';
// получение поста
$post = $db->getById($_GET['id'], 'posts');
if ($post) {
    $layout->view('single', array(
        'article' => $post
    ));
}

Этот файл получает _id статьи через HTTP GET-параметр. Мы вызываем метод findOne() для коллекции articles, передавая ему значение _id в качестве параметра. Метод findOne() используется для запроса одиночного документа.

Смотрите функцию getById() в файле db.php:

Введите произвольное имя и e-mail в соответствующие поля ввода под секцией комментариев, и заполните текстовое поле самим комментарием.

Затем кликните по кнопке «Сохранить» и страница перезагрузится, отобразив добавленный вами комментарий.

Вот так выглядит файл comment.php:

<?php

require 'app.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    $id = $_POST['article_id'];
    $comment = array(
        'name' => $_POST['fName'],
        'email' => $_POST['fEmail'],
        'comment' => $_POST['fComment'],
        'posted_at' => new MongoDate()
    );
    $status = $db->commentId($id, 'posts', $comment);

    if ($status == TRUE) {
        header('Location: single.php?id=' . $id);
    }
}

Комментарии к статье хранятся в виде массива в поле документа под названием comments. Каждый комментарий является документом, содержащим несколько полей.

Заключение

В данной статье, мы описали процесс создания простейшего CRUD-приложения на PHP и MongoDB. Мы даже использовали примитивный MVC-подход при разработке (смотрите полный пример на Github).

На ваши плечи ложится ответственность за использование фреймворка для более надежной аутентификации посредством HTTP, добавление дополнительного функционала, но основные вещи уже реализованы и вы можете использовать приведенный пример для своего блога, наполнив его контентом.

Для подробной информации о MongoDB обратитесь к документации. Надеюсь, данная статья оказалась полезной для вас!

Вадим Дворниковавтор-переводчик статьи «Building a Simple Blog App with MongoDB and PHP»