📜 ⬆️ ⬇️

Automatic package building for CMS Joomla!

Before I started working on a current project, I did not think that I would ever have to use tools to automatically build projects. After all, I work exclusively with interpreted languages ​​that do not need compilation. However, as it turned out, they can be useful when developing in PHP, and especially when working with Joomla!

Previously, while working on any site, I made the necessary edits to the files and database on my local server, checked whether everything worked correctly, then, using the ftp-client and the phpMyAdmin, I copied the files and database changes to the working site. If I do not remember which files I exactly rules, and usually it happens, copied everything.

In the current project, work is being done on the local server, then edits are transferred to the test one, and only then to the working one. Moreover, the customer must be able to perform the last action independently. The solution for this in Joomla is - installation files for extensions plus the packaging of all extensions in the package. Thus, the customer can update all the extensions in just one step. And what should the developer do? For the component, you need to copy: the administrative and frontal parts, a folder from the media directory (you also had to copy language files before, but using the new standard for placing them you are freed from this). Then you need to move the manifest file from the administrative folder to the root and archive everything. It is also desirable to indicate the version number in the archive name. When all extensions are compiled, pack them all and the package manifest file into one archive. It seems to be nothing complicated, but only for the time being there are not many extensions. And if there are more than a dozen of them (in my case, 21, and their number is growing)? And what if from time to time it is necessary to promptly make edits and transmit an updated package?

It was then that I was puzzled by the issue of automatic assembly. At that time, I only knew about Ant. Starting to explore its capabilities, I learned more about Maven. But I was embarrassed that if suddenly I lacked the available opportunities, I would have to write in Java. So I continued searching and found Phing, the project builder for PHP. After reviewing its capabilities, I quickly realized that it has everything you need:

Phing installation


The easiest way to install Phing is using PEAR. To do this, just enter two commands in the console:
pear channel-discover pear.phing.info pear install phing/phing 

If you do not use PEAR, then the official website has instructions on how to install Phing manually.
')

Connect to NetBeans


The next step after installation is to connect to your IDE. I use NetBeans, there is a phingKing plugin for it to run tasks from the IDE. Starting from version 7.3, it can be installed directly from the plugin manager. In earlier versions, you will have to pre-download the plugin and install from a file.

After installation, the Phing Targets item will appear in the Windows menu. Phing tasks will be displayed in this window:

In the PHP settings in the NetBeans section, the PhingKing tab will appear in which you need to specify the path to Phing. In the project properties in the appropriate section, you must specify the path to the xml-file with tasks (more on this below).

Use from the command line


Using Phing from the command line is also easy. Place the tasks in the build.xml file and run the Phing script in the same directory, or specify the path to the xml file in the -buildfile parameter. You can get the full set of options by running phing -help.

Creating tasks


Tasks for Phing are written to an xml file (build.xml by default). By default, only one task specified in the project properties as default is launched, but in it you can specify dependencies for other tasks, each of which can also have its own dependencies, and all of them will be executed. The whole project is in the project tag, and each task in the target tag.

The simplest task file looks like this:
 <?xml version="1.0" encoding="UTF-8"?> <project name="test" default="build"> <target name="task1"> <echo msg="Task 1" /> </target> <target name="task2"> <echo msg="Task 2" /> </target> <target name="build" depends="task1, task2"> <echo msg="Build" /> </target> </project> 

The result will be displayed:
Task 1
Task 2
Build


Build Joomla Extensions


Now let's make Phing do something useful - build a package with extensions for Joomla.
Initial conditions:
Note: files with version numbers are conveniently used as independent ones, and without numbers to simplify the package building.
 <project name="make_project" default="build"> <!--    ,   --> <property name="src_dir" value="/opt/lampp/htdocs/mysite" /> <property name="res_dir" value="/home/user1/mysite" /> <target name="clear"> <echo>=============    =============</echo> <!--  delete       fileset --> <delete includeemptydirs="true"> <!--  ${res_dir}    res_dir --> <fileset dir="${res_dir}"> <!--    /   --> <include name="**"/> </fileset> </delete> </target> <target name="com_test"> <echo>=============  Test =============</echo> <!--   xml-.     . --> <xmlproperty file="${src_dir}/administrator/components/com_test/test.xml" prefix="com_test." keepRoot="false" /> <!--       → <!--   --> <copy todir="${res_dir}/src/com_test/site" overwrite="true"> <fileset dir="${src_dir}/components/com_test"> <include name="**" /> </fileset> </copy> <!--   --> <copy todir="${res_dir}/src/com_test/admin" overwrite="true"> <fileset dir="${src_dir}/administrator/components/com_test"> <!--  ,    --> <exclude name="${src_dir}/administrator/test.xml" /> </fileset> </copy> <!--        --> <copy file="${src_dir}/administrator/components/com_test/test.xml" tofile="${res_dir}/src/com_test/test.xml" overwrite="true"/> <!--    media --> <copy todir="${res_dir}/src/com_test/media" overwrite="true"> <fileset dir="${src_dir}/media/com_test"> <include name="**" /> </fileset> </copy> <!--     --> <zip destfile="${res_dir}/cache/com_test.zip" basedir="${res_dir}/src/com_test"/> <!--      .    xml- --> <copy file="${res_dir}/cache/com_test.zip" tofile="${res_dir}/zip/com_test-${com_test.version}.zip" overwrite="true"/> </target> <!--    .     --> <target name="mod_test"> <echo>=============  Test =============</echo> <xmlproperty file="${src_dir}/modules/mod_test/mod_test .xml" prefix="mod_test." keepRoot="false"/> <copy todir="${res_dir}/src/mod_test" overwrite="true"> <fileset dir="${src_dir}/modules/mod_test"> <include name="**" /> </fileset> </copy> <zip destfile="${res_dir}/cache/mod_test.zip" basedir="${res_dir}/src/mod_test"/> <copy file="${res_dir}/cache/mod_test .zip" tofile="${res_dir}/zip/mod_test-${mod_calendar.version}.zip" overwrite="true"/> </target> <target name="build" depends="clear, com_test, mod_test"> <echo>=============   =============</echo> <!-- build/pkg_test.xml —     --> <xmlproperty file="${src_dir}/build/pkg_test.xml" prefix="pkg." keepRoot="false" /> <copy file="${src_dir}/build/pkg_test.xml" tofile="${res_dir}/cache/pkg_test.xml" overwrite="true"/> <zip destfile="${res_dir}/pkg_test-${pkg.version}.zip" basedir="${res_dir}/cache"/> </target> </project> 

At first glance, it looks a bit intimidating, but in fact there is nothing complicated here. For most extensions, the code can be copied with only minor changes. Yes, and he has to rule very rarely. But with just one click we get a package with the current versions of all developed extensions.

You can still improve the process by adding auto-increment version numbers for each build, but I didn’t do that to match the version numbers with the database migration file names. If someone has any thoughts on this, write in the comments.

Source: https://habr.com/ru/post/212165/


All Articles