I have installed zend skeleton application framework.after Install running the browser its working good.
showing following page :
after insert module.run the code it also working good.
After created following to create Registerform.
src/Users/Form/RegisterForm.php
<?php
// filename : module/Users/src/Users/Form/RegisterForm.php
namespace UsersForm;
use ZendFormForm;
class RegisterForm extends Form
{
public function __construct($name = null)
{
parent::__construct('Register');
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/formdata');
$this->add(array(
'name' => 'name',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'Full Name',
),
));
$this->add(array(
'name' => 'email',
'attributes' => array(
'type' => 'email',
),
'options' => array(
'label' => 'Email',
),
'attributes' => array(
'required' => 'required'
),
'filters' => array(
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'EmailAddress',
'options' => array(
'messages' => array(
ZendValidator
EmailAddress::INVALID_FORMAT => 'Email address format is
invalid'
)
)
)
)
));
}
}
The view for registration page is created in
src/view/users/register/index.phtml
<section class="register">
<h2>Register</h2>
<?php if ($this->error): ?>
<p class="error">
There were one or more issues with your submission.
Please correct them as
indicated below.
</p>
<?php endif ?>
<?php
$form = $this->form;
$form->prepare();
$form->setAttribute('action', $this->url(NULL,
array('controller'=>'Register', 'action' => 'process')));
$form->setAttribute('method', 'post');
echo $this->form()->openTag($form);
?>
<dl class="zend_form">
<dt><?php echo $this->formLabel($form->get('name')); ?></dt>
<dd><?php
echo $this->formElement($form->get('name'));
echo $this->formElementErrors($form->get('name'));
?></dd>
<dt><?php echo $this->formLabel($form->get('email')); ?></
dt>
<dd><?php
echo $this->formElement($form->get('email'));
echo $this->formElementErrors($form->get('email'));
?></dd>
<dt><?php echo $this->formLabel($form->get('password'));
?></dt>
<dd><?php
echo $this->formElement($form->get('password'));
echo $this->formElementErrors($form->get('password'));
?></dd>
<dt><?php echo $this->formLabel($form->get('confirm_
password')); ?></dt>
<dd><?php
echo $this->formElement($form->get('confirm_password'));
echo $this->formElementErrors($form->get('confirm_
password'));
?></dd>
<dd><?php
echo $this->formElement($form->get('submit'));
echo $this->formElementErrors($form->get('submit'));
?></dd>
</dl>
<?php echo $this->form()->closeTag() ?>
</section>
The view for the confirmation page is pretty straightforward, the view is created in
src/view/users/register/confirm.phtml.
<section class="register-confirm">
<h2>Register Sucessfull</h2>
<p> Thank you for your registration. </p>
</section>
src/Users/Controller/RegisterController.php file
<?php
namespace UsersController;
use ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;
use UsersFormRegisterForm;
class RegisterController extends AbstractActionController
{
public function indexAction()
{
$form = new RegisterForm();
$viewModel = new ViewModel(array('form' =>
$form));
return $viewModel;
}
public function confirmAction()
{
$viewModel = new ViewModel();
return $viewModel;
}
}
config/module.config.php:
<?php
return array(
'controllers' => array(
'invokables' => array(
'UsersControllerIndex' => 'UsersControllerIndexController',
'UsersControllerRegister' =>'UsersControllerRegisterController',
),
),
'router' => array(
'routes' => array(
'users' => array(
'type' => 'Literal',
'options' => array(
// Change this to something specific to your module
'route' => '/users',
'defaults' => array(
// Change this value to reflect the namespace in which
// the controllers for your module are found
'__NAMESPACE__' => 'UsersController',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
// This route is a sane default when developing a module;
// as you solidify the routes for your module, however,
// you may want to remove it and replace it with more
// specific routes.
'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(
),
),
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'ZendSkeletonModule' => __DIR__ . '/../view',
),
),
);
Finally i want expect output look like but i am getting error :
but i am getting error:
An error occurred during execution; please try again later.
Additional information:
ZendViewExceptionRuntimeException
#0 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendViewView.php(205): ZendViewRendererPhpRenderer->render(Object(ZendViewModelViewModel))
#1 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendViewView.php(233): ZendViewView->render(Object(ZendViewModelViewModel))
#2 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendViewView.php(198): ZendViewView->renderChildren(Object(ZendViewModelViewModel))
#3 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendMvcViewHttpDefaultRenderingStrategy.php(103): ZendViewView->render(Object(ZendViewModelViewModel))
#4 [internal function]: ZendMvcViewHttpDefaultRenderingStrategy->render(Object(ZendMvcMvcEvent))
#5 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendEventManagerEventManager.php(468): call_user_func(Array, Object(ZendMvcMvcEvent))
#6 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendEventManagerEventManager.php(207): ZendEventManagerEventManager->triggerListeners('render', Object(ZendMvcMvcEvent), Array)
#7 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendMvcApplication.php(352): ZendEventManagerEventManager->trigger('render', Object(ZendMvcMvcEvent))
#8 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendMvcApplication.php(327): ZendMvcApplication->completeRequest(Object(ZendMvcMvcEvent))
#9 D:xampphtdocsCommunicationApppublicindex.php(17): ZendMvcApplication->run()
#10 {main}
please help me!!!
An error occurred
An error occurred during execution; please try again later.
Additional information:
ZendServiceManagerExceptionServiceNotFoundException
File:
C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php:518
Message:
ZendServiceManagerServiceManager::get was unable to fetch or create an instance for ZendAdapterAdapter
Stack trace:
#0 C:xampphtdocsZendSkeletonApplicationmoduleAlbumModule.php(40): ZendServiceManagerServiceManager->get(‘ZendAdapterAd…’)
#1 [internal function]: AlbumModule->Album{closure}(Object(ZendServiceManagerServiceManager), ‘albumtablegatew…’, ‘AlbumTableGatew…’)
#2 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(897): call_user_func(Object(Closure), Object(ZendServiceManagerServiceManager), ‘albumtablegatew…’, ‘AlbumTableGatew…’)
#3 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(1029): ZendServiceManagerServiceManager->createServiceViaCallback(Object(Closure), ‘albumtablegatew…’, ‘AlbumTableGatew…’)
#4 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(601): ZendServiceManagerServiceManager->createFromFactory(‘albumtablegatew…’, ‘AlbumTableGatew…’)
#5 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(561): ZendServiceManagerServiceManager->doCreate(‘AlbumTableGatew…’, ‘albumtablegatew…’)
#6 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(503): ZendServiceManagerServiceManager->create(Array)
#7 C:xampphtdocsZendSkeletonApplicationmoduleAlbumModule.php(35): ZendServiceManagerServiceManager->get(‘AlbumTableGatew…’)
#8 [internal function]: AlbumModule->Album{closure}(Object(ZendServiceManagerServiceManager), ‘albummodelalbum…’, ‘AlbumModelAlb…’)
#9 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(897): call_user_func(Object(Closure), Object(ZendServiceManagerServiceManager), ‘albummodelalbum…’, ‘AlbumModelAlb…’)
#10 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(1029): ZendServiceManagerServiceManager->createServiceViaCallback(Object(Closure), ‘albummodelalbum…’, ‘AlbumModelAlb…’)
#11 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(601): ZendServiceManagerServiceManager->createFromFactory(‘albummodelalbum…’, ‘AlbumModelAlb…’)
#12 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(561): ZendServiceManagerServiceManager->doCreate(‘AlbumModelAlb…’, ‘albummodelalbum…’)
#13 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendServiceManagerServiceManager.php(503): ZendServiceManagerServiceManager->create(Array)
#14 C:xampphtdocsZendSkeletonApplicationmoduleAlbumsrcAlbumControllerAlbumController.php(33): ZendServiceManagerServiceManager->get(‘AlbumModelAlb…’)
#15 C:xampphtdocsZendSkeletonApplicationmoduleAlbumsrcAlbumControllerAlbumController.php(14): AlbumControllerAlbumController->getAlbumTable()
#16 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendMvcControllerAbstractActionController.php(83): AlbumControllerAlbumController->indexAction()
#17 [internal function]: ZendMvcControllerAbstractActionController->onDispatch(Object(ZendMvcMvcEvent))
#18 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendEventManagerEventManager.php(468): call_user_func(Array, Object(ZendMvcMvcEvent))
#19 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendEventManagerEventManager.php(207): ZendEventManagerEventManager->triggerListeners(‘dispatch’, Object(ZendMvcMvcEvent), Object(Closure))
#20 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendMvcControllerAbstractController.php(117): ZendEventManagerEventManager->trigger(‘dispatch’, Object(ZendMvcMvcEvent), Object(Closure))
#21 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendMvcDispatchListener.php(114): ZendMvcControllerAbstractController->dispatch(Object(ZendHttpPhpEnvironmentRequest), Object(ZendHttpPhpEnvironmentResponse))
#22 [internal function]: ZendMvcDispatchListener->onDispatch(Object(ZendMvcMvcEvent))
#23 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendEventManagerEventManager.php(468): call_user_func(Array, Object(ZendMvcMvcEvent))
#24 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendEventManagerEventManager.php(207): ZendEventManagerEventManager->triggerListeners(‘dispatch’, Object(ZendMvcMvcEvent), Object(Closure))
#25 C:xampphtdocsZendSkeletonApplicationvendorzendframeworkzendframeworklibraryZendMvcApplication.php(309): ZendEventManagerEventManager->trigger(‘dispatch’, Object(ZendMvcMvcEvent), Object(Closure))
#26 C:xampphtdocsZendSkeletonApplicationpublicindex.php(28): ZendMvcApplication->run()
#27 {main}
0
2
Не могу понять в чем дело с этой веб мордой бареоса. установил залогинился, все джобы отображаются, только при ресторе не отображается список файлов, не работает вкладка «фоновое задание», вот такая ошибка:
Произошла ошибка
An error occurred during execution; please try again later.
Дополнительная информация:
ZendFormExceptionInvalidElementException
Файл:
/usr/share/bareos-webui/vendor/zendframework/zend-form/src/Fieldset.php:218
Сообщение:
No element by the name of [jobname] found in form
Трассировки стека:
#0 /usr/share/bareos-webui/module/Job/view/job/job/index.phtml(43): ZendFormFieldset->get('jobname')
#1 /usr/share/bareos-webui/vendor/zendframework/zend-view/src/Renderer/PhpRenderer.php(501): include('/usr/share/bare...')
#2 /usr/share/bareos-webui/vendor/zendframework/zend-view/src/View.php(205): ZendViewRendererPhpRenderer->render(Object(ZendViewModelViewModel))
#3 /usr/share/bareos-webui/vendor/zendframework/zend-view/src/View.php(233): ZendViewView->render(Object(ZendViewModelViewModel))
#4 /usr/share/bareos-webui/vendor/zendframework/zend-view/src/View.php(198): ZendViewView->renderChildren(Object(ZendViewModelViewModel))
#5 /usr/share/bareos-webui/vendor/zendframework/zend-mvc/src/View/Http/DefaultRenderingStrategy.php(103): ZendViewView->render(Object(ZendViewModelViewModel))
#6 [internal function]: ZendMvcViewHttpDefaultRenderingStrategy->render(Object(ZendMvcMvcEvent))
#7 /usr/share/bareos-webui/vendor/zendframework/zend-eventmanager/src/EventManager.php(444): call_user_func(Array, Object(ZendMvcMvcEvent))
#8 /usr/share/bareos-webui/vendor/zendframework/zend-eventmanager/src/EventManager.php(205): ZendEventManagerEventManager->triggerListeners('render', Object(ZendMvcMvcEvent), Array)
#9 /usr/share/bareos-webui/vendor/zendframework/zend-mvc/src/Application.php(353): ZendEventManagerEventManager->trigger('render', Object(ZendMvcMvcEvent))
#10 /usr/share/bareos-webui/vendor/zendframework/zend-mvc/src/Application.php(328): ZendMvcApplication->completeRequest(Object(ZendMvcMvcEvent))
#11 /usr/share/bareos-webui/public/index.php(24): ZendMvcApplication->run()
#12 {main}
При поисках в гуглах пишут что в версии 16.2.4 это пофиксили, но именно эта версия и установлена, php 5.6.30, на офсайте рекомендуют PHP >= 5.3.23
Подобная ошибка и на вкладке «Объемы» только сообщение другое
Decoding failed: Syntax error
I have installed zend skeleton application framework.after Install running the browser its working good. showing following page :
after insert module.run the code it also working good.
After created following to create Registerform. src/Users/Form/RegisterForm.php
<?php
// filename : module/Users/src/Users/Form/RegisterForm.php
namespace UsersForm;
use ZendFormForm;
class RegisterForm extends Form
{
public function __construct($name = null)
{
parent::__construct('Register');
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/formdata');
$this->add(array(
'name' => 'name',
'attributes' => array(
'type' => 'text',
),
'options' => array(
'label' => 'Full Name',
),
));
$this->add(array(
'name' => 'email',
'attributes' => array(
'type' => 'email',
),
'options' => array(
'label' => 'Email',
),
'attributes' => array(
'required' => 'required'
),
'filters' => array(
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'EmailAddress',
'options' => array(
'messages' => array(
ZendValidator
EmailAddress::INVALID_FORMAT => 'Email address format is
invalid'
)
)
)
)
));
}
}
The view for registration page is created in src/view/users/register/index.phtml
<section class="register">
<h2>Register</h2>
<?php if ($this->error): ?>
<p class="error">
There were one or more issues with your submission.
Please correct them as
indicated below.
</p>
<?php endif ?>
<?php
$form = $this->form;
$form->prepare();
$form->setAttribute('action', $this->url(NULL,
array('controller'=>'Register', 'action' => 'process')));
$form->setAttribute('method', 'post');
echo $this->form()->openTag($form);
?>
<dl class="zend_form">
<dt><?php echo $this->formLabel($form->get('name')); ?></dt>
<dd><?php
echo $this->formElement($form->get('name'));
echo $this->formElementErrors($form->get('name'));
?></dd>
<dt><?php echo $this->formLabel($form->get('email')); ?></
dt>
<dd><?php
echo $this->formElement($form->get('email'));
echo $this->formElementErrors($form->get('email'));
?></dd>
<dt><?php echo $this->formLabel($form->get('password'));
?></dt>
<dd><?php
echo $this->formElement($form->get('password'));
echo $this->formElementErrors($form->get('password'));
?></dd>
<dt><?php echo $this->formLabel($form->get('confirm_
password')); ?></dt>
<dd><?php
echo $this->formElement($form->get('confirm_password'));
echo $this->formElementErrors($form->get('confirm_
password'));
?></dd>
<dd><?php
echo $this->formElement($form->get('submit'));
echo $this->formElementErrors($form->get('submit'));
?></dd>
</dl>
<?php echo $this->form()->closeTag() ?>
</section>
The view for the confirmation page is pretty straightforward, the view is created in src/view/users/register/confirm.phtml.
<section class="register-confirm">
<h2>Register Sucessfull</h2>
<p> Thank you for your registration. </p>
</section>
src/Users/Controller/RegisterController.php file
<?php
namespace UsersController;
use ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;
use UsersFormRegisterForm;
class RegisterController extends AbstractActionController
{
public function indexAction()
{
$form = new RegisterForm();
$viewModel = new ViewModel(array('form' =>
$form));
return $viewModel;
}
public function confirmAction()
{
$viewModel = new ViewModel();
return $viewModel;
}
}
config/module.config.php:
<?php
return array(
'controllers' => array(
'invokables' => array(
'UsersControllerIndex' => 'UsersControllerIndexController',
'UsersControllerRegister' =>'UsersControllerRegisterController',
),
),
'router' => array(
'routes' => array(
'users' => array(
'type' => 'Literal',
'options' => array(
// Change this to something specific to your module
'route' => '/users',
'defaults' => array(
// Change this value to reflect the namespace in which
// the controllers for your module are found
'__NAMESPACE__' => 'UsersController',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
// This route is a sane default when developing a module;
// as you solidify the routes for your module, however,
// you may want to remove it and replace it with more
// specific routes.
'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(
),
),
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'ZendSkeletonModule' => __DIR__ . '/../view',
),
),
);
Finally i want expect output look like but i am getting error :
but i am getting error: An error occurred during execution; please try again later. Additional information: ZendViewExceptionRuntimeException
#0 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendViewView.php(205): ZendViewRendererPhpRenderer->render(Object(ZendViewModelViewModel))
#1 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendViewView.php(233): ZendViewView->render(Object(ZendViewModelViewModel))
#2 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendViewView.php(198): ZendViewView->renderChildren(Object(ZendViewModelViewModel))
#3 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendMvcViewHttpDefaultRenderingStrategy.php(103): ZendViewView->render(Object(ZendViewModelViewModel))
#4 [internal function]: ZendMvcViewHttpDefaultRenderingStrategy->render(Object(ZendMvcMvcEvent))
#5 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendEventManagerEventManager.php(468): call_user_func(Array, Object(ZendMvcMvcEvent))
#6 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendEventManagerEventManager.php(207): ZendEventManagerEventManager->triggerListeners('render', Object(ZendMvcMvcEvent), Array)
#7 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendMvcApplication.php(352): ZendEventManagerEventManager->trigger('render', Object(ZendMvcMvcEvent))
#8 D:xampphtdocsCommunicationAppvendorzendframeworkzendframeworklibraryZendMvcApplication.php(327): ZendMvcApplication->completeRequest(Object(ZendMvcMvcEvent))
#9 D:xampphtdocsCommunicationApppublicindex.php(17): ZendMvcApplication->run()
#10 {main}
please help me!!!
I have encountered same problem making this example by the book. Anyway, problem is that you are calling «view» located in
"src/view/users/register/index.phtml"
and in config/module.config.php you have set
'view_manager' => array(
'template_path_stack' => array(
'ZendSkeletonModule' => __DIR__ . '/../view',
),
),
It should point to right file location DIR . ‘/../src/view’. Or you should move this folder to right location «module/Users/view» (without «src») where all views should be.
Introducing Services and the ServiceManager — Zend Framework 2 2.4.9 documentation
Introducing Services and the ServiceManager¶
In the previous chapter we’ve learned how to create a simple “Hello World” Application in Zend Framework 2. This is a
good start and easy to understand but the application itself doesn’t really do anything. In this chapter we will
introduce you into the concept of Services and with this the introduction to ZendServiceManagerServiceManager.
What is a Service?¶
A Service is an object that executes complex application logic. It’s the part of the application that wires all
difficult stuff together and gives you easy to understand results.
For what we’re trying to accomplish with our Blog-Module this means that we want to have a Service that will give
us the data that we want. The Service will get it’s data from some source and when writing the Service we don’t really
care about what the source actually is. The Service will be written against an Interface that we define and that
future Data-Providers have to implement.
Writing the PostService¶
When writing a Service it is a common best-practice to define an Interface first. Interfaces are a good way to
ensure that other programmers can easily build extensions for our Services using their own implementations. In other
words, they can write Services that have the same function names but internally do completely different things but have
the same specified result.
In our case we want to create a PostService. This means first we are going to define a PostServiceInterface.
The task of our Service is to provide us with data of our blog posts. For now we are going to focus on the read-only
side of things. We will define a function that will give us all posts and we will define a function that will give us a
single post.
Let’s start by creating the Interface at /module/Blog/src/Blog/Service/PostServiceInterface.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?php // Filename: /module/Blog/src/Blog/Service/PostServiceInterface.php namespace BlogService; use BlogModelPostInterface; interface PostServiceInterface { /** * Should return a set of all blog posts that we can iterate over. Single entries of the array are supposed to be * implementing BlogModelPostInterface * * @return array|PostInterface[] */ public function findAllPosts(); /** * Should return a single blog post * * @param int $id Identifier of the Post that should be returned * @return PostInterface */ public function findPost($id); } |
As you can see we define two functions. The first being findAllPosts() that is supposed to return all posts and the
second one being findPost($id) that is supposed to return the post matching the given identifier $id. What’s new
in here is the fact that we actually define a return value that doesn’t exist yet. We make the assumption that the
return value all in all are of type BlogModelPostInterface. We will define this class at a later point and for
now we simply create the PostService first.
Create the class PostService at /module/Blog/src/Blog/Service/PostService.php, be sure to implement the
PostServiceInterface and its required functions (we will fill in these functions later). You then should have a
class that looks like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php // Filename: /module/Blog/src/Blog/Service/PostService.php namespace BlogService; class PostService implements PostServiceInterface { /** * {@inheritDoc} */ public function findAllPosts() { // TODO: Implement findAllPosts() method. } /** * {@inheritDoc} */ public function findPost($id) { // TODO: Implement findPost() method. } } |
Writing the required Model Files¶
Since our PostService will return Models, we should create them, too. Be sure to write an Interface for the
Model first! Let’s create /module/Blog/src/Blog/Model/PostInterface.php and /module/Blog/src/Blog/Model/Post.php.
First the PostInterface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?php // Filename: /module/Blog/src/Blog/Model/PostInterface.php namespace BlogModel; interface PostInterface { /** * Will return the ID of the blog post * * @return int */ public function getId(); /** * Will return the TITLE of the blog post * * @return string */ public function getTitle(); /** * Will return the TEXT of the blog post * * @return string */ public function getText(); } |
Notice that we only created getter-functions here. This is because right now we don’t bother how the data gets inside
the Post-class. All we care for is that we’re able to access the properties through these getter-functions.
And now we’ll create the appropriate Model file associated with the interface. Make sure to set the required class
properties and fill the getter functions defined by our PostInterface with some useful content. Even if our interface
doesn’t care about setter functions we will write them as we will fill our class with data through these. You then
should have a class that looks like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
<?php // Filename: /module/Blog/src/Blog/Model/Post.php namespace BlogModel; class Post implements PostInterface { /** * @var int */ protected $id; /** * @var string */ protected $title; /** * @var string */ protected $text; /** * {@inheritDoc} */ public function getId() { return $this->id; } /** * @param int $id */ public function setId($id) { $this->id = $id; } /** * {@inheritDoc} */ public function getTitle() { return $this->title; } /** * @param string $title */ public function setTitle($title) { $this->title = $title; } /** * {@inheritDoc} */ public function getText() { return $this->text; } /** * @param string $text */ public function setText($text) { $this->text = $text; } } |
Bringing Life into our PostService¶
Now that we have our Model files in place we can actually bring life into our PostService class. To keep the
Service-Layer easy to understand for now we will only return some hard-coded content from our PostService class directly. Create
a property inside the PostService called $data and make this an array of our Model type. Edit PostService like
this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<?php // Filename: /module/Blog/src/Blog/Service/PostService.php namespace BlogService; class PostService implements PostServiceInterface { protected $data = array( array( 'id' => 1, 'title' => 'Hello World #1', 'text' => 'This is our first blog post!' ), array( 'id' => 2, 'title' => 'Hello World #2', 'text' => 'This is our second blog post!' ), array( 'id' => 3, 'title' => 'Hello World #3', 'text' => 'This is our third blog post!' ), array( 'id' => 4, 'title' => 'Hello World #4', 'text' => 'This is our fourth blog post!' ), array( 'id' => 5, 'title' => 'Hello World #5', 'text' => 'This is our fifth blog post!' ) ); /** * {@inheritDoc} */ public function findAllPosts() { // TODO: Implement findAllPosts() method. } /** * {@inheritDoc} */ public function findPost($id) { // TODO: Implement findPost() method. } } |
After we now have some data, let’s modify our find*() functions to return the appropriate model files:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
<?php // Filename: /module/Blog/src/Blog/Service/PostService.php namespace BlogService; use BlogModelPost; class PostService implements PostServiceInterface { protected $data = array( array( 'id' => 1, 'title' => 'Hello World #1', 'text' => 'This is our first blog post!' ), array( 'id' => 2, 'title' => 'Hello World #2', 'text' => 'This is our second blog post!' ), array( 'id' => 3, 'title' => 'Hello World #3', 'text' => 'This is our third blog post!' ), array( 'id' => 4, 'title' => 'Hello World #4', 'text' => 'This is our fourth blog post!' ), array( 'id' => 5, 'title' => 'Hello World #5', 'text' => 'This is our fifth blog post!' ) ); /** * {@inheritDoc} */ public function findAllPosts() { $allPosts = array(); foreach ($this->data as $index => $post) { $allPosts[] = $this->findPost($index); } return $allPosts; } /** * {@inheritDoc} */ public function findPost($id) { $postData = $this->data[$id]; $model = new Post(); $model->setId($postData['id']); $model->setTitle($postData['title']); $model->setText($postData['text']); return $model; } } |
As you can see, both our functions now have appropriate return values. Please note that from a technical point of view
the current implementation is far from perfect. We will improve this Service a lot in the future but for now we have
a working Service that is able to give us some data in a way that is defined by our PostServiceInterface.
Bringing the Service into the Controller¶
Now that we have our PostService written, we want to get access to this Service in our Controllers. For this task
we will step foot into a new topic called “Dependency Injection”, short “DI”.
When we’re talking about dependency injection we’re talking about a way to get dependencies into our classes. The most
common form, “Constructor Injection”, is used for all dependencies that are required by a class at all times.
In our case we want to have our Blog-Modules ListController somehow interact with our PostService. This means
that the class PostService is a dependency of the class ListController. Without the PostService our
ListController will not be able to function properly. To make sure that our ListController will always get the
appropriate dependency, we will first define the dependency inside the ListControllers constructor function
__construct(). Go on and modify the ListController like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php // Filename: /module/Blog/src/Blog/Controller/ListController.php namespace BlogController; use BlogServicePostServiceInterface; use ZendMvcControllerAbstractActionController; class ListController extends AbstractActionController { /** * @var BlogServicePostServiceInterface */ protected $postService; public function __construct(PostServiceInterface $postService) { $this->postService = $postService; } } |
As you can see our __construct() function now has a required argument. We will not be able to call this class anymore
without passing it an instance of a class that matches our defined PostServiceInterface. If you were to go back to
your browser and reload your project with the url localhost:8080/blog, you’d see the following error message:
( ! ) Catchable fatal error: Argument 1 passed to BlogControllerListController::__construct() must be an instance of BlogServicePostServiceInterface, none given, called in {libraryPath}ZendServiceManagerAbstractPluginManager.php on line {lineNumber} and defined in moduleBlogsrcBlogControllerListController.php on line 15 |
And this error message is expected. It tells you exactly that our ListController expects to be passed an implementation
of the PostServiceInterface. So how do we make sure that our ListController will receive such an implementation?
To solve this, we need to tell the application how to create instances of the BlogControllerListController. If you
remember back to when we created the controller, we added an entry to the invokables array in the module config:
<?php // Filename: /module/Blog/config/module.config.php return array( 'view_manager' => array( /** ViewManager Config */ ), 'controllers' => array( 'invokables' => array( 'BlogControllerList' => 'BlogControllerListController' ) ), 'router' => array( /** Router Config */ ) ); |
An invokable is a class that can be constructed without any arguments. Since our BlogControllerListController
now has a required argument, we need to change this. The ControllerManager, which is responsible for instantiating
controllers, also support using factories. A factory is a class that creates instances of another class.
We’ll now create one for our ListController. Let’s modify our configuration like this:
<?php // Filename: /module/Blog/config/module.config.php return array( 'view_manager' => array( /** ViewManager Config */ ), 'controllers' => array( 'factories' => array( 'BlogControllerList' => 'BlogFactoryListControllerFactory' ) ), 'router' => array( /** Router Config */ ) ); |
As you can see we no longer have the key invokables, instead we now have the key factories. Furthermore the value
of our controller name BlogControllerList has been changed to not match the class BlogControllerListController
directly but to rather call a class called BlogFactoryListControllerFactory. If you refresh your browser
you’ll see a different error message:
An error occurred An error occurred during execution; please try again later. Additional information: ZendServiceManagerExceptionServiceNotCreatedException File: {libraryPath}ZendServiceManagerAbstractPluginManager.php:{lineNumber} Message: While attempting to create blogcontrollerlist(alias: BlogControllerList) an invalid factory was registered for this instance type. |
This message should be quite easy to understand. The ZendMvcControllerControllerManager
is accessing BlogControllerList, which internally is saved as blogcontrollerlist. While it does so it notices
that a factory class is supposed to be called for this controller name. However, it doesn’t find this factory class so
to the Manager it is an invalid factory. Using easy words: the Manager doesn’t find the Factory class so that’s probably
where our error lies. And of course, we have yet to write the factory, so let’s go ahead and do this.
Writing a Factory Class¶
Factory classes within Zend Framework 2 always need to implement the ZendServiceManagerFactoryInterface.
Implementing this class lets the ServiceManager know that the function createService() is supposed to be called. And
createService() actually expects to be passed an instance of the ServiceLocatorInterface so the ServiceManager will
always inject this using Dependency Injection as we have learned above. Let’s implement our factory class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php // Filename: /module/Blog/src/Blog/Factory/ListControllerFactory.php namespace BlogFactory; use BlogControllerListController; use ZendServiceManagerFactoryInterface; use ZendServiceManagerServiceLocatorInterface; class ListControllerFactory implements FactoryInterface { /** * Create service * * @param ServiceLocatorInterface $serviceLocator * * @return mixed */ public function createService(ServiceLocatorInterface $serviceLocator) { $realServiceLocator = $serviceLocator->getServiceLocator(); $postService = $realServiceLocator->get('BlogServicePostServiceInterface'); return new ListController($postService); } } |
Now this looks complicated! Let’s start to look at the $realServiceLocator. When using a Factory-Class that will be
called from the ControllerManager it will actually inject itself as the $serviceLocator. However, we need the real
ServiceManager to get to our Service-Classes. This is why we call the function getServiceLocator()` who will give us
the real «ServiceManager.
After we have the $realServiceLocator set up we try to get a Service called BlogServicePostServiceInterface.
This name that we’re accessing is supposed to return a Service that matches the PostServiceInterface. This Service
is then passed along to the ListController which will directly be returned.
Note though that we have yet to register a Service called BlogServicePostServiceInterface. There’s no magic
happening that does this for us just because we give the Service the name of an Interface. Refresh your browser and you
will see this error message:
An error occurred An error occurred during execution; please try again later. Additional information: ZendServiceManagerExceptionServiceNotFoundException File: {libraryPath}ZendServiceManagerServiceManager.php:{lineNumber} Message: ZendServiceManagerServiceManager::get was unable to fetch or create an instance for BlogServicePostServiceInterface |
Exactly what we expected. Somewhere in our application — currently our factory class — a service called
BlogServicePostServiceInterface is requested but the ServiceManager doesn’t know about this Service yet.
Therefore it isn’t able to create an instance for the requested name.
Registering Services¶
Registering a Service is as simple as registering a Controller. All we need to do is modify our module.config.php and
add a new key called service_manager that then has invokables and factories, too, the same way like we have it
inside our controllers array. Check out the new configuration file:
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php // Filename: /module/Blog/config/module.config.php return array( 'service_manager' => array( 'invokables' => array( 'BlogServicePostServiceInterface' => 'BlogServicePostService' ) ), 'view_manager' => array( /** View Manager Config */ ), 'controllers' => array( /** Controller Config */ ), 'router' => array( /** Router Config */ ) ); |
As you can see we now have added a new Service that listens to the name BlogServicePostServiceInterface and
points to our own implementation which is BlogServicePostService. Since our Service has no dependencies we are
able to add this Service under the invokables array. Try refreshing your browser. You should see no more error
messages but rather exactly the page that we have created in the previous chapter of the Tutorial.
Using the Service at our Controller¶
Let’s now use the PostService within our ListController. For this we will need to overwrite the default
indexAction() and return the values of our PostService into the view. Modify the ListController like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?php // Filename: /module/Blog/src/Blog/Controller/ListController.php namespace BlogController; use BlogServicePostServiceInterface; use ZendMvcControllerAbstractActionController; use ZendViewModelViewModel; class ListController extends AbstractActionController { /** * @var BlogServicePostServiceInterface */ protected $postService; public function __construct(PostServiceInterface $postService) { $this->postService = $postService; } public function indexAction() { return new ViewModel(array( 'posts' => $this->postService->findAllPosts() )); } } |
First please note that our controller imported another class. We need to import ZendViewModelViewModel, which
usually is what your Controllers will return. When returning an instance of a ViewModel you’re able to always
assign so called View-Variables. In this case we have assigned a variable called $posts with the value of whatever
the function findAllPosts() of our PostService returns. In our case it is an array of BlogModelPost classes.
Refreshing the browser won’t change anything yet because we obviously need to modify our view-file to be able to display
the data we want to.
Note
You do not actually need to return an instance of ViewModel. When you return a normal php array it will
internally be converted into a ViewModel. So in short:
return new ViewModel(array(‘foo’ => ‘bar’));
equals
return array(‘foo’ => ‘bar’);
Accessing View Variables¶
When pushing variables to the view they are accessible through two ways. Either directly like $this->posts or
implicitly like $posts. Both are the same, however, calling $posts implicitly will result in a little round-trip
through the __call() function.
Let’s modify our view to display a table of all blog posts that our PostService returns.
<!-- Filename: /module/Blog/view/blog/list/index.phtml --> <h1>Blog</h1> <?php foreach ($this->posts as $post): ?> <article> <h1 id="post<?= $post->getId() ?>"><?= $post->getTitle() ?></h1> <p> <?= $post->getText() ?> </p> </article> <?php endforeach ?> |
In here we simply run a foreach over the array $this->posts. Since every
single entry of our array is of type BlogModelPost we can use the respective getter functions to receive the data
we want to get.
Summary¶
And with this the current chapter is finished. We now have learned how to interact with the ServiceManager and we
also know what dependency injection is all about. We are now able to pass variables from our services into the view
through a controller and we know how to iterate over arrays inside a view-script.
In the next chapter we will take a first look at the things we should do when we want to get data from a database.
Я использую Zend Framework для отправки электронных писем. У меня есть имя хоста :: ALLOW_DNS валидатор. Сбой при попытке отправить письмо на yahoo.gr. Я получаю эту ошибку:
An error occurred
An error occurred during execution; please try again later.
Additional information:
ZendMailExceptionInvalidArgumentException
File:
/var/www/file/project/vendor/zendframework/zendframework/library/Zend/Mail/Address.php:41
Message:
'yahoo.gr ' is not a valid hostname for the email address
Электронная почта smth@yahoo.gr. Какие-либо предложения?
0
Решение
Из вашей ошибки единственная проблема, которую я вижу, это пробелы ‘yahoo.gr’ который будет / может вызвать сбой проверки.
Исправить предложение 1:
Вы должны начать использовать отделка() на ваше значение GET / POST «email».
Исправить предложение 2:
Что, кстати, в документация:
Проверка только локальной части
Если вам требуется Zend Validator EmailAddress для проверки только локальной части адреса электронной почты и вы хотите отключить проверку имени хоста, вы можете установить для параметра домена значение FALSE. Это заставляет Zend Validator EmailAddress не проверять часть имени узла адреса электронной почты.
$validator = new ZendValidatorEmailAddress();
$validator->setOptions(array('domain' => FALSE));
Исправить предложение 3:
Что, кстати, в документация также:
Проверка разных типов имен хостов
Часть имени узла адреса электронной почты проверяется на соответствие Zend Validator Hostname. По умолчанию принимаются только DNS-имена хостов в форме domain.com, хотя вы также можете принимать IP-адреса и локальные имена хостов.
Для этого вам нужно создать экземпляр Zend Validator EmailAddress, передав параметр для указания типа имен хостов, которые вы хотите принять. Более подробная информация включена в Zend Validator Hostname, хотя пример того, как принимать DNS и локальные имена хостов, приведен ниже:
$validator = new ZendValidatorEmailAddress(
ZendValidatorHostname::ALLOW_DNS |
ZendValidatorHostname::ALLOW_LOCAL);
if ($validator->isValid($email)) {
// email appears to be valid
} else {
// email is invalid; print the reasons
foreach ($validator->getMessages() as $message) {
echo "$messagen";
}
}
Ну, больше никаких предложений. Желаю тебе удачи!
Конец.
3
Другие решения
Других решений пока нет …
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
In-Depth Tutorial
In This Article
- What is a Model?
- Writing the PostRepository
- Create an entity
- Bringing Life into our PostRepository
- Bringing the Service into the Controller
- Writing a Factory Class
- Registering Services
- Using the repository in our controller
- Accessing View Variables
- Summary
In the previous chapter we’ve learned how to create a «Hello World» Application
using zend-mvc. This is a good start, but the application itself doesn’t really
do anything. In this chapter we will introduce you into the concept of models,
and with this, introduce zend-servicemanager.
What is a Model?
A model encapsulates application logic. This often entails entity or value
objects representing specific things in our model, and repositories for
retrieving and updating these objects.
For what we’re trying to accomplish with our Blog
module, this means that we
need functionality for retrieving and saving blog posts. The posts themselves
are our entities, and the repository will be what we retrieve them from and save
them with. The model will get its data from some source; when writing the model,
we don’t really care about what the source actually is. The model will be
written against an interface that we define and that future data providers must
implement.
Writing the PostRepository
When writing a repository, it is a common best-practice to define an interface
first. Interfaces are a good way to ensure that other programmers can easily
build their own implementations. In other words, they can write classes with
identical function names, but which internally do completely different things,
while producing the same expected results.
In our case, we want to create a PostRepository
. This means first we are going to
define a PostRepositoryInterface
. The task of our repository is to provide us with
data from our blog posts. For now, we are going to focus on the read-only side of
things: we will define a method that will give us all posts, and another method
that will give us a single post.
Let’s start by creating the interface at
module/Blog/src/Model/PostRepositoryInterface.php
namespace BlogModel;
interface PostRepositoryInterface
{
/**
* Return a set of all blog posts that we can iterate over.
*
* Each entry should be a Post instance.
*
* @return Post[]
*/
public function findAllPosts();
/**
* Return a single blog post.
*
* @param int $id Identifier of the post to return.
* @return Post
*/
public function findPost($id);
}
The first method, findAllPosts()
, will return all posts, and the second
method, findPost($id)
, will return the post matching the given identifier
$id
. What’s new in here is the fact that we actually define a return value —
Post
— that doesn’t exist yet. We will define this Post
class at a later
point; for now, we will create the PostRepository
class.
Create the class PostRepository
at module/Blog/src/Model/PostRepository.php
;
be sure to implement the PostRepositoryInterface
and its required method (we
will fill these in later). You then should have a class that looks like the
following:
namespace BlogModel;
class PostRepository implements PostRepositoryInterface
{
/**
* {@inheritDoc}
*/
public function findAllPosts()
{
// TODO: Implement findAllPosts() method.
}
/**
* {@inheritDoc}
*/
public function findPost($id)
{
// TODO: Implement findPost() method.
}
}
Create an entity
Since our PostRepository
will return Post
instances, we must create that
class, too. Let’s create module/Blog/src/Model/Post.php
:
namespace BlogModel;
class Post
{
/**
* @var int
*/
private $id;
/**
* @var string
*/
private $text;
/**
* @var string
*/
private $title;
/**
* @param string $title
* @param string $text
* @param int|null $id
*/
public function __construct($title, $text, $id = null)
{
$this->title = $title;
$this->text = $text;
$this->id = $id;
}
/**
* @return int|null
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getText()
{
return $this->text;
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
}
Notice that we only created getter methods; this is because each instance should
be unchangeable, allowing us to cache instances in the repository as necessary.
Bringing Life into our PostRepository
Now that we have our entity in place, we can bring life into our
PostRepository
class. To keep the repository easy to understand, for now we
will only return some hard-coded content from our PostRepository
class directly.
Create a property inside the PostRepository
class called $data
and make this an array
of our Post
type. Edit PostRepository
as follows:
namespace BlogModel;
class PostRepository implements PostRepositoryInterface
{
private $data = [
1 => [
'id' => 1,
'title' => 'Hello World #1',
'text' => 'This is our first blog post!',
],
2 => [
'id' => 2,
'title' => 'Hello World #2',
'text' => 'This is our second blog post!',
],
3 => [
'id' => 3,
'title' => 'Hello World #3',
'text' => 'This is our third blog post!',
],
4 => [
'id' => 4,
'title' => 'Hello World #4',
'text' => 'This is our fourth blog post!',
],
5 => [
'id' => 5,
'title' => 'Hello World #5',
'text' => 'This is our fifth blog post!',
],
];
/**
* {@inheritDoc}
*/
public function findAllPosts()
{
// TODO: Implement findAllPosts() method.
}
/**
* {@inheritDoc}
*/
public function findPost($id)
{
// TODO: Implement findPost() method.
}
}
Now that we have some data, let’s modify our find*()
functions to return the
appropriate entities:
namespace BlogModel;
use DomainException;
class PostRepository implements PostRepositoryInterface
{
private $data = [
1 => [
'id' => 1,
'title' => 'Hello World #1',
'text' => 'This is our first blog post!',
],
2 => [
'id' => 2,
'title' => 'Hello World #2',
'text' => 'This is our second blog post!',
],
3 => [
'id' => 3,
'title' => 'Hello World #3',
'text' => 'This is our third blog post!',
],
4 => [
'id' => 4,
'title' => 'Hello World #4',
'text' => 'This is our fourth blog post!',
],
5 => [
'id' => 5,
'title' => 'Hello World #5',
'text' => 'This is our fifth blog post!',
],
];
/**
* {@inheritDoc}
*/
public function findAllPosts()
{
return array_map(function ($post) {
return new Post(
$post['title'],
$post['text'],
$post['id']
);
}, $this->data);
}
/**
* {@inheritDoc}
*/
public function findPost($id)
{
if (! isset($this->data[$id])) {
throw new DomainException(sprintf('Post by id "%s" not found', $id));
}
return new Post(
$this->data[$id]['title'],
$this->data[$id]['text'],
$this->data[$id]['id']
);
}
}
Both methods now have appropriate return values. Please note that from a
technical point of view, the current implementation is far from perfect. We will
improve this repository in the future, but for now we have a working repository
that is able to give us some data in a way that is defined by our
PostRepositoryInterface
.
Bringing the Service into the Controller
Now that we have our PostRepository
written, we want to get access to this
repository in our controllers. For this task, we will step into a new topic
called «Dependency Injection» (DI).
When we’re talking about dependency injection, we’re talking about a way to get
dependencies into our classes. The most common form, «Constructor Injection», is
used for all dependencies that are required by a class at all times.
In our case, we want to have our ListController
somehow interact with our
PostRepository
. This means that the class PostRepository
is a dependency of
the class ListController
; without the PostRepository
, our ListController
will not be able to function properly. To make sure that our ListController
will always get the appropriate dependency, we will first define the dependency
inside the ListController
constructor. Modify ListController
as follows:
namespace BlogController;
use BlogModelPostRepositoryInterface;
use ZendMvcControllerAbstractActionController;
class ListController extends AbstractActionController
{
/**
* @var PostRepositoryInterface
*/
private $postRepository;
public function __construct(PostRepositoryInterface $postRepository)
{
$this->postRepository = $postRepository;
}
}
The constructor now has a required argument; we will not be able to create
instances of this class anymore without providing a PostRepositoryInterface
implementation. If you were to go back to your browser and reload your project
with the url localhost:8080/blog
, you’d see the following error message:
Catchable fatal error: Argument 1 passed to BlogControllerListController::__construct()
must be an instance of BlogModelPostRepositoryInterface, none given,
called in {projectPath}/vendor/zendframework/src/Factory/InvokableFactory.php on line {lineNumber}
and defined in {projectPath}/module/Blog/src/Controller/ListController.php on line {lineNumber}
And this error message is expected. It tells you exactly that our
ListController
expects to be passed an implementation of the
PostRepositoryInterface
. So how do we make sure that our ListController
will
receive such an implementation? To solve this, we need to tell the application
how to create instances of the BlogControllerListController
. If you remember
back to when we created the controller, we mapped it to the InvokableFactory
in the module configuration:
// In module/Blog/config/module.config.php:
namespace Blog;
use ZendServiceManagerFactoryInvokableFactory;
return [
'controllers' => [
'factories' => [
ControllerListController::class => InvokableFactory::class,
],
],
'router' => [ /** Router Config */ ]
'view_manager' => [ /** ViewManager Config */ ],
);
The InvokableFactory
instantiates the mapped class using no constructor
arguments. Since our ListController
now has a required argument, we need to
change this. We will now create a custom factory for our ListController
.
First, update the configuration as follows:
// In module/Blog/config/module.config.php:
namespace Blog;
// Remove the InvokableFactory import statement
return [
'controllers' => [
'factories' => [
// Update the following line:
ControllerListController::class => FactoryListControllerFactory::class,
],
],
'router' => [ /** Router Config */ ]
'view_manager' => [ /** ViewManager Config */ ],
);
The above changes the mapping for the ListController
to use a new factory
class we’ll be creating, BlogFactoryListControllerFactory
. If you refresh
your browser you’ll see a different error message:
An error occurred
An error occurred during execution; please try again later.
Additional information:
ZendServiceManagerExceptionServiceNotFoundException
File:
{projectPath}/zendframework/zend-servicemanager/src/ServiceManager.php:{lineNumber}
Message:
Unable to resolve service "BlogControllerListController" to a factory; are you
certain you provided it during configuration?
This exception message indicates that the service container could not resolve
the service to a factory, and asks if we provided it during configuration. We
did, so the end result is that the factory must not exist. Let’s write the
factory now.
Writing a Factory Class
Factory classes for zend-servicemanager may implement either
ZendServiceManagerFactoryFactoryInterface
, or be callable classes (classes
that implement the __invoke()
method); FactoryInterface
itself defines the
__invoke()
method. The first argument is the application container, and is
required; if you implement the FactoryInterface
, you must also define a second
argument, $requestedName
, which is the service name mapping to the factory,
and an optional third argument, $options
, which will be any options provided
by the controller manager at instantiation. In most situations, the last
argument can be ignored; however, you can create re-usable factories by
implementing the second argument, so this is a good one to consider when writing
your factories! For our purposes, this is a one-off factory, so we’ll only use
the first argument. Let’s implement our factory class:
// In /module/Blog/src/Factory/ListControllerFactory.php:
namespace BlogFactory;
use BlogControllerListController;
use BlogModelPostRepositoryInterface;
use InteropContainerContainerInterface;
use ZendServiceManagerFactoryFactoryInterface;
class ListControllerFactory implements FactoryInterface
{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param null|array $options
* @return ListController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new ListController($container->get(PostRepositoryInterface::class));
}
}
The factory receives an instance of the application container, which, in our
case, is a ZendServiceManagerServiceManager
instance. The container also
conforms to InteropContainerContainerInterface
, allowing re-use in other
dependency injection systems if desired. We pull a service matching the
PostRepositoryInterface
fully qualified class name and pass it directly to the
controller’s constructor.
There’s no magic happening; it’s just PHP code.
Refresh your browser and you will see this error message:
An error occurred
An error occurred during execution; please try again later.
Additional information:
ZendServiceManagerExceptionServiceNotFoundException
File:
{projectPath}/vendor/zendframework/zend-servicemanager/src/ServiceManager.php:{lineNumber}
Message:
Unable to resolve service "BlogModelPostRepositoryInterface" to a factory; are
you certain you provided it during configuration?
Exactly what we expected. Within our factory, the service
BlogModelPostRepositoryInterface
is requested but the ServiceManager
doesn’t know about it yet. Therefore it isn’t able to create an instance for the
requested name.
Registering Services
Registering other services follows the same pattern as registering a controller.
We will modify our module.config.php
and add a new key
called service_manager
; the configuration of this key is the same as that for
the controllers
key. We will add two entries, one for aliases
and one for
factories
, as follows:
// In module/Blog/config/module.config.php
namespace Blog;
// Re-add the following import:
use ZendServiceManagerFactoryInvokableFactory;
return [
// Add this section:
'service_manager' => [
'aliases' => [
ModelPostRepositoryInterface::class => ModelPostRepository::class,
],
'factories' => [
ModelPostRepository::class => InvokableFactory::class,
],
],
'controllers' => [ /** Controller Config */ ],
'router' => [ /** Router Config */ ],
'view_manager' => [ /** View Manager Config */ ],
];
This aliases PostRepositoryInterface
to our PostRepository
implementation,
and then creates a factory for the PostRepository
class by mapping it to the
InvokableFactory
(like we originally did for the ListController
); we can do
this as our PostRepository
implementation has no dependencies of its own.
Aliasing services
In zend-servicemanager, when you request a service by an alias you get the service
it is mapped to. So when you requestModelPostRepositoryInterface::class
you get
the PostRepository class using its fully qualified class name (FQCN). We often
alias an interface to an implementation service, as that allows the user to
indicate they want an implementation of the interface, but do not care which
implementation. For more information see
the zend-servicemanager Aliases documentation.
Try refreshing your browser. You should see no more error messages, but rather
exactly the page that we have created in the previous chapter of the tutorial.
Using the repository in our controller
Let’s now use the PostRepository
within our ListController
. For this we will
need to overwrite the default indexAction()
and return a view with the results
from the PostRepository
. Modify ListController
as follows:
// In module/Blog/src/Controller/ListController.php:
namespace BlogController;
use BlogModelPostRepositoryInterface;
use ZendMvcControllerAbstractActionController;
// Add the following import statement:
use ZendViewModelViewModel;
class ListController extends AbstractActionController
{
/**
* @var PostRepositoryInterface
*/
private $postRepository;
public function __construct(PostRepositoryInterface $postRepository)
{
$this->postRepository = $postRepository;
}
// Add the following method:
public function indexAction()
{
return new ViewModel([
'posts' => $this->postRepository->findAllPosts(),
]);
}
}
First, please note that our controller imported another class,
ZendViewModelViewModel
; this is what controllers will usually return within
zend-mvc applications. ViewModel
instances allow you to provide variables to
render within your template, as well as indicate which template to use. In this
case we have assigned a variable called $posts
with the value of whatever the
repository method findAllPosts()
returns (an array of Post
instances).
Refreshing the browser won’t change anything yet because we haven’t updated our
template to display the data.
ViewModels are not required
You do not actually need to return an instance of
ViewModel
; when you return
a normal PHP array, zend-mvc internally converts it into aViewModel
. The
following are equivalent:// Explicit ViewModel: return new ViewModel(['foo' => 'bar']); // Implicit ViewModel: return ['foo' => 'bar'];
Accessing View Variables
Let’s modify our view to display a table of all blog posts that our repository
returns:
<!-- Filename: module/Blog/view/blog/list/index.phtml -->
<h1>Blog</h1>
<?php foreach ($this->posts as $post): ?>
<article>
<h1 id="post<?= $post->getId() ?>"><?= $post->getTitle() ?></h1>
<p><?= $post->getText() ?></p>
</article>
<?php endforeach ?>
In the view script, we iterate over the posts passed to the view model. Since
every single entry of our array is of type BlogModelPost
, we can use its
getter methods and render it.
Instance Variables Vs Script Variables
By default, all variables passed via a view model to the renderer are imported
directly into the view script, and can therefore be referenced as either
instance or script variables (i.e.,$this->posts
is the same as$posts
).
However, we recommend to reference any variables defined as part of the
original view model using instance variable notation ($this->posts
), to
make it clear where they originate, and to only use script variable notation
($posts
) for variables defined in the script itself.
After saving this file, refresh your browser, and you should now see a list of
blog entries!
Summary
In this chapter, we learned:
- An approach to building the models for an application.
- A little bit about dependency injection.
- How to use zend-servicemanager to implement dependency injection in zend-mvc
applications. - How to pass variables to view scripts from the controller.
In the next chapter, we will take a first look at the things we should do when
we want to get data from a database.
Я пытался добавить больше гибкости в модуль альбома из Zend Framework 2. В этом процессе я пытался установить валидатор для одного из полей формы, особенно для имени альбома, которое в моем случае имя столбца в моей базе данных заглавие.
Я следил за частью проверки из одного из предыдущих ответов на мой пост, который можно найти здесь
Я использовал этот класс в своем классе альбомного контроллера следующим образом:
<?php
namespace AlbumController;
use ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;
use AlbumEntityAlbumAlbum;
use AlbumFormAlbumForm;
use AlbumModelAlbumAlbumExists;
use DoctrineORMEntityManager;
class AlbumController
extends AbstractActionController
{
public function addAction()
{
$form = new AlbumForm();
$form->get('submit')->setAttribute('value', 'Add');
$query = "SELECT a.title FROM AlbumEntityAlbumAlbum a";
$albumExists = new AlbumExists($this->getEntityManager(), $query, 'title');
$request = $this->getRequest();
if ($request->isPost())
{
$album = new Album();
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
$title = $this->getRequest()->getPost('title');
if ($form->isValid() && $albumExists->isValid($title))
{
$album->populate($form->getData());
$this->getEntityManager()->persist($album);
$this->getEntityManager()->flush();
return $this->redirect()->toRoute('album');
}
}
return array('form' => $form);
}
Когда я ввожу название/название альбома, которое уже есть в базе данных, возникает ошибка следующим образом:
An error occurred during execution; please try again later. Additional information: DoctrineORMQueryQueryException File: C:vendordoctrineormlibDoctrineORMQueryQueryException.php:69 Message: Invalid parameter number: number of bound variables does not match number of tokens.
Любая идея, где я делаю ошибку?