📜 ⬆️ ⬇️

Zend Framework 2 Blog Development Example. Part 1. ZendSkeletonApplication

In the past few years, my work has been connected with the use of CMS Drupal , but at leisure I studied and just started running projects on Python frameworks Django , Flask and Twisted . Now I decided to learn the basics of two or three popular PHP frameworks, and first I decided to study Zend Framework 2 and Yii .

In the process of familiarization with the Zend Framework 2, I studied the tutorial from the official site ( http://framework.zend.com/manual/2.2/en/user-guide/overview.html ), I looked through the framework documentation ( http: //framework.zend .com / manual / 2.2 / en / index.html ), read Michael Romer’s “Web development with Zend Framework 2” book and put together his own test application.

Having digested all this information, I came to the conclusion that the official tutorial on the framework is rather dry:

As a result, I was able to create a more or less satisfactory application in terms of functionality after reading the book.
')
In this article I want to give an example of developing a simple blog, it will have several differences from the official tutorial. First of all, I will try to focus on those issues that during the study seemed to me insufficiently disclosed in the official tutorial. In addition, I will use some technologies that are alternative to those used in the default Zend framework:


The article was written by a newbie (in the Zend Framework) for newbies, so any criticism of the case and tips for improving the application are welcome.

You can find the project code on Github: github.com/romka/zend-blog-example .

The article will be divided into 3 parts:

So let's get started.

Environment


I assume that you already have a configured web server (mine is available at zblog.kece.ru ) and an empty database has been created in MySQL for this project. Due to the fact that I plan to use Doctrine for working with the database, the database can be any one supported by this ORM.

I assume that you have the source code for ZendSkeletonApllication or my tutorial on hand. You can take them here: github.com/zendframework/ZendSkeletonApplication and here: github.com/romka/zend-blog-example . In addition, I assume that you understand the MVC pattern, have experience with any template maker and form validator.

Zend Framework uses the awesome Composer dependency manager, which also needs to be installed on your system. You can read more about Composer here in this article: habrahabr.ru/post/145946 . In a nutshell, Composer is a command line utility that allows you to quickly and conveniently download and install external libraries on which your PHP project depends. At the entrance, the utility accepts a JSON file in an intuitive format containing a list of names and versions of dependencies, at the output it downloads and installs the necessary libraries and their dependencies freeing you from the routine work.

The text of the article will sometimes refer to the source code of external applications or files automatically generated by Composer. These files are not in the repository, so for a deeper study of the application developed in this tutorial, you will need to install the necessary software yourself.

ZendSkeletonApplication


Using the Zend Framework, you can design and create the structure of your application from scratch, but to study the operation of the system, it is better to use the ZendSkeletonApplication preset . If you have configured Composer, just run the command:
php composer.phar create-project --repository-url="http://packages.zendframework.com" -s dev zendframework/skeleton-application path/to/install 


(with proper configuration, the php composer.phar command can be replaced simply with composer , but later in the article I will cite the first option as more universal)

After its execution, you will receive an application with the following structure (I left only the most interesting directories and files):
 config/ autoload/ global.php application.config.php module/ Application/ <   Application   > public/ css/ img/ js/ index.php vendor/ < ,      Zend Framework> composer.json init_autoloader.php 


Now you can open the created project. My version is available at zblog.kece.ru .

Let's take a closer look at the created directories and files.

Project structure


composer.json


Let's start with the composer.json file in the project root. It has the following form:
 { "name": "zendframework/skeleton-application", "description": "Skeleton Application for ZF2", "license": "BSD-3-Clause", "keywords": [ "framework", "zf2" ], "homepage": "http:// framework.zend.com/", "require": { "php": ">=5.3.3", "zendframework/zendframework": ">2.2.0rc1" } } 

This file sets the application parameters that will be used by Composer. The most interesting part of this config is the require section, which contains a list of external libraries on which the application depends. Now there is only Zend Framework 2 in the list of dependencies, but in the future, we will add some more dependencies here: Doctrine, Twig and others. After adding a new dependency, it will be enough to execute the command in the console:
 php composer.phar update 

and Composer will download the necessary libraries. All external dependencies are added to the vendor directory, now we can see the zendframework and composer directories in it.

Document root


Document_root of our application is not in the root of the project, but in the public directory, this is where the index.php file is located - the entry point to our project and the web server must be configured to work with this directory.

Index.php performs several important tasks, the two most interesting of which are connecting external libraries, loading the application configuration and launching it.

To connect external libraries, the init_autoloader.php file is executed from the project root, which in turn calls vendor / autoload.php and, after it, the file vendor / composer / autoaload_real.php automatically generated by Composer . This file defines autoload methods for external libraries loaded by the Composer. Thus, when we in the code of our modules will connect namespaces of the Zend \ View \ Model \ ViewModel form, PHP will know in which files to search for the specified namespaces.

Line of code:
 Zend\Mvc\Application::init(require 'config/application.config.php')->run(); 

loads application configuration files and launches it. During application initialization (calling the Zend \ Mvc \ Application :: init () method), a ServiceManager is created - a key object used in many parts of the application. By default, ServiceManager creates another key object - EventManager. In the future, when we will create our modules in their settings, we will inform the Service Manager what other objects need to be created for the operation of our module.

We will talk more about the Service Manager later, but now let's take a closer look at the config directory. It contains the application.config.php file, which returns an array with the application configuration that can tell a lot of interesting things.

The modules array contains a list of enabled modules. Now we have only one Application module enabled, but there will be more of them in the future.

The module_listener_options array contains two interesting elements - the module_paths and config_glob_paths arrays:

Thus, first of all, the settings are loaded from the file config / application.config.php, then the settings are loaded from the files config / autoload / {, *.} {Global, local} .php and, last of all, the settings set at the module level (about this we will talk later).

If there are two configuration files for the same module in the config / autoload: global and local (module_name.global.php and module_name.local.php), then the global file will be downloaded first, followed by the local, have priority over global ones.

The local.php and * .local.php files are included by default in the .gitignore file (if you use another version control system, you need to add them to exceptions manually) and they should be used only for settings that correspond only to the current environment. That is, if you have a project in one form or another running on several different platforms: production, test and developer sites, then in the global settings of the application you need to store data that is relevant for all the listed sites, and unique for each site, for example , data to access the database.

In addition to the configuration files global for the whole application, each module can have its own settings file. Such module configuration files are loaded in the order in which the list of active modules in the application.config.php file is defined. Thus, if you want to override the settings of another module in your module, then your module should be lower in this list.

The last important and not yet considered directory is the modules directory. In this directory there will be modules developed by us for our application. ZendSkeletonApplication comes with one Application module, but before exploring its structure, let's understand what a ServiceManager is and why it is needed.

ServiceManager


The official documentation ( http://framework.zend.com/manual/2.2/en/modules/zend.service-manager.intro.html ) states that the ServiceManager is a component that implements the Service Locator pattern for extracting other objects. . In other words, this is some entry point that allows you to access any objects registered in Service Manager from any location of the application.

Objects are registered in Service Manager either in the configuration file module.config.php in the service_manager section, or in Module.php in the getServiceConfig () method, it looks like this (example is copied from the documentation):
 <?php // a module configuration, "module/SomeModule/config/module.config.php" return array( 'service_manager' => array( 'aliases' => array( //            'SomeModule\Model\User' => 'User', ), 'factories' => array( //  —  , //  —   ,   FactoryInterface, //   ,  FactoryInterface, //   PHP  'User' => 'SomeModule\Service\UserFactory', 'UserForm' => function ($serviceManager) { $form = new SomeModule\Form\User(); // Retrieve a dependency from the service manager and inject it! $form->setInputFilter($serviceManager->get('UserInputFilter')); return $form; }, ), 'invokables' => array( //  —  , //  —  ,     . 'UserInputFiler' => 'SomeModule\InputFilter\User', ), 'services' => array( //  —  , //  — . 'Auth' => new SomeModule\Authentication\AuthenticationService(), ), ), ); 

Having the above configuration Service Manager in any of our controller, we can now call the code of the form:
 $user_form = $this->getServiceLocator()->get('UserForm'); 

and the $ user_form object will contain the corresponding form.

Now it is time to return to the Application module included in ZendSkeletonApplication.

Application Module


The directory tree of this module looks like this:
 config/ module.config.php language/ < *.po   > src/ Application/ Controller/ IndexController.php view/ application/ index/ index.phtml error/ 404.phtml index.phtml layout/ layout.phtml Module.php 

Let's start with Module.php. This file declares the Module class with 3 methods:
  1. onBootstrap ();
  2. getConfig ();
  3. getAutoloaderConfig ().

The code of the onBootstrap () method in this module is responsible for maintaining the routes of the Segment type (on the types of routes just below).

The getAutoloaderConfig () method tells the framework framework where to look for the source code for the module:
 public function getAutoloaderConfig() { return array( 'Zend\Loader\StandardAutoloader' => array( 'namespaces' => array( __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, ), ), ); } 

In the current case, this is the modules / Application / src / Application directory.

In the getConfig () method, the path to the module settings file is returned:
 return include __DIR__ . '/config/module.config.php'; 

This file returns an array with settings containing the following data:

As in other MVC frameworks, the Zend Framework uses the concepts of: route (route), controller, and action (action). The route determines the address of the page, the controller and the action - the actions that will be performed to display the page. Each controller is a class, and actions are methods with the name of the form nameAction () in it. As a result, each controller can contain several actions, for example, the BlogPostController () controller that we will create next will contain the actions addAction (), editAction (), deleteAction (), viewAction () and indexAction ().

In the settings of the Application module, two routes are defined:
 return array( 'router' => array( 'routes' => array( 'home' => array( 'type' => 'Zend\Mvc\Router\Http\Literal', 'options' => array( 'route' => '/', 'defaults' => array( 'controller' => 'Application\Controller\Index', 'action' => 'index', ), ), ), 'application' => array( 'type' => 'Literal', 'options' => array( 'route' => '/application', 'defaults' => array( '__NAMESPACE__' => 'Application\Controller', 'controller' => 'Index', 'action' => 'index', ), ), 'may_terminate' => true, 'child_routes' => array( 'default' => array( 'type' => 'Segment', 'options' => array( 'route' => '/[:controller[/:action]]', 'constraints' => array( 'controller' => '[a-zA-Z][a-zA-Z0-9_-]*', 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', ), 'defaults' => array( ), ), ), ), ), ), ), ); 


There are several types of routes, their description can be found in the documentation: framework.zend.com/manual/2.2/en/modules/zend.mvc.routing.html .

The Application module contains a single IndexController () controller with a single indexAction () action, which returns a page with a welcome message. To display this page, templates located in the view directory of the module are used.

At this point, I would like to complete the first part of the article, if it turns out to be in demand, I will complete and publish the remaining two parts, containing an example of developing a custom module and describing the mechanism for working with users.

upd:
The second and third parts of the article.

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


All Articles