-
Notifications
You must be signed in to change notification settings - Fork 0
Migrating components from FOF 2 to FOF 3
This page describes how you can refactor a real world FOF 2 component to use FOF 3. This is how we refactored Akeeba Subscriptions, a fairly complex piece of software, in less than two weeks – while also making the final touches to FOF 3 and maintianing and supporting our existing software at the same time. If you stick to this plan you will be able to pull off a code migration without losing your mind, minimising the bugs that you introduce while refactoring.
Move all code (component, plugins, modules) to a directory named “old". Since there’s no b/c you won’t be able to use the new code with the old code without a massive meltdown.
Start with the component back-end.
First create the fof.xml file. You need to tell it which namespace you want for your component, e.g. MyCompany\MyApp. Remember to set fof.xml to use the MagicSwitch factory in the back-end but also the Basic factory in the front-end for security and privacy reasons.
Then add an empty Dispatcher, then the main entry point file (e.g. myapp.php), then an empty Toolbar which you’ll need later. Now you have a component which goes straight to a 404 page. That’s actually good!
Now create an empty Control Panel view template file. The view should be named ControlPanel, not cpanel, but that's really up to you. We simply find that descriptive names work best six to eighteen months down the road when you'll have to remember what did you do when refactoring your component.
Edit the Dispatcher and make the ControlPanel view the default.
Now start importing one view at a time.
Start with the Model, copying the old code and refactoring it. Try restricting yourself to overriding / implementing onBefore/onAfter event methods. That is to say, try not overriding the main methods themselves. As for filters, you can always do $this->addBehaviour('Filters'); in your contructor to have FOF 3 manage field filters automatically. You can add customised filters by overriding onBeforeBuildQuery and onBeforeBuildCountQuery. As for table names, these remain the same. No need for data migration!
Keep in mind that FOF 3 models also implement what used to live in FOF 2's Table classes. You will most probably have to override the check() method itself. However, if you want to use server-side validation of form filters, you MUST remember to call parent::check before your customised code. Also remember that, unlike FOF 2, you do not return false and/or use setError to mark validation errors. You have to throw a RuntimeException instead.
Then create view template files for the back-end views. We recommend sticking with XML forms when possible. If you need some very customised presentation of data you can either create your own Field classes or use the ViewTemplate field type to quickly create customised representations. You may want to take a look at the Akeeba Subscriptions component to take hints.
You should not need many Controllers in the back-end. Most views can be dealt with without any specialised Controller. If you do need to specialise Controller try restricting yourself to either entirely new methods or the onBefore/onAfter events. That is to say, don't override the main methods (e.g. browse, edit, save, apply and so on) whenever possible.
At this point you do need to also add the Toolbar methods for each view you’re importing. See where you needed the Toolbar?
After importing all back-end views dealing with data you should move to the ControlPanel view. If you display stats and stuff like that it will take you a day to get it right… or you can look at Akeeba Subscriptions’ code for hints. A very important hint is how you get stats. In FOF 2 you were probably using a single Model to handle the business logic of the main data set of your application (e.g. subscriptions) and get stats about them. This is an overkill and will land you into hot water when maintaining the application. Instead, we recommend having a different Model for stats, extending from your main data set's model class and adding customised filters. See Akeeba Subscriptions' Subscriptions and SubscriptionsForStats back-end models.
Now we can move to the front-end.
First we have to import the back-end models in the frontend. This means creating front-end model classes which extend the back-end classes. Do that only for the models you are sure you so need in the front-end. This is required because you're using the Basic factory in the front-end which needs explicit class definition. This is a good thing because it makes sure that you're not accidentally exposing more information than you meant to in the public part of your application.
Now start importing each view, one at a time. This means that you have to work on the view template, view class and controller at the same time. You do need all of these classes, even if they're empty, because you're using the Basic factory. As explained, this is a good thing from a security and privacy point of view, just a bit of a kludge while refactoring.
Finally, you need to take care of the packaging. You need to take a look at Akeeba Subscriptions. We do NOT want developers to package dev releases of FOF 3 with their components. This was the norm in FOF 2, it caused interesting problems and is currently frowned upon. You are supposed to include the latest published version of FOF 3. Take a look at the Akeeba Subscriptions repository for a way to do that through Phing. The same repository also includes a package installation script for Joomla! 3.3 and later which lets you install FOF 3 through your package without problems.
After your component is refactored you can start migrating your modules and plugins, one at a time.
FOF (Framework on Framework) and its documentation are Copyright © 2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd.
FOF is Open Source Software, distributed under the GNU General Public License, version 2 of the license, or (at your option) any later version.
The FOF Wiki content is provided under the GNU Free Documentation License, version 1.3 of the license, or (at your option) any later version.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license can be found on the GNU site.