Generate Custom Code with Symfony
Time to read: 6 minutes
Generate Custom Code With Symfony
Very few frameworks come close to Symfony in terms of developer experience. One major contributor to this is the Symfony MakerBundle which helps developers auto-generate code associated with controllers, forms, and entities. However, it doesn’t stop there as the MakerBundle allows you to create your custom Makers — auto-generating code for your particular use case.
In the previous part of this series, you created an application that converts between files of different formats. In this tutorial, you will create a custom Maker which auto-generates the code for creating a new converter. You will conclude by creating a new converter for a popular format in use today — XML!
Prerequisites
To follow this tutorial, you will require the following.
- A basic understanding of and familiarity with PHP and Symfony
- PHP 8.2 or above
- Composer globally installed
- The Symfony CLI
- A JavaScript package manager (npm will be used in this tutorial)
Set up a new Symfony project
If you already have the code from the first part in this series, you can skip this section. However, if you're just joining, you can clone the repository to get started.
Next, install the project's dependencies using Composer, by running the command below.
Provision the database
For this tutorial, SQLite will be used for the database. The database will be saved to a file named data.db in the var folder. Create this file using the following command.
Then, update your database schema using the following commands:
Set up Tailwind CSS
Tailwind CSS and Flowbite are used to style the application. The JavaScript assets associated with this project are managed using Encore Webpack. Install the JavaScript dependencies and build your assets using the following commands.
After that, start the application by running the following command.
By default, the application runs on port 8000. Navigate to that port in your browser and your application will run as shown below. By default you should see the following conversion formats in the drop down.
This is a good starting point. Before adding a new conversion format, we'll create a Maker command to help with creating new converters.
Build the Maker command
In the src/Helper folder, create a new file named Maker. This folder will contain the code templates, the help text for the command, and the code for creating new files.
Add resources
In the Maker folder, create a new folder named Resources, and in it create two new folders named help and skeleton.
In the help folder, create a new file named make_converter.txt and add the following to it.
This text file will be rendered when the user passes the --help
flag to your command.
Add code templates
In the Resources/skeleton folder, create a new file named Reader.tpl.php and add the following code to it.
This is the template for the reader service which every converter must have. This service extends the AbstractReader
class located in src/Helper/Reader/AbstractReader.php, implementing the abstract function read()
.
Next, in the Resources/skeleton folder, create a new file named Writer.tpl.php and add the following code to it.
In a similar manner to the Reader
template, this is the template for the writer service which every converter must have. This service extends the AbstractWriter
class located in src/Helper/Reader/AbstractWriter.php, implementing the abstract function write()
.
Then, in the Resources/skeleton folder, create a new file named Converter.tpl.php and add the following code to it.
Every converter must implement the FileConverterInterface
located in src/Helper/Converter/FileConverterInterface.php. This template generates a new converter implementing the interface. It also imports the associated reader and writer services for you, saving you the hassle of remembering to do so.
With these in place, you can create a new maker that uses these resources for code generation.
Create the Maker
In the Helper/Maker folder, create a new file named MakeConverter.php, and add the following code to it.
The secret to creating your own Maker is extending the AbstractMaker class and implementing the required functions.
The getCommandName()
function should return a string corresponding to the name of the command. In your case you return ‘make:converter’ so that you can create a new converter by running symfony console make:converter
.
In the configureCommand()
function, you specify the arguments for the command and also set the help text. The command has only one argument which is the data format you want to build a converter for. Observe that the help message is set to the content of the src/Helper/Maker/Resources/help/make_converter.txt file you created earlier.
The getCommandDescription()
function returns a brief description of the command and what it does.
If your command depends on any other bundles, you can configure them in the configureDependencies()
function. This does not apply to your use case so the function is left empty.
The last function you implement is generate()
. This function performs the following actions:
- Retrieves the data format from the
data-format
command argument. If this argument is not provided, the command will ask for it. - Creates a new reader class using the data format and the
Reader
template you declared earlier - Creates a new writer class using the data format and the
Writer
template you created earlier - Creates a new converter class using the data format and the
Converter
template you created earlier. This template requires some extra parameters for the reader and writer class names. They are passed as an array to thegenerateClass()
function. - Writes the changes to actually create the files
- Writes a success message to the user
Test your implementation by running the following command.
Create a new converter
With your Maker command in place, create a new converter using the following command.
You should see the following output printed to the terminal:
To successfully handle a data format for conversion, you require three services:
- A reader service to read data in the XML format. The src/Helper/Reader/XMLReader.php file code contains the code for this service.
- A writer service that takes formatted data and writes it out in XML format. The src/Helper/Writer/XMLWriter.php file code contains the code for this service.
- A service that binds the reader and writer services to provide a conversion service. The src/Helper/Converter/XMLConverter.php file code contains the code for this service.
The output of the terminal command shows that the skeleton of these services have been created and are ready for you to update.
Add functionality for the XML reader
Open the newly created src/Helper/Reader/XMLReader.php fileand update its content as follows.
Add functionality for the XML Writer
Open src/Helper/Writer/XMLWriter.php and update its code to match the following.
Add functionality for the XML Converter
Edit the code in the newly created src/Helper/Converter/XMLConverter.php to match the following.
With these in place, your application is now able to handle files in the XML format.
Test that the application works as expected
Run the application using the following command (if you stopped it previously)
Loading the index page should show a new option for XML conversion as shown below.
That's how to generate custom code with Symfony
There you have it! Not only did you create a new conversion format, you’ve made it easier to add new formats in the future. By using a maker command to create new converters, you don’t have to remember which files to create, what interfaces they should implement (or classes to extend), where they should be located, or what classes to import. All these are taken care of so, that you can focus on what matters - reading and writing in a new format.
You can review the final codebase for this article on GitHub, should you get stuck at any point. I’m excited to see what else you come up with. Until next time, make peace not war ✌🏾
Joseph Udonsak is a software engineer with a passion for solving challenges — be it building applications, or conquering new frontiers on Candy Crush. When he’s not staring at his screens, he enjoys a cold beer and laughs with his family and friends. Find him at LinkedIn, Medium, and Dev.to.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.