Let’s add MongoDB to our previously created Docker environment and configure Symfony to connect to our Mongo database.
This blog post builts upon the results we archived in Part 1 and Part 2 of this series about creating a Docker environment for PHP development with Symfony. Please make yourself familiar with the there introduced technologies. The result of the previous artices is needed to program along with this article.
Summary of the previous articles
In the first part we created the basic Docker environment with a NGINX webserver and PHP-FPM as PHP process manager. We also set up our git repository which will be the base for our deployment pipeline in a later article.
The second part was about installing Symfony in our container environment and connecting to the shell of our PHP container.
A database for our Docker system
Nearly every application today needs some kind of data persistence. For small apps data persistence in files may be enough, but most web apps use a database. Basically, there are two different types of database system: SQL and NoSQL.
Traditionally, a SQL database like MySQL or MariaDB was often used with PHP. Most of the PHP literature still uses MySQL as default database. There was even created a special expression for this tech stack: LAMP. It stands for Linux Apache MySQL PHP.
Nowadays, most modern application don’t use this stack anymore. Of course, for most servers we still use Linux. But instead of Apache, many apps are using the leaner NGINX webserver. And more and more MySQL is replaced by a NoSQL database like MongoDB.
You can find a lot of articles only about the advantages and disadvantages of both database technologies. I don’t want to add another one. Let’s just say, that for me MongoDB brings more flexibility and speed compared with the SQL approach. But of course, there are surely some cases where SQL is better suited. So decide by yourself what database you want to use. If you decided to use MongoDB, I am going to show you how to integrate the Mongo Database in your Docker Compose system for development and production.
Adding MongoDB to Docker Compose
As the first step, we are going to add a MongoDB container to our Docker system. We use the latest Image from the official Docker Hub. Since we don’t want to use hardcoded credentials in our scripts, we will use environment variables to store the credentials and to inject them to our container. In a dedicated article I explained how to configure your MongoDB with environment variables in your Docker system. I won’t go into detail here again. If you are interested, please read the dedicated blog post.
Let’s edit our docker-compose.dev.yml
file which we created in the last parts of the post series. We add MongoDB as a new service in the lines 26 to 39.
# myapp/docker-compose.dev.yml version: '3.7' services: php-fpm: build: context: ./php-fpm restart: unless-stopped environment: - COMPOSER_MEMORY_LIMIT=-1 volumes: - ./src:/var/www nginx: image: nginx:alpine restart: unless-stopped depends_on: - php-fpm ports: - "80:80" volumes: - ./src:/var/www - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./logs:/var/log mongo: image: mongo:latest restart: unless-stopped ports: - 27017:27017 environment: MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE} MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME} MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD} MONGODB_DB: ${MONGODB_DB} MONGODB_USER: ${MONGODB_USER} MONGODB_PASSWORD: ${MONGODB_PASSWORD} volumes: - ./mongo/init.sh:/docker-entrypoint-initdb.d/init.sh:ro
With this file we expose the MongoDB port 27017 outside of the Docker network. This has the effect that we can connect to our MongoDB from a Database Client like Studio 3T.
We also need to create our docker entry script in which we create the database credentials for our Symfony app. More details on the script you find in the blog post.
Create a new file myapp/mongo/init.sh
with the following content:
# myapp/mongo/init.sh set -e mongosh <<EOF use admin db = db.getSiblingDB('$MONGODB_DB'); db.createUser({ user: '$MONGODB_USER', pwd: '$MONGODB_PASSWORD', roles: [{ role: 'readWrite', db: '$MONGODB_DB' }] }) EOF
As you can see, we need six environment variables for our myapp/docker-compose.dev.yml
and myapp/mongo/init.sh
files. For our development environment, we are going to use a .env
file to set these variables. Let’s create the new file:
# myapp/.env MONGO_INITDB_ROOT_USERNAME=YOUR-NEW-LOCAL-MONGO-ADMIN-USER MONGO_INITDB_ROOT_PASSWORD=YOUR-NEW-LOCAL-MONGO-ADMIN-PASSWORD MONGO_INITDB_DATABASE=root-db # This os going to be used as MongoDB credentials for your app MONGODB_USER=YOUR-NEW-APP-MONGO-USER MONGODB_PASSWORD=YOUR-NEW-APP-MONGO-PASSWORD MONGODB_DB=myapp_dev MONGODB_URL=mongodb://${MONGODB_USER}:${MONGODB_PASSWORD}@mongo:27017/${MONGODB_DB}
Please customize the values of all variables but the MONGODB_URL
as you wish. We will use this file as source for the MongoDB container as well as for Symfony.
Restarting Docker with your new Container
Now we are ready to restart our Docker container with Docker Compose and check if everything works fine. Switch to your local terminal navigate to your project folder and enter the following command.
docker compose -f docker-compose.dev.yml up -d --build
Docker is now rebuilding and after a short while back with 3 container: PHP-FPM
, NGINX
and MONGO
. If you like, you can test you MongoDB and connect with a tool like Studio 3T with the credentials from your .env
file and localhost
as hostname.
Pushing changes to git
Before we go on and take care of the Symfony side, we should commit our changes to our git repository:
git add . git commit -m "Adding MongoDB container" git push -u origin main
Adding Doctine MongoDB ODM to your Symfony project
Great, we have now completed all the preliminary work to use Symfony with MongoDB. So, let’s configure Symfony accordingly. To do so, open your PHP containers shell. We install the Doctrine MongoDB ODM Bundle via Composer. To benefit from the advantages of Symfony Flex, we have to enable Recipes, we need to allow the usage of contributed recipes before we install the Bundle.
composer config extra.symfony.allow-contrib true composer require doctrine/mongodb-odm-bundle
The last command is installing the Doctrine MongoDB ODM Bundle and all its dependencies. After a short time the Composer is finished and you will find a lot of new files.
One file is particularly important for us: myapp/src/config/packages/doctrine_mongodb.yaml
– the configuration file for the MongoDB Bundle. It should look like this:
# myapp/src/config/packages/doctrine_mongodb.yaml doctrine_mongodb: auto_generate_proxy_classes: true auto_generate_hydrator_classes: true connections: default: server: '%env(resolve:MONGODB_URL)%' options: {} default_database: '%env(resolve:MONGODB_DB)%' document_managers: default: auto_mapping: true mappings: App: is_bundle: false dir: '%kernel.project_dir%/src/Document' prefix: 'App\Document' alias: App when@prod: doctrine_mongodb: auto_generate_proxy_classes: false auto_generate_hydrator_classes: false document_managers: default: metadata_cache_driver: type: service id: doctrine_mongodb.system_cache_pool framework: cache: pools: doctrine_mongodb.system_cache_pool: adapter: cache.system
As you can see in lines 6 and 8, Symfony expects two variables that happen to be named the same as our variables already set up in the .env
file. We need only to inject the values from our host system to our PHP docker container and connection from Symfony to MongoDB should work without changing any files in our Symfony project. We need adjust our myapp/docker-compose.dev.yml file accordingly in line 10 and 11:
# myapp/docker-compose.dev.yml version: '3.7' services: php-fpm: build: context: ./php-fpm restart: unless-stopped environment: - MONGODB_URL=${MONGODB_URL} - MONGODB_DB=${MONGODB_DB} - COMPOSER_MEMORY_LIMIT=-1 volumes: - ./src:/var/www nginx: image: nginx:alpine restart: unless-stopped depends_on: - php-fpm ports: - "80:80" volumes: - ./src:/var/www - ./nginx/nginx.conf:/etc/nginx/nginx.conf - ./logs:/var/log mongo: image: mongo:latest restart: unless-stopped ports: - 27017:27017 environment: MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE} MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME} MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD} MONGODB_DB: ${MONGODB_DB} MONGODB_USER: ${MONGODB_USER} MONGODB_PASSWORD: ${MONGODB_PASSWORD} volumes: - ./mongo/init.sh:/docker-entrypoint-initdb.d/init.sh:ro
Let’s rebuild our Docker container from our host systems terminal. Navigate to your projects folder and run the following command:
docker compose -f docker-compose.yml up -d --build
That’s it! We can now start and use MongoDB as database for our Symfony project. You can find all information about using the Doctrine MongoDB ODM Bundle with Symfony in the official documentation.
Symfony does not offer a official test command for the MongoDB connection and it would go beyond the scope of the article to develop some Mongo Documents, but you can follow the official guide I linked before.
Commit your changes
Before we end with this blog post, we have to commit our changes to our git repo. Run the following commands again from your host systems shell:
git add . git commit -m "Installing Doctrine MongoDB ODM Bundle" git push -u origin main
Summary
To summarize, we added a MongoDB container to our Docker system and used some environment variables to inject our wished database credentials to our container. Then we installed Symfony in our PHP container, also injected the credentials as environment variables and are now ready to use Symfony with MongoDB.
Next Steps
In the next parts of these blog article series, we are going to create also a production system based on our Docker environment and we are going to build a deployment pipeline to automatically deploy changes from our git repository to our live system.
The next blog post will be published on Sunday, 26th March at 11 am. The topic will be how to build your custom Docker Images locally with your PHP source code and push it to GitLabs Container Registry.