Zend Framework 2 not loading config from mail.local.php - zend-framework2

I am trying to get config smtp from mail.local.php, i did tried ServiceLoader getServiceLoader method, but I am unable to find a way to get configurations in my helper class:
What would be the best way to get autoload\mail.local.php,
namespace Helpers;
use Zend\Mail;
use Zend\Mail\Transport\Smtp as SmtpTransport;
use Zend\Mail\Transport\SmtpOptions;
class SendEmail
{
public static function email($to = '', $recipientName = '', $template = '')
{
$transport = new SmtpTransport();
// $options = new SmtpOptions(array(
// 'name' => 'smtp.mailtrap.io',
// 'host' => 'smtp.mailtrap.io',
// 'port' => 2525,
// 'connection_class' => 'crammd5',
// 'connection_config' => array(
// 'username' => 'f11f5a55fdfbf5',
// 'password' => '7780e1e7ee1cc5',
// ),
// ));
$mail = new Mail\Message();
$html = new \Zend\Mime\Part($template);
$html->type = 'text/html';
$body = new \Zend\Mime\Message;
$body->setParts(array($html));
$mail->setBody($body);
$mail->setFrom('admin#fonedoctors.com', 'Admin FoneDoctors');
$mail->addTo($to, $recipientName);
$mail->setSubject('Unpaid Invoices');
$transport->setOptions($options);
$transport->send($mail);
}
}

If you have your configuration file in /autoload/mail.local.php the configuration will have already been merged together as part of the ZF bootstrapping process. The merged module configuration can then be fetched from the service manager using $serviceManager->get('config');
To inject this configuration into your SendEmail class, you should ideally create a new factory.
class SendEmailFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$config = $container->get('config'); // all merged module configuration
$emailOptions = isset($config['my_email_config_key'])
? $config['my_email_config_key']
: [];
return new SendEmail($emailOptions);
}
}
You will also need to register the service with the service manager :
'service_manager' => [
'factories' => [
SendEmail::class => SendEmailFactory::class,
],
],
And update the SendEmail class to accept the options via the constructor.
class SendEmail
{
private $options;
public function __construct(array $options)
{
$this->options = $options;
}
// ...
}

Related

How to include EntityManager in ZendFramework 2 AbstractValidator

I have a custom validator, extending Zend AbstractValidator. The thing is, i want to include Doctrine EntityManager, but i keep failing! I tried to make a Factory for my Validator, but it doesn't seem to work. Help!! What am I doing wrong?
Validator:
$this->objectRepository stays empty, while i expect content.
namespace Rentals\Validator;
use Rentals\Response;
use Zend\Validator\AbstractValidator;
use Zend\Stdlib\ArrayUtils;
class ExistentialQuantification extends AbstractValidator
{
const NO_ENTITY_ID = 'noEntityId';
const ENTITY_NOT_FOUND = 'entityNotFound';
const INVALID_ID = 'invalidId';
protected $messageTemplates = [
self::NO_ENTITY_ID => 'The input does not contain an entity id.',
self::ENTITY_NOT_FOUND => 'The entity could not be found.',
self::INVALID_ID => 'The input does not contain an entity id.',
];
protected $objectRepository;
public function __construct(array $options)
{
$this->objectRepository = $options['object_repository'];
parent::__construct($options);
}
public function isValid($value)
{
if ($value === null) {
return true;
}
if (! isset($value->id)) {
$this->error(self::NO_ENTITY_ID);
return false;
}
$entityClass = $this->getOption('entity_class');
$controller = new Controller();
$entity = (new FactoryInterface)(EntityManager::class)->find($entityClass, $entity->id);
if (! $entity instanceof $entityClass) {
$this->error(self::ENTITY_NOT_FOUND);
return false;
}
if (! $entity->getId()) {
$this->error(self::NO_ENTITY_ID);
return false;
}
return true;
}
}
Factory:
namespace Rentals\Validator;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Stdlib\ArrayUtils;
class ExistentialQuantificationFactory implements FactoryInterface, MutableCreationOptionsInterface
{
protected $options = [];
public function setCreationOptions(array $options)
{
$this->options = $options;
}
public function createService(ServiceLocatorInterface $serviceLocator)
{
if (! isset($this->options['object_manager'])) {
$this->options['object_manager'] = 'doctrine.entitymanager.orm_default';
}
$objectManager = $serviceLocator->get($this->options['object_manager']);
$objectRepository = $objectManager->getRepository($this->options['entity_class']);
return new ExistentialQuantification(ArrayUtils::merge(
$this->options, [
'objectManager' => $objectManager,
'objectRepository' => $objectRepository
]
));
}
}
Module config:
<?php
return [
'service_manager' => [
'factories' => [
'Rentals\\Validator\\ExistentialQuantification' => 'Rentals\\Validator\\ExistentialQuantificationFactory'
]
]
];
?>
What if you change your config entry like the following example?
return [
'validators' => [
'factories' => [
ExistentialQuantification::class => ExistentialQuantificationFactory::class,
],
],
];
This change will result in further changes for your factory, because the service locator for the entity manager differs from the one you injected.
namespace Application\Validator\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\MutableCreationOptionsTrait;
use Zend\ServiceManager\ServiceLocatorInterface;
class ExistentialQuantificationFactory implements FactoryInterface, MutableCreationOptionsInterface
{
use MutableCreatinOptionsTrait;
public function createService(ServiceLocatorInterface $serviceLocator)
{
$parentLocator = $serviceLocator->getServiceLocator();
if (! isset($this->creationOptions['object_manager'])) {
$this->creationOptions['object_manager'] = 'doctrine.entitymanager.orm_default';
}
$objectManager = $parentLocator->get($this->creationOptions['object_manager']);
$objectRepository = $objectManager->getRepository($this->creationOptions['entity_class']);
return new ExistentialQuantification(ArrayUtils::merge(
$this->options, [
'objectManager' => $objectManager,
'objectRepository' => $objectRepository
]
));
}
}
What I 've done here? First I implemented the MutableCreationOptionsTrait class. This trait implements the needed functions for working with creation options. But this is just a little hint for avoiding unnecessary work.
Because of setting the validator class as validator in the config, we have to use the parent service locator for getting the entity manager. The inherited service locator just provides access to validators.
Now you can try to access your validator in your controller like in the following examaple.
$validator = $this->getServiceLocator()
->get('ValidatorManager')
->get(ExistentialQuantification::class, [
'entity_class' => YourEntityClass::class,
]);
\Zend\Debug\Debug::dump($validator, __METHOD__);
The validator manager should return your validator so that you can test it.

FormElementError for login failed

I am very new to Zend Framework 2. When I try to login on false credentials it don't show any error. So what should be the code to display FormElementError in this case.
My LoginFilter.php is given below:
use Zend\InputFilter\InputFilter;
class LoginFilter extends InputFilter
{
public function __construct()
{
$this->add(array(
'name' => 'email',
'required' => true,
'validators' => array(
array(
'name' => 'EmailAddress',
'options' => array(
'domain' => true,
),
),
),
));
$this->add(array(
'name' => 'password',
'required' => true,
//'validators' => array(),
));
}
}
So this is how I do it with a custom InputFilter. I apply the setMessage to the Zend-Validator, which is being stuffed into the ValidatorChain, via setMessage().Below you can see $emailDoesNotExist->setMessage('This e-mail address is already in use'); is here I set my error message. You can also do it to like StringLength variable ($stringLength).
namespace User\InputFilter;
use Zend\Db\Adapter\Adapter;
use Zend\Filter\FilterChain;
use Zend\Filter\StringTrim;
use Zend\I18n\Validator\Alnum;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\Validator\Db\NoRecordExists;
use Zend\Validator\EmailAddress;
use Zend\Validator\Identical;
use Zend\Validator\Regex;
use Zend\Validator\StringLength;
use Zend\Validator\ValidatorChain;
class AddUser extends InputFilter
{
/**
*
* #var InputFilter $dbAdapter
*/
protected $dbAdapter;
public function __construct(Adapter $dbAdapter)
{
$this->dbAdapter = $dbAdapter;
$firstName = new Input('first_name');
$firstName->setRequired(true);
$firstName->setValidatorChain($this->getNameValidatorChain());
$firstName->setFilterChain($this->getStringTrimFilterChain());
$lastName = new Input('last_name');
$lastName->setRequired(true);
$lastName->setValidatorChain($this->getNameValidatorChain());
$lastName->setFilterChain($this->getStringTrimFilterChain());
$email = new Input('email');
$email->setRequired(true);
$email->setValidatorChain($this->getEmailValidatorChain());
$email->setFilterChain($this->getStringTrimFilterChain());
$password = new Input('password');
$password->setRequired(true);
$password->setValidatorChain($this->getPasswordValidatorChain());
$password->setFilterChain($this->getStringTrimFilterChain());
$repeatPassword = new Input('repeat_password');
$repeatPassword->setRequired(true);
$repeatPassword->setValidatorChain($this->getRepeatPasswordValidatorChain());
$repeatPassword->setFilterChain($this->getStringTrimFilterChain());
$this->add($firstName);
$this->add($lastName);
$this->add($email);
$this->add($password);
$this->add($repeatPassword);
}
/**
* Gets the validation chain for the first name and last name inputs
*
* #return ValidatorChain
*/
protected function getNameValidatorChain()
{
$stringLength = new StringLength();
$stringLength->setMin(2);
$stringLength->setMax(50);
$validatorChain = new ValidatorChain();
$validatorChain->attach(new Alnum(true));
$validatorChain->attach($stringLength);
return $validatorChain;
}
/**
* Gets the validation chain for the email input
*
* #return ValidatorChain
*/
protected function getEmailValidatorChain()
{
$stringLength = new StringLength();
$stringLength->setMin(2);
$stringLength->setMax(50);
$emailDoesNotExist = new NoRecordExists(
array(
'table' => 'user',
'field' => 'email',
'adapter' => $this->dbAdapter
)
);
$emailDoesNotExist->setMessage('This e-mail address is already in use');
$validatorChain = new ValidatorChain();
$validatorChain->attach($stringLength, true);
$validatorChain->attach(new EmailAddress(), true);
$validatorChain->attach($emailDoesNotExist, true);
return $validatorChain;
}
/**
*
* #return ValidatorChain
*/
protected function getPasswordValidatorChain()
{
$stringLength = new StringLength();
$stringLength->setMax(6);
$oneNumber = new Regex('/\d/'); //checking to make sure it has at least one number
$oneNumber->setMessage('Must contain at least one number');
$validatorChain = new ValidatorChain();
$validatorChain->attach($stringLength);
$validatorChain->attach($oneNumber);
return $validatorChain;
}
/**
*
* #return ValidatorChain
*/
protected function getRepeatPasswordValidatorChain()
{
$identical = new Identical();
$identical->setToken('password'); // Name of the input whose value to match
$identical->setMessage('Passwords must match');
$validatorChain = new ValidatorChain();
$validatorChain->attach($identical);
return $validatorChain;
}
/**
*
* #return \User\InputFilter\FilterChain
*/
protected function getStringTrimFilterChain()
{
$filterChain = new FilterChain();
$filterChain->attach(new StringTrim());
return $filterChain;
}
}

Dynamic generated form with Zend Framework 2

I'm creating ZF2 Poll Module. I have poll with many questions. Every question has answers that can be multiple answers or single answer(Radio or MultiCheckbox). How to create a dynamic form that I can show to front-end?
This is what I've tried, but the form doesn't validate correctly...
module\Polls\src\Polls\Form\PollFillingQuestionsForm.php
<?php
namespace Polls\Form;
use Zend\Form\Form;
use Polls\Form\Fieldset\PollFillingQuestionAnswerFieldset;
use Polls\Form\Fieldset\PollFillingQuestionFieldset;
class PollFillingQuestionsForm extends Form {
public function __construct($questionsObject) {
parent::__construct('questionsForm');
$questionsFieldset = new PollFillingQuestionFieldset('questions');
//$questionsObject is array of question objects.
foreach ($questionsObject as $questionObject) {
$fieldset = new PollFillingQuestionAnswerFieldset($questionObject->id, array(), $questionObject);
$questionsFieldset->add($fieldset);
}
$this->add($questionsFieldset);
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Submit Poll',
'class' => 'btn btn-success',
),
));
}
}
module\Polls\src\Polls\Form\Fieldset\PollFillingQuestionAnswerFieldset.php
<?php
namespace Polls\Form\Fieldset;
use Polls\Model\QuestionAnswer;
use Zend\Form\Fieldset;
use Zend\Stdlib\Hydrator\ArraySerializable;
class PollFillingQuestionAnswerFieldset extends Fieldset {
public function __construct($name, $options, $questionObject) {
parent::__construct($name, $options);
$question = $questionObject;
$this->setLabel($question->title);
$type = 'Radio';
$elementType = 'radio';
switch ($question->answer_type) {
case 'many':
$type = 'MultiCheckbox';
$elementType = 'checkbox';
break;
case 'one':
$type = 'Radio';
$elementType = 'radio';
break;
default:
$type = 'Radio';
$elementType = 'radio';
break;
}
$this->setHydrator(new ArraySerializable())
->setObject(new QuestionAnswer());
$answers = $question->getAnswers();
$answerValues = array();
foreach ($answers as $answer) {
$answerValues[$answer->id] = $answer->title;
}
$this->add(array(
'name' => 'answer',
'type' => $type,
'options' => array(
'type' => $elementType,
'value_options' => $answerValues,
),
));
}
}
I've done this in the past, with a clean Factory strategy you can inject the dependencies into your form and your input filter. The magic lies in your Factories.
Start by wiring things in your service manager config:
'form_elements' => [
'factories' => [
DynamicForm::class => DynamicFormFactory::class,
],
],
'input_filters' => [
'factories' => [
DynamicInputFilter::class => DynamicInputFilterFactory::class,
],
],
First task is to get your FormFactory done up right.
class DynamicFormFactory implements FactoryInterface, MutableCreationOptionsInterface
{
/**
* #var array
*/
protected $options;
/**
* Set creation options
*
* #param array $options
* #return void
*/
public function setCreationOptions( array $options )
{
$this->options = $options;
}
/**
* {#inheritdoc}
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
/**
* #var \Zend\Form\FormElementManager $serviceLocator
* #var \Zend\ServiceManager\ServiceManager $serviceManager
*/
$serviceManager = $serviceLocator->getServiceLocator();
try
{
$options = /* set up your form's config, you have the service manager here */;
$form = new DynamicForm( $options );
$form->setInputFilter( $serviceManager->get('InputFilterManager')->get( DynamicFormFilter::class, $options ) );
}
catch( \Exception $x )
{
die( $x->getMessage() );
}
return $form;
}
}
Then, react to $options in your DynamicInputFilterFactory through the MutableCreationOptionsInterface implementation. You generally don't want forms and filters to be 'option aware', let the factories take care of that.
class DynamicInputFilterFactory implements FactoryInterface, MutableCreationOptionsInterface
{
protected $options;
/**
* Set creation options
*
* #param array $options
* #return void
*/
public function setCreationOptions( array $options )
{
$this->options = $options;
}
public function createService( ServiceLocatorInterface $serviceLocator )
{
/* do stuff with $this->options */
return new DynamicInputFilter(
/* pass your transformed options */
);
}
}
Next, all you have to do is create your form and input filter per what was passed to them through MutableOptions. Set your dependencies in __construct (don't forget to call parent::__construct) and initialize your form in init per the options passed in.
I suspect you have a good base in ZF2, so I'll stop here. This ought to get you on your way. Take-aways are MutableCreationOptionsInterface and separating your InputFilter and Form construction, combining the two in your Form Factory.

Zend Framework 2 Service Manager Dependency Injection

My application is a collection of POPO's and I'm trying to wire these POPO's up using the Zend Framework 2 Service Manager.
To illustrate my problem, take the following example:
$config = array(
'services' => array(
'my.app.serviceA' => new \My\App\Services\ServiceA(),
'my.app.serviceB' => new \My\App\Services\ServiceB(),
'my.app.manager.task' => new \My\App\Manager\TaskManager(),
),
);
My TaskManager class looks something like this:
class TaskManager {
protected $serviceA;
protected $serviceB;
public function setServiceA( \My\App\Service\ServiceA $serviceA )
{
$this->serviceA = $serviceA;
}
public function setServiceB( \My\App\Service\ServiceB $serviceB )
{
$this->serviceB = $serviceB;
}
}
As you can see, the TaskManager class has dependencies on both ServiceA and ServiceB. How do inject those services into my.app.manager.task using the Service Manager configuration using the service names defined for both ServiceA and ServiceB?
UPDATE:
I'm beginning to believe that I shouldn't be using the ServiceManager component for my purposes at all but that I should be using the Zend DI component instead.
I get the impression that the ServiceManager is a ZF2 "framework" component whereas Zend\DI seems to be more of a generic all purpose DiC. Hence, this might be the reason of ServiceManager's tied relationship with the MVC and ModuleManager components (which also seem to be "framework" components).
Maybe someone could clarify?
in module.config.php The Service Manager can be configured in 7 different ways:
return array(
// instantiate the class for you when needed
'invokables' => array(
'commentController' => '\Comment\Controller\CommentController';
),
// Aliasing a name to a known service name
'aliases' => array(
'Comment\Service' => 'commentService';
),
// configure the instance of the object
'factories' => array(
'commentController' => function ($sm) {
$locator = $sm->getServiceLocator();
$controller = $locator->get('commentController');
$controller->setCommentService($locator->get('Comment\Service'));
return $controller;
}
),
// register already instantiated objects
'services' => array(
'commentController' => new \Comment\Controller\CommentController(),
),
//factory instance that can create multiple services based on the name supplied to the factory.
'abstract_factories' => array(
'SomeModule\Service\FallbackFactory',
),
// initialize the service whenever service created
'initializers' => array(
function ($instance, $sm) {
if ($instance instanceof \Comment\Controller\CommentController){
$instance->setCommentService($sm->get('Comment\Service'));
}
}
),
// indicating whether or not a service should be shared
'shared' => array(
'commentController' => false,
),
);
and in Module.php
public function getControllerConfig() {
return array(
'factories' => array(
'commentController' => function ($sm) {
$controller = new \Comment\Controller\CommentController();
$locator = $sm->getServiceLocator();
$controller->setCommentForm($locator->get('commentForm'));
$controller->setCommentService($locator->get('commentService'));
return $controller;
}
)
);
}
and simple use in controller :
$commentService = $this->serviceLocator->get('Comment\Service');
you put this in getter or in init() method
ZF2's New Controller::init() :: phly, boy, phly
in Controller ;
$yourService = $this->getServiceLocator()->get('your_service_alias');
in View Helper :
you should send in from Module.php by constructor of viewHelper
public function getViewHelperConfig() {
return array(
'factories' => array(
'loginHelper' => function($sm) {
return new LoginHelper($sm);
}
)
}
in a calss
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
public class UseCaseBO implements ServiceLocatorAwareInterface {
protected $serviceLocator;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->serviceLocator = $serviceLocator;
}
public function getServiceLocator() {
return $this->serviceLocator;
}
// now instance of Service Locator is ready to use
public function someMethod() {
$table = $this->serviceLocator->get('your_service_alias');
//...
}
}
for me, the best way is to create a class factory and use the factoryInterface, like this :
return array(
'service_manager' => array(
'factories' => [
'Task' => 'Application\TaskFactory',
],
'invokables' => array(
'Task'=> 'Application\Task',
'ServiceA'=> 'Application\ServiceA',
'ServiceB' => 'Application\ServiceB'
)
),
);
And a factory class :
class TaskFactory implements FactoryInterface {
/** #var ServiceLocatorInterface $serviceLocator */
var $serviceLocator;
public function createService(ServiceLocatorInterface $serviceLocator) {
$sl = $this->serviceLocator = $serviceLocator;
// you can get your registered services
$serviceA = $sl->get('ServiceA');
$serviceB = $sl->get('ServiceB');
// You can build your class using the class loader
$task = new Application\Task();
// Or the Service Locator Again
$task = $sl->get('Task');
return $task;
}
}
You can implement the factory interface on your Task class. I prefer to have control on what I'm building.

How to forward data to another action using Forward Plugin and read it there in Zend Framework 2?

I have two actions in a controller: actionA() and actionB(). Dependent on a condition the actionA() should return a ViewModel object or be forwarded to actionB() (and return its result):
class MyController extends AbstractActionController {
public function aAction() {
...
$data = ...
...
if (...) {
$result = new ViewModel(array(
'data' => $data,
));
} else {
$result = $this->forward()->dispatch('MyModule\Controller\My', array(
'action' => 'b',
));
}
return $result;
}
I tried it with
$result = $this->forward()->dispatch('MyModule\Controller\My', array(
'action' => 'b',
'data' => $data,
));
But I have no idea, how to fetch this data now.
I'm sure, it's possible. How can I do it?
public function bAction() {
...
// so:
$params = $this->params()->fromRoute();
// or so:
$params = $this->getEvent()->getRouteMatch()->getParams();
...
}

Resources