PHP7 and MongoDb madness

Alex Tatulchenkov
3 min readJun 10, 2016

--

Intro

This week I’ve decided to upgrade version of PHP to 7 and refactor code of my framework to use its new features. On my local machine I have php 5.5.32 which I use for all my projects so far. So I provisioned VM using Vagrant and Ansible.

The part of the role (in terms of Ansible) responsible for PHP 7 installation:

- name: PHP | Add PHP 7.0 PPA
apt_repository: repo='ppa:ondrej/php'
state=present
update_cache=yes
become: yes
become_method: sudo

- name: ensure PHP installed
apt: pkg={{ item }} state=latest

with_items:
- php7.0
- php7.0-dev
... more packages goes here
- php-pear
tags: php

for MongoDb:

---
- name: add MongoDB keyring
become: yes
become_method: sudo
shell: apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10

- name: add MongoDB repo
shell: echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/mongodb.list
become: yes
become_method: sudo

- name: install MongoDB
apt: pkg=mongodb-org state=latest update_cache=yes
become: yes
become_method: sudo
notify: restart mongodb

and for MongoDB PHP driver:

- name: Install php driver for MongoDB
pear: name=pecl/mongodb state=present
become: yes
become_method: sudo

After I had VM up and running I decided to run my unit test and got the first surprise:

Fatal error: Uncaught Error: Class 'MongoDB' not found in ...

After quick search I realized that ‘MongoDB’ class is provided only by mongo.so extension (which is deprecated) but not by mongodb.so. This meant that I had to rewrite all classes related to Mongo. Fortunately I had unit tests for all of them.

Next challenge I faced with was lack of examples for new MongoDB driver. If you are going to move from old MongoDb driver to the new one — here is my mini how-to.

Refactoring

First of all you have to use new Manager class, like

$storage = new \MongoDB\Driver\Manager("mongodb://localhost:27017");

instead of

$storage = new \MongoDB(new \MongoClient(), 'mongo_db_name');

see more in official documentation

One of the classes related to MongoDb was a class responsible for adding and getting items from the queue. Lets go method after method to see how I refactored my code.

To create a queue based on MongoDb we need two collections: one for items and another one for generating auto-increment IDs. See explanation in MongoDb docs

First of all we need to prepare our collections:

New MongoDb driver uses a fully qualified namespace (e.g. “databaseName.collectionName”) in most commands, so we prepare two namespaces one per collection.

For any write operation like ‘insert’, ‘update’, ‘delete’ we need instance of MongoDB\Driver\BulkWrite. Because it is bulk you can do several operations at once:

$bulk = new MongoDB\Driver\BulkWrite();
$bulk->insert([‘_id’ => 1, ‘x’ => 1]);
$bulk->insert([‘_id’ => 2, ‘x’ => 2]);

and then execute it with:

$manager->executeBulkWrite(‘db.collection’, $bulk, $writeConcern);

Items in the queue can have two types of priority: Normal and High. Items with high priority must be extracted before items with normal priority even if former was inserted earlier then latter.

To achieve this we need to add two additional fields to each item in the queue: ‘seq’ to store position in the sequence and ‘priority’. For quick search we add indexes for these fields. You should use MongoDB\Driver\Command for such operations.

To add new item to queue we have to generate new auto-incremental id to set it as ‘seq’. Following instructions from MongoDb site I used findAndModify query against ‘counters collection’:

Once we get value for ‘seq’ we can push an item to a queue. Here I used already known bulkInsert() again:

To extract item from the queue we have to use findAndModify again but this time against main collection:

As you see from the query I sort collection by priority desc and sequence number asc and remove found item from the queue.

findAndModify as well as update are atomic so even if we have number of concurrent processes every process will get its own item.

If you have an experience of work with old MongoDb driver you can compare the old version of the class with the new one.

One thing which was not covered in this article is execution of the queries on mongo. There is a good example in official documentation for MongoDB\Driver\Manager::executeQuery which is pretty straightforward

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Alex Tatulchenkov
Alex Tatulchenkov

Written by Alex Tatulchenkov

Senior Software Engineer at Intetics Inc., AppSec Manifesto evangelist

No responses yet

Write a response