Sonata, MongDB & Symfony 3.3 on PHP7.1
I wanted to know if it was possible to use Sonata with mMngodb. After some research I found out that it was indeed possible.
If there is one thing I love it's discovering new things, trying out new things. There is so much I would like todo, sadly weekends are to shorty for all the experiments I wish to run.
I would like to write about those experiments more often, but it takes quite a lot of time to write these articles; so usually I don't write much about it.
But getting mongodb sf3.3 with sonata working without a mysql server has been slightly more complicated then expected, because the documentation was not that complete and there isn't any stable release of some of the bundles needed.
Before setting sail, I will not go into the details, I assume you have already installed a sonata with doctrine odm and that you are familliar with the process.
Also I used many elements from the sonata project user bundle installation guide.
What you need to installed
I did my install on a PHP 7.1 (thanks docker to make it so easy). But it should work the same on 7.0 normally.
You will of course need a brand new SF3.3, install with the fallowing packages :
Doctrine
We need doctrine to get our database sorted out.
- doctrine/mongodb-odm:^1.1.6 : To run with mongodb. You should remove the doctrine orm as we are going for a no sql install.
- doctrine/doctrine-bundle:^1.6 : The adapter to have doctrine & sf work together
Doctrine doesen't work with the latest php 7+ mongodb driver, which means we need another package to add compatibility
- alcaeus/mongo-php-adapter: ^1.1.2
Sonata
We also need sonata for our BO.
-
sonata-project/user-bundle:dev-master : To have user management, this will install the other bundles such as core and sonata admin.
- sonata-project/doctrine-mongodb-admin-bundle: dev-master : To allow sonata to work with a mongodb database.
Sadly we have to use dev-master and not any tags. There are fixes for SF3.3 and also for PHP7.1 that's not available in any tags. Latest version will simply not work. This is where I lost most of my time as I tried not to use any dev versions.
Mongdb ACL bundle
Well normally acl are handled in the orm database. But as we wish to use mongodb. Again we will need a bundle in dev-master
-
pwalkow/mongodb-acl-bundle: dev-master
This bundles composer.json says it isn't compatible with php 7.1. The issue is this bundle seems to be abandoned. But I couldn't find anything similar not abandoned. So let's use composer with --ignore-platform-reqs to get this bundle installed.
End result
"require": { "doctrine/doctrine-bundle": "^1.6", "doctrine/mongodb-odm": "^1.1.6", "alcaeus/mongo-php-adapter": "^1.1.2", "incenteev/composer-parameter-handler": "^2.0", "sensio/distribution-bundle": "^5.0.19", "sensio/framework-extra-bundle": "^3.0.2", "sonata-project/doctrine-mongodb-admin-bundle": "dev-master", "sonata-project/user-bundle": "dev-master", "symfony/monolog-bundle": "^3.1.0", "symfony/polyfill-apcu": "^1.0", "symfony/swiftmailer-bundle": "^2.3.10", "symfony/symfony": "3.3.*", "twig/twig": "^1.0||^2.0", "predis/predis": "^1.1.1", "pwalkow/mongodb-acl-bundle": "dev-master" },
Other bundles such as FOSUserBundle has been installed at this stage. Let's no start configuring our SF.
Getting truely started
Enable the proper bundles.
Modify your AppKernel to add the fallowing bundles.
// Dependency bundles new \Knp\Bundle\MenuBundle\KnpMenuBundle(), new \FOS\UserBundle\FOSUserBundle(), new \PWalkow\MongoDBAclBundle\MongoDBAclBundle(), // Sonata bundles new \Sonata\CoreBundle\SonataCoreBundle(), new \Sonata\BlockBundle\SonataBlockBundle(), new \Sonata\EasyExtendsBundle\SonataEasyExtendsBundle(), new \Sonata\AdminBundle\SonataAdminBundle(), new \Sonata\DoctrineMongoDBAdminBundle\SonataDoctrineMongoDBAdminBundle(), new \Sonata\UserBundle\SonataUserBundle('\'FOSUserBundle\''),
Configuration (app/config/config.yml)
Remove the symfony default doctrine orm configuration and add mongodb configuration
doctrine_mongodb: connections: default: server: "%mongodb_server%" options: {} default_database: "%mongodb_database%" document_managers: default: auto_mapping: true
Configure the acl storage :
pwalkow_mongo_db_acl: acl_provider: default_database: %mongodb_database%
Let's note that I have used a intermediate variable mongodb_database & server that will need to be set in the parameters.yml
We need to configure fos user bundle as well
fos_user: from_email: address : toto@toto.com sender_name: toto db_driver: mongodb firewall_name: main user_class: Sonata\UserBundle\Entity\BaseUser group: group_class: Sonata\UserBundle\Entity\BaseGroup group_manager: sonata.user.mongodb.group_manager service: user_manager: sonata.user.mongodb.user_manager
We are going to lake some changes here later. For now let's continue with our configuration.
Finally we need to configure sonata
sonata_block: default_contexts: [cms] blocks: # enable the SonataAdminBundle block sonata.admin.block.admin_list: contexts: [admin] sonata_user: security_acl: true manager_type: mongodb
This are quick configurations to get things going, you will need to make changes.
Routing (app/config/routing.yml)
We simply add the sonata routes.
sonata_user_security: resource: "@SonataUserBundle/Resources/config/routing/sonata_security_1.xml" sonata_user_resetting: resource: "@SonataUserBundle/Resources/config/routing/sonata_resetting_1.xml" prefix: /resetting sonata_user_profile: resource: "@SonataUserBundle/Resources/config/routing/sonata_profile_1.xml" prefix: /profile sonata_user_register: resource: "@SonataUserBundle/Resources/config/routing/sonata_registration_1.xml" prefix: /register sonata_user_change_password: resource: "@SonataUserBundle/Resources/config/routing/sonata_change_password_1.xml" prefix: /profile sonata_user_admin_security: resource: '@SonataUserBundle/Resources/config/routing/admin_security.xml' prefix: /admin sonata_user_admin_resetting: resource: '@SonataUserBundle/Resources/config/routing/admin_resetting.xml' prefix: /admin/resetting
You could also use the fos routes, both will work.
We are now missing the security configuration.
Security (app/config/security.yml)
security: role_hierarchy: ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN] ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] SONATA: - ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT # if you are using acl then this line must be commented providers: fos_userbundle: id: fos_user.user_manager firewalls: # Disabling the security for the web debug toolbar, the profiler and Assetic. dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false # -> custom firewall for the admin area of the URL admin: pattern: /admin(.*) context: user form_login: provider: fos_userbundle login_path: /admin/login use_forward: false check_path: /admin/login_check failure_path: null logout: path: /admin/logout target: /admin/login anonymous: true # -> end custom configuration # default login area for standard users # This firewall is used to handle the public login area # This part is handled by the FOS User Bundle main: pattern: .* context: user form_login: provider: fos_userbundle login_path: /login use_forward: false check_path: /login_check failure_path: null logout: true anonymous: true access_control: # URL of FOSUserBundle which need to be available to anonymous users - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } # Admin login page needs to be accessed without credential - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/admin/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } # Secured part of the site # This config requires being logged for the whole site and having the admin role for the admin part. # Change these rules to adapt them to your needs - { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] } - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY } acl: provider: mongodb_acl_provider
Basically this is the exact same as what has been done in the sonata documentation : https://sonata-project.org/bundles/user/3-x/doc/reference/installation.html#integrating-the-bundle-into-the-sonata-admin-bundle
With the diffrence of the acl provider being
mongodb_acl_provider.
At this point everyhing is nearly working, but if you try to open a page sf it going to tell you that mongodb_acl_provider is not know. We need to register a new service. To have it simple let's put this in the app/config/services.yml file
Adding Mongodb acl service
A simple service declaration is sufficient :
mongodb_acl_provider: parent: doctrine_mongodb.odm.security.acl.provider abstract: false autowire: false autoconfigure: false public: true
At this stage we are nearly ready.
Extending Sonata User bundle
We need to generate the proper entities.
php app/console sonata:easy-extends:generate SonataUserBundle -d src
Edit the AppKernetl to add our new bundle
new Application\Sonata\UserBundle\ApplicationSonataUserBundle(),
And update fos configuration to use the new entity, we only edit the fallowing configurations.
fos_user: user_class: Application\Sonata\UserBundle\Entity\User group: group_class: Application\Sonata\UserBundle\Entity\Group
We are nearly there, let's now create our mongodb indexes.
Preparing indexes
bin/console doctrine:mongodb:schema:update
We also need to init the acl's;
docker-compose exec php bin/console init:acl:mongodb
And you are good to go.
Errors I encountered
Sadly you are going to encounter a few errors in the sonata interface when trying to edit the users.
I had to create a getGenderList method in the ApplicationSonataUserBudnles/Mode/User
public function getGenderList() { return ['male' => 'Male', 'female' => 'Female']; }
Last I had an error with the groups not being able to render propelry, and ended up removing it from the admin form of the users.
Conclusions
Using Sonata on a orm project is quite easy, once all is installed everything works fine and the tutorials are straight forward. But on mongodb it's not so, there a re quite a few things not documented. The acl provider is the most annoying one of the bunch. Even in the latest symfony 3.3 documentation this is not propelry documented as it links to a unmaintained version. I believe majority of the install used mongodb & mysql together and therfore doesen't require acl stored in mongo.
I would like to point that it has been a month already since I actually did this and some new versions might be out there not requiring you to use the dev-master. I haven't had time to check.
Globally this install works well, but the sonata mongodb admin bundle is still not 100%. For exemple for some reasons embeded documens displayed as a table works great but the standard display is ugly. I ended up using the views of the admin bundle for collections which works and looks much better.