Pass a value from controller to partial in ZF2 - zend-framework

I want to pass some value from controller to view partial, basically, view partial is set using the placeholder in Application\Module.php, here is the code that does it.
<?php
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\View\Renderer\PhpRenderer;
use Zend\View\Resolver;
use Zend\ServiceManager\ServiceManager;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$eventManager->attach(\Zend\Mvc\MvcEvent::EVENT_DISPATCH, array($this, 'initBreadcrumbAndActionButtonWidget'));
$moduleRouteListener->attach($eventManager);
$serviceManager = $e->getApplication()->getServiceManager();
}
public function initBreadcrumbAndActionButtonWidget(\Zend\Mvc\MvcEvent $e)
{
$serviceManager = $e->getApplication()->getServiceManager();
$config = $serviceManager->get('config');
$viewHelperManager = $this->getViewHelperManager($e->getApplication()->getServiceManager());
$partialHelper = $viewHelperManager->get('partial');
$partial = $partialHelper('widgets/breadcrumb', array(
'config' => $config,
'actionButtons' => $config['action-buttons']
));
$placeHolder = $viewHelperManager->get('placeholder');
$placeHolder('widgets/breadcrumb')->set($partial);
}
public function getViewHelperManager($serviceManager)
{
$stack = new Resolver\TemplatePathStack(array('script_paths' => array(__DIR__ . '/view/')));
$resolver = new Resolver\AggregateResolver();
$resolver->attach($stack);
$renderer = new PhpRenderer();
$renderer->setResolver($resolver);
$viewHelperManager = $serviceManager->get('ViewHelperManager');
return $viewHelperManager;
}
public function getConfig()
{
return array_merge_recursive(
include __DIR__ . '/config/module.config.php',
);
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
It is all working good till here, however now i want to pass a value from controller to the partial widgets/breadcrumb, after several attempt i thought implementing a ViewHelper could be a solution, and i implemented following view helper.
<?php
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
class Variable extends AbstractHelper
{
protected $data;
public function __invoke()
{
return $this;
}
public function set($identifier, $data)
{
$this->data[$identifier] = $data;
return $this;
}
public function get($identifier)
{
return $this->data[$identifier];
}
}
In controller i assign the value to ViewHelper like this.
$viewHelperManager = $this->getServiceLocator()->get('ViewHelperManager');
$variable = $viewHelperManager->get('variable');
$variable->set('stack', 'overflow');
And in partial, to access the value i use the get method.
$this->variable()->get('stack');
Now my problem is that get() is rendered first hence the value set in controller has no effect.
My question is how can i make the set() gets rendered first so i can have the value in partial, or if there is any better approach of passing the value to partial please suggest.
Thanks.

Baaah, i called the view helper in wrong action, it worked when i moved the $variable->set('stack', 'overflow'); in the action where i wanted the value to pass.
Not sure if there can be a better solution, but this does the job for me to pass the value after i found no way in ZF2 that satisfies my requirement.

Related

Omnipay Paypal set store name and logo (Laravel)

How can I set the store name and logo using the Omnipay Paypal package for Laravel?
Please see my code below, until now I tried to use the method setBrandName on the gateway variable, but this method was not found. It seems like the class ExpressCheckout has such methods but is like deprecated and one should use this code and checkout procedure. Also tried to add entry to the purchase method array parameter but it didn't work.
<?php
namespace App\Http\Controllers;
..
use Omnipay\Omnipay;
class PurchaseController extends Controller
{
public $gateway;
public function __construct()
{
$this->gateway = Omnipay::create('PayPal_Rest');
$this->gateway->setClientId(...);
$this->gateway->setSecret(...);
$this->gateway->setTestMode(true);
}
protected function makePurchase(Request $request) {
try {
$items = ...;
$response = $this->gateway->purchase(array(
'amount' => $cart->getSum(),
'items' => $items,
'currency' => config('paypal.currency'),
'returnUrl' => route('payment.success'),
'cancelUrl' => route('cart'),
))->send();
if ($response->isRedirect()) {
$response->redirect(); // this will automatically forward the customer
} else {
// not successful
return $response->getMessage() . ", " . $response->getCode();
}
} catch(Exception $e) {
return $e->getMessage();
}
}
protected function purchaseCompleted(Request $request) {
...
}
}

ZF3: ServiceNotFoundException while creating a class with Abstract Factory registered in ServiceManager

I got problem with the Abstract Factories example.
I get ServiceNotFoundException while creating a class with Abstract Factory registered in the ServiceManager.
First I download zend-servicemanager with composer
composer require zendframework/zend-servicemanager
Then I run the ServiceManager example in the single file (for simplicity).
<?php
require_once 'vendor/autoload.php';
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\Factory\InvokableFactory;
use Zend\ServiceManager\Factory\FactoryInterface;
use Zend\ServiceManager\Factory\AbstractFactoryInterface;
Class that should be obtained with ServiceManager.
class A
{
public $text;
public function __construct()
{
$this->text = "Default text";
}
}
I use MyAbstractFactory from documentation.
class MyAbstractFactory implements AbstractFactoryInterface
{
public function canCreate(ContainerInterface $container, $requestedName)
{
return in_array('Traversable', class_implements($requestedName), true);
}
public function __invoke(ContainerInterface $container,
$requestedName,
array $options = null)
{
return $requestedName();
}
}
I create ServiceManager with registered Abstract Factory.
$serviceManager = new ServiceManager([
// Neither works
//'abstract_factories' => array('MyAbstractFactory')
'abstract_factories' => array( new MyAbstractFactory() )
//'abstract_factories' => array( MyAbstractFactory::class )
/*
'abstract_factories' => [
MyAbstractFactory::class => new MyAbstractFactory()
]
*/
]);
Finally I try to obtain the instance of class A.
$a = $serviceManager->get(A::class);
var_dump($a);
I get
Fatal error: Uncaught Zend\ServiceManager\Exception\ServiceNotFoundException: Unable to resolve service "A" to a factory; are you certain you provided it during configuration?
with the stack trace
.\vendor\zendframework\zend-servicemanager\src\ServiceManager.php(763): Zend\ServiceManager\ServiceManager->getFactory('A') #1
.\vendor\zendframework\zend-servicemanager\src\ServiceManager.php(200): Zend\ServiceManager\ServiceManager->doCreate('A') #2
.\script.php(53): Zend\ServiceManager\ServiceManager->get('A') #3
My formulation of the problem was wrong. #rkeet's comment made it clear.
As my objective was the working example of the Abstract Factory registration within ServiceManager, I post the single-file script where canCreate() is simplified just to check if the class exists.
<?php
// composer require zendframework/zend-servicemanager
require_once 'vendor/autoload.php';
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\Factory\AbstractFactoryInterface;
class A
{
public $text;
public function __construct()
{
$this->text = "Default text";
}
}
class MyAbstractFactory implements AbstractFactoryInterface
{
public function canCreate(ContainerInterface $container, $requestedName)
{
return class_exists($requestedName);
}
public function __invoke(ContainerInterface $container,
$requestedName,
array $options = null)
{
return new $requestedName();
}
}
$serviceManager = new ServiceManager([
//'abstract_factories' => array('MyAbstractFactory') // works
//'abstract_factories' => array( new MyAbstractFactory() ) // works
'abstract_factories' => array( MyAbstractFactory::class ) // also works
]);
try {
$a = $serviceManager->get(A::class);
var_dump($a);
echo "<br/>\n";
$b = $serviceManager->get(B::class);
var_dump($b);
} catch (Exception $e) {
echo $e->getMessage() . "<br/>\n";
echo "{$e->getFile()} ({$e->getLine()})";
}
?>
As #rkeet pointed, if someone needs the original example working, class A should implement Traversable.

ZF2 Dependent Form Fields

How can i set a input filter which is dependent from another input field.
I want to set a form field as required only when the othe form field (checkbox) is selected.
How can i handle this in zf2 ?
I use the same idea as Crisp but I prefer to do it in the Form classes instead of the controller. I think it's better to have all validators defined all together in the same place. I do it this way:
1 - All Form classes inherits from a custom BaseForm:
class BaseForm extends ProvidesEventsForm
{
private $postData;
protected function getPostData() {
return $this->postData;
}
public function __construct( $name = null, $serviceManager ) {
parent::__construct( $name );
$this->serviceManager = $serviceManager;
$this->request = $serviceManager->get( 'Application' )->getMvcEvent()->getRequest();
$this->postData = get_object_vars( $this->request->getPost() );
}
}
This way you can easily pick any value from the post, like your checkbox (you can do the same approach with the route parameters, so you'll have all the view data in your Form).
2 - In the FormEdit class that inherits from BaseForm, you pass the getPostData() value to the SomeFilter this way:
class FormEdit extends BaseForm
{
public function __construct( $name = null, $serviceManager ) {
parent::__construct( $name, $serviceManager );
$filter = new SomeFilter( $this->getPostData() );
$this->setInputFilter( $filter );
}
3 - And now just use it in the SomeFilter:
class SomeFilter extends InputFilter
{
public function __construct( $postData ) {
if ( $postData[ 'checkbox' ] ) {
$this->add( array(
'name' => 'other_input',
'required' => true,
) );
}
}
}
This way you keep the Controller clean and all the validators in the same place.
You could test if the checkbox is populated and setValidationGroup accordingly on the form before validating it in your controller action...
public function someAction()
{
$form = new MyForm; // contains name, title, checkbox, required_if_checked fields
// usual form related setup
if ($request->isPost()) {
$form->setData($request->getPost());
// see if the checkbox is checked
$checked = $this->params()->fromPost('checkbox', false);
// not checked, set validation group, omitting the dependent field
if (!$checked) {
$form->setValidationGroup(array(
'name',
'title',
'checkbox', // could probably skip this too
));
}
if ($form->isValid()) {
// do stuff with valid data
}
}
}

How to pass params from controller to Zend_Form?

I know this question is already answered here. But this doesnt work for me.
The Form is generated by using the PluginLoader:
$formClass = Zend_Registry::get('formloader')->load('Payment');
$form = new $formClass(array('someval' => $my_arr));
Payment.php:
class Form_Payment extends Zend_Form
{
protected $_someval = array();
public function init()
{
$this->setAction('payment/save');
//....
$this->addElement('multiCheckbox', 'store_id', array('label' => 'Someval:', 'required' => true, 'multiOptions' => $this->getSomeval()))
}
public function setSomeval($someval) {
$this->_someval = $someval;
}
public function getSomeval() {
return $this->_someval;
}
}
As I can see the load method only returns the class name, so new $formClass(); is equal new Form_Payment() but why this isn't accept params?
Ok I found a way by myself. I was looking for a way to inject some params while my Zend_Form was initialised. It seems the only way for this is to pass the params to the constructor - which is executed before the init method.
class Form_Payment extends Zend_Form
{
private $_someval;
public function __construct(array $params = array())
{
$this->_someval = $params['someval'];
parent::__construct();
}
public function init()
{
$this->setAction('payment/save');
//....
$this->addElement('multiCheckbox', 'store_id',
array('label' => 'Someval:',
'required' => true,
'multiOptions' => $this->_someval // passed params now available
))
}
}
You can add custom function to your form class like
class Form_Payment extends Zend_Form
{
public function init()
{
$this->setAction('payment/save');
// and so on
}
public function doSome()
{
$this->setAction('other/action');
}
}
and call it after instanciating form in controller
$form = new $formClass();
$form->doSome();

Symfony2: Delete entity through post request (improvements required)

I need some improvements about my actual way to delete entities:
public function deleteAction($path)
{
$form = $this->createFormBuilder(array('path' => $path))
->add('path')
->setReadOnly(true)
->getForm();
if ($this->getRequest()->getMethod() === 'POST') {
$form->bindRequest($this->getRequest());
if ($form->isValid()) {
$image = $this->getImageManager()->findImageByPath($path);
$this->getImageManager()->deleteImage($image);
return $this->redirect($this->generateUrl('AcmeImageBundle_Image_index'));
}
}
return $this->render('AcmeImageBundle:Image:delete.html.twig', array(
'form' => $form->createView(),
));
}
Two improvements I already found while writting:
CreateFormBuilder in extra method in controller
Hidden field and overgive extra image-entity to get rendered
Are there other thing I could make better?
Regards
(my answer is too long for the comment so i add it here)
First you have to create a Type file (generally in YourApp\YourBundle\Form\yourHandler.php), some basique code to put inside if you don't know:
<?php
namespace ***\****Bundle\Form;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManager;
use ***\****Bundle\Entity\your_entity;
class *****Handler
{
protected $form;
protected $request;
protected $em;
public function __construct(Form $form, Request $request, EntityManager $em)
{
$this->form = $form;
$this->request = $request;
$this->em = $em;
}
public function process()
{
if( $this->request->getMethod() == 'POST' )
{
$this->form->bindRequest($this->request);
if( $this->form->isValid() )
{
$this->onSuccess($this->form->getData());
return true;
}
}
return false;
}
public function onSuccess(your_entity $object)
{
// Make your stuff here (remove,....)
}
}
And in your controller i just call it this way:
if (!empty($_POST))
{
$formHandler = new *****Handler($my_form, $this->get('request'), $this->getDoctrine()->getEntityManager());
$formHandler->process();
}
Hope i'm clear enough