
The lead developer of the Symfony framework, Fabien Potencier, in 2009, spoke at the Zend / PHP Conference with a report on how to benefit from sharing Symfony 1.3 / 1.4 and Zend Framework. The main theses of his speech are available
in the presentation published on his personal website [1].
As you know, Symfony2 is almost a new framework, created using the latest features of the PHP language. At the moment, the development went into the RC-cycle, and more and more developers with experience on the first branch of Symfony (and not only them) are looking towards the new flagship. But, despite the significant number of components included in the standard edition, Symfony2 does not cover all the needs of a web developer, therefore, sooner or later, the question arises of connecting external libraries.
')
Obviously, in this light, the extensive set of Zend libraries (Gdata, Search_Lucene, Pdf, etc.) cannot be ignored. In this post, I will look at the process of integrating Symfony2 and Zend using the example of Zend Gdata, a library for interacting with the
Google Data API [2].
Briefly about installing symfony2
As stated in the README of the standard symfony2 distribution, developers no longer recommend using git, offering to download the archive from the official site instead. At the time of writing the latest version of the post - RC4. All of the following will work in earlier versions with some reservations, because a significant refactoring was made in Command that affected the names of classes, and code generators appeared. I prefer to download the archive without vendors (without vendors), because when using GIT, the vendors directory
will be added to .gitignore anyway [3].
For development, the Apache and PHP 5.3.2 web server (and above) is sufficient. Detailed requirements are detailed in the
documentation [4].
Integration of Zend Gdata into the project
At the decision presented in this article, I was prompted by the presentation of Fabien, which was already mentioned above. On the Internet, you can find quite insane solutions, like processing a Zend distribution with regular expressions. I would be glad to hear other suggestions in the comments. There is also a
discussion on stackoverflow [5].
Since making any changes to the distribution library of the plug-in library can lead to difficulties in updating (and generally considered bad form), and binding to server environment variables restricts the developer, the proposed solution uses only standard Symfony2 and php tools.
First, follow the Zend Framework website and download
the Gdata distribution [6].
Create the following directory structure in the project:
vendor/
-> zend/
--> lib/
---> Zend/
----> [Zend directory from Zend GData package]
--> README
--> LICENSE
The README and LICENSE files are copied from the Zend GData distribution. Register the 'Zend_' prefix in app / autoload.php:
$loader->registerPrefixes(array(
Next, add to the end of the file (by analogy with Swift Mailer) the code from the Fabien presentation:
Now the classes included in Zend GData will be determined by the Symfony2 boot loader by the 'Zend_' prefix and all the numerous unlinked require in the Gdata distribution will work correctly, thanks to the changed include_path. It is possible that on loaded servers it would be reasonable to specify the value of include_path in php.ini.
Services
Quoting a
glossary of Symfony2 [7], a
service is a generic term for any PHP objects that perform any task used globally. Examples include a database connection or an object sending emails.
Based on this definition, it is easy enough to understand that, in our case, Zend_Gdata is a service.
Next, we will develop a console command that, using the Google GData API service, will upload blog posts from blogspot.com to the database.
First, create the GdataTestBundle bundle. Now that the code generator has appeared, this is done very simply:
$ php app/console generate:bundle --namespace=Habr/GDataBundle --format=yml
Now, add the following lines to the src / Habr / GDataBundle / Resources / config / services.yml configuration file (you must replace ~ in the lines marked with comments with real data to access the blog on blogger):
parameters: gdata.class: Zend_Gdata gdata.http_client.class: Zend_Gdata_HttpClient gdata.http_client_factory.class: Zend_Gdata_ClientLogin gdata.username: ~ # <email_address@gmail.com> gdata.password: ~ # <password> gdata.blog_id: ~ # <blog ID> gdata.service_name: blogger services: gdata_http_client: class: %gdata.http_client.class% factory_class: %gdata.http_client_factory.class% factory_method: getHttpClient arguments: - %gdata.username% - %gdata.password% - %gdata.service_name% gdata: class: %gdata.class% arguments: [@gdata_http_client]
Let us dwell on the contents of this configuration file. Symfony2 provides many ways to initialize services and resolve dependencies. In the simplest case, based on the class name specified in the configuration, an object is created that is returned to the client code using the get () method from the ContainerInterface interface. In reality, objects have complex dependencies among themselves and, often, the initialization of one service requires an instance of another, passed as an argument to the constructor. This case can be observed above for the gdata service.
Of much greater interest is the initialization of Zend_Gdata_HttpClient - an instance of an object of this class is created by calling the static method of the factory class (Zend_Gdata_ClientLogin), which is also passed arguments. More details about using factory classes to initialize services are described in the
special chapter of the Symfony Cookbook [8].
We will be able to test the resulting configuration when we create a console command using the service defined by us.
Model
Let's create a simple model for storing records uploaded from Blogger.com, which will also be helped by the built-in generator (if you don’t want to make your own changes to the model configuration, you can press enter on all subsequent questions interactively):
$ php app/console doctrine:generate:entity --entity="HabrGDataBundle:Post" --fields="title:string(255) content:text remote_id:string(255) created_at:datetime"
Now in the src / Habr / GDataBundle / Entity directory there is a generated Blog.php file, in which all necessary getters and setters are present. Further, to reflect the changes made at the DBMS level, we need to first configure the connection to the database.
To use MySQL, you need to change the corresponding part of app / config / parameters.ini as follows, using connection settings specific to you:
[parameters] ; ... database_driver = pdo_mysql database_host = localhost database_name = habr database_user = root database_password = ; …
The next step is to create a database:
$ php app/console doctrine:database:create
After we create tables based on models:
$ php app/console doctrine:schema:update --force
You can check the result of the command in phpmyadmin or any other client for the database you are using.
Team
The entity that was called “task” (task) in symfony 1.4 became a command in symfony2. In the current release, there is not yet a generator for commands, therefore, inside the root directory of the bundle, manually create a Command sub-directory where we put the file FetchFeedCommand.php (the Command suffix is ​​required).
The implementation of commands [9] (like most of the components of symfony2) is very simple, so I only provide source code with comments:
Now you can run the command by passing ./app/console its name, which is defined in the call to setName.
$ ./app/console gdata:blogger:fetch-feed
The result should be all blog entries in the database post table.
Conclusion
This example is somewhat synthetic, since authentication is not required to obtain an open feed of posts from Blogger.com. Those who want to practice and gain additional experience with Symfony2 can implement adding or deleting a new blog entry themselves. The link to the detailed documentation has already been given above.
In general, I want to add that now Symfony2 has already grown from the status of "impressive, but unstable thing." The framework is ready for serious projects.
PS I thank everyone who helped in the publication of this post.
Links
- Symfony & Zend Framework Together - 2009
- GData API
- Ignoring the vendor directory
- Requirements for running symfony2
- Question about using Zend_GData in Symfony2 on Stackoverflow
- Zend GData download page
- Symfony2 glossy
- How to Use Services
- How to create Console / Command-Line Commands