How we built the Symfony CRM for Oxford Business Group

Sergey Konstantinov
ADCI Solutions
Published in
11 min readJan 19, 2018

From a simple search page to a high-grade CRM application in a year? That’s what we’ve been doing for Oxford Business Group using Symfony.

OBG is a global publisher and consultancy that has offices all around the globe. We were challenged to create the application that would allow the OBG staff to get timely updates on projects.

In this article, we will tell you how a CRM system on Symfony may look like, what goals it reaches, and what features includes.

Our project has a few specific terms.

  • Contact — a person in company, one of the main types of entities in the project
  • Outlook file — a list of all company’s meetings with details
  • Personal assistant — a person that assists the head of the company or someone else
  • Project — it’s simply a combination of a country and a year. For example, Peru + 2017

CRM: goals

Likewise, many other custom CRM systems, a CRM application for Oxford Business Group includes different search pages, forms for creating, editing and removing content, a users’ permissions system, a statistics dashboard, a scheduling system, etc.

We were supposed to create the application that should include the following functionality:

  • Data processing (editing/creating/removing information about companies, meetings, contacts)
  • A permissions system (an access to a project)
  • Search
  • Workflow features / Easy and comfortable layouts

Data Processing

There is a lot of stored information about companies, contacts of these companies, meetings, advertisement contracts. We designed the special pages for viewing, searching, and editing information. We have the separated blocks with scheduled meetings, and we have other blocks for “outlook files”: it is a special type of content that contains all information connected to a meeting: when it was held, what companies took part in the meeting, different notes of a meeting’s curator.

Meeting notes autosaving

Having a meeting considers taking a lot of notes. We developed the special feature that saves them for a manager. The manager doesn’t have to click on the ‘save’ button: all that he/she writes is saved in real time. This solution defends the manager against situations when he/she writes a lot of information and accidentally closes a page or something goes wrong with the internet connection, and when they try to save information by clicking on the button — a browser returns an error and all data is lost then. We also worked on the optimisation of our code, and this solution never hangs a server. We assume that this is a good practice — to use real-time saving for important information that users enter using their browsers.

A log system for calls and emails

Calls to different companies, negotiations, scheduling meetings are typical daily routine for managers. Of course, managers need a special place where they can find information about a company or add a new one, find a contact person and log them. Logging information about calls and emails is important because it helps to navigate through a big amount of companies and change priorities of calls or just separate companies that are not interested in the OBG services.

The latest meeting and a date of the latest getting in touch (with a company)

If you design a database that consists of a big number of tables and different relationships it could be difficult to produce fast queries. A typical situation here is a case when you are forced to find a way to denormalize your database because a lot of JOINs can’t work fast. The best way to solve it is using some search tool like Solr or using another relational database for saving indexes. At this moment, we don’t know whether we will use another kind of search or not in the future. So, using Solr looks like overhead because we just need to optimize search on the one page for a few parameters. And our solution is very typical. We added special fields to the ‘companies’ table that stores information about when these companies were contacted the last time and a date of the latest meeting. We created a special listener that fires special methods from our service class for updating these values. The architecture is simple and clear. One listener class listens to Doctrine events like ‘post update’, ‘post remove’, and ‘post delete’. Another service class has complex methods of getting data of the last meeting / a date of the last getting in touch, and updating a company’s record. Using something like this is very typical because we have no alternative solutions. Solr is nice, but we don’t need a search tool at this moment. We just need to optimize two queries. Using cron also can’t help us because we need to update records in real time. So, we found a rather good solution that helps us to save time and release very tricky logic for searching last meetings dates.

The permissions system

OBG is working in different countries, and we decided to create a flexible permissions system that takes this specifics into account. Managers often have an access to a few projects. A project looks like a combination of a project’s year and a project’s country. And different users have different sets of these combinations. This is a first layer of the permissions system.

Users roles

Next point is the usage of a roles’ system. For example, a user can be an ‘administrator’ in one project, and in this case, he/she can do all operations with content in this year. In another project the same user can be an ‘editorial manager’, and in this case, he/she can’t remove any data from this project.

And the last layer of the permissions system is the usage of Symfony FOSUserBundle roles. This layer is not directly connected to user permissions in projects but it defines what global operations are available for the user: viewing administration pages (like a page where admin can create a new user) or something else.

User Access Log

Administrators should have some statistics about using the application. We added the special functionality that can help admins with that. When the user logs in CRM it (CRM) fires a special method that saves a few details into a database: a date of the latest user login and an updated login counter. This approach helps us to understand who’s not active and who’s using the application a lot.

Select Project Form

The first step of optimization is the decrease of selection. All in all, if a user is forced to search information by looking through a lot of data, it takes more time than if the user has a small data set instead. We decided to add a form where the user can select a project. It means that the user works with data connected only with a selected project. This solution allows us to use our permissions system and makes the CRM application faster. A manager’s working day assumes that they work only with one project all day. So, if other data isn’t used we definitely don’t need to use this data in our queries. This is a key point if you want to make your application cleverer.

Search

Searching information should be easy and simple. We added all key fields that are usually used by managers in their search requests to forms. There are a lot of tricky fields that run complex queries and filter information in different layers. For instance, a user can find all companies that have advertising contracts in different projects or have no meetings yet. Also, we had a lot of requirements regarding queries’ maximal execution time, and we spent some time on optimising our requests.

Saving search

From time to time, users search for information by using the same parameters. Let’s imagine the following situation. You’re working on one project and your working day starts with opening a CRM and finding all companies in this project that has no updates in the current year. It means that you should select these parameters every day and if you are logged out of an application you will be forced to repeat all these operations. It’s annoying. We added a functionality that can help users to deal with this. So, you just select parameters one time and click the ‘save search’ button. It saves your searching parameters and makes it available on a special page. Also, you can make your saved searching parameters available for other staff. It’s convenient and gets you rid of routine operations each time when you need to get results by parameters that you already have used. We’re using our custom service for that, and if we have new search pages in future, we will be able to add the saving search functionality for these new pages. When we designed this feature we decided to write our custom service for parsing URLs. Why? If we change a site URL all saved searches won’t be available, because results depend on a site address. So, instead of using hardcoded links to pages in our solution we added a URL parser, which saves GET parameters to JSON. This looks pretty fine now, and can’t be affected if we move our app to another domain address.

Quick search

Sometimes users need an easier way to find a company or a contact. We added the special field that uses Select2 component and allows users to find information in real time. This special search field has two different algorithms for search: not strict and strict. If I wrap my searching string to quotes, the search form returns me only exact matches. After that, I just click on this link and the company or the contact that I want to find will be shown in a new tab. This is a good way of saving manager’s time and improving application usability.

Tags

This is a common practice to use some keywords to mark similar records. A lot of different CMSs and frameworks provide tagging functionality. There is a lot of bundles in Packagist, but we chose to write a custom bundle for our needs. This solution is more flexible for client requirements and has no extra logic or heavy queries. Our approach allows us to integrate tags bundle with the application permissions system and searching functionality. Not all users can create new vocabularies or edit existing tags. A set of terms that the user can add to different content depends on a selected project. Some vocabularies can appear in one or a few projects. If we had used a third-party bundle for tags we would have got overhead and a non-flexible solution.

Workflow features / Easy and comfortable layouts

Managers have a very busy day. All that they need is to open one page and get all information about a company, open related information like meetings, list of calls or “outlook file” by making just one click. So, we tried to take this into consideration and worked a lot on pages’ structures, layouts, and different control elements.

Company Wizard

Let’s consider a very simple use case. A manager tries to find the company by using a search page but the page returns no results. On the search page’s form, we placed the button ‘Add Company’. This button provides a method of creating a company without any details excluding a company name. If a user clicks on this button, a modal window will be opened where the manager can type a name of a new company, save and add other details or simply save and continue working with the search page. We used the modal windows API provided by Bootstrap, added custom logic. Very simple, but it helps managers to avoid extra clicks.

Interactive calendar

Our application has a mean of managing scheduled meetings. We used FullCalendar Bundle to release this feature. How does it work? You open a page and see a grid containing days of a current month. Each cell contains a list of meetings scheduled for this day. Meetings have different colors because a meeting can be of different types. If you click on a cell the application opens a modal window that allows you to add a new meeting. This window contains special fields that you can use for adding meeting details: assigned companies, assigned contacts, a meeting type and a meeting date/time. Our calendar section is named ‘Agenda’ and it’s similar to the interactive calendar in Microsoft Outlook. But our system has a few key differences. We released our custom filters because sometimes managers want to find meetings connected with some person or just view meetings that have selected types.

Сontact’s personal assistant

When you try to talk to a VIP it can be difficult to do. In most cases, heads of companies have personal assistants that can talk to you regarding topics of your interest. And managers need to store information about these people. We developed the special feature that lets managers tag some contacts as ‘main’ and store information about their personal assistants. We added special icons for easier search of this kind of personnel. So, if a contact has a personal assistant you will see an icon near the contact’s name. It can help to avoid annoying calls to very busy big bosses.

Dashboard

The Oxford business group’s CRM has a lot of stored information about companies worldwide. But how can we have a look at information connected with a particular project? What if I want to select companies in one project and select companies that have already signed a contract with us? We provide a way to do that. The special page ‘dashboard’ displays information about companies’ statuses in different projects. Here you can see percent values, different filters, and diagrams. It’s very simple and visual. Also, you can get a list of these companies with a click on a selected value.

Conclusion

Shout out to those who made it this far! We had the quick observation of the main features implemented in this CRM, and now you are all set to develop your own CRM with Symfony.

Stay in touch: those features are listed among 61 other ones and the new list of features is coming! The project is under active development, and you have a unique chance to see how this application is evolving, to learn in details how the simplest CRM system looks like, and how it can be upgraded. And we’re always here for you to consult and just chat.

Originally posted at the ADCI Solutions website.

--

--