How to execute console command from the controller in Zend Framework 2? - zend-framework2

I have developed a CLI command in Zend Framework 2. I want to run it from the controller. How can I do this in Zend Framework 2?

You should forward your request to the specific CLI ConsoleController you have in mind. You can achieve this by using the Forward plugin. For example:
class HttpController extends AbstractActionController
{
public function indexAction()
{
// do some stuff
$response = $this->forward()->dispatch(ConsoleController::class, ['action' => 'process']);
// do stuff with your response | array
$bar = $response['foo'];
}
}
class ConsoleController extends AbstractActionController
{
public function processAction()
{
// do stuff
return ['foo' => 'bar'];
}
}
Note that I call ConsoleController::class within the first argument. You should match the way how your controllers are registred within your configuration.
return [
'controllers' => [
'factories' => [
HttpController::class => InvokableFactory::class,
ConsoleController::class => InvokableFactory::class,
],
'aliases' => [
'ConsoleController' => ConsoleController::class,
],
],
];
Note that calling $this->forward()->dispatch('ConsoleController', ['action' => 'process']) is also a valid option, as the Dispatch looks for registered controllers.

You can do it like this:
$cmd = "php filenameToRun.php";
shell_exec($cmd);
or like this:
$cmd = "pwd";
shell_exec($cmd);
or like this:
$cmd = "mkdir myNewFolder";
shell_exec($cmd);
Any regular command you put into brackets will work.

Related

Zf2 - I am not able to define the form as shared one using its name as well as alias

I am working on ZendFramework 2. I have a form which I want to be used as a shared instance. But the shared key only accepts the actual class rather then the name allocated to it. Sharing some of the code snippet for better understanding of my problem:
SampleForm.php
namespace MyProject\Form;
use Zend\Form\Form;
class Sampleform extends Form
{
public function __construct()
{
parent::__construct('sampelname');
}
/**
* Initialize the form elements
*/
public function init()
{
$this->add(
[
'type' => 'Text',
'name' => 'name',
'options' => [
'label' => 'Enter your name',
]
]
);
}
}
Defining the SampleForm in Module.php:
namespace MyProject;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\Feature\FormElementProviderInterface;
use MyProject\Form\SampleForm;
class Module implements ConfigProviderInterface, FormElementProviderInterface
{
/**
* {#inheritDoc}
*/
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
/**
* {#inheritdoc}
*/
public function getFormElementConfig()
{
return [
'invokables' => [
'MyProject\Form\SharedSampleForm' => SampleForm::class,
],
'aliases' => [
'sharedSampleForm' => 'MyProject\Form\SharedSampleForm'
],
'shared' => [
'MyProject\Form\SharedSampleForm' => true
]
];
}
}
It throws me the error like:
Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\Form\FormElementManager\FormElementManagerV2Polyfill::setShared: A service by the name "MyProject\Form\SharedSampleForm" was not found and could not be marked as shared
But it works as expected when I define my getFormElementConfig in Module.php as follows:
public function getFormElementConfig()
{
return [
'invokables' => [
'MyProject\Form\SharedSampleForm' => SampleForm::class,
],
'aliases' => [
'sharedSampleForm' => 'MyProject\Form\SharedSampleForm'
],
'shared' => [
SampleForm::class => true
]
];
}
i.e. In the shared key I provide the reference to the actual Form class name.
If the same definitions are defined under getServiceConfig() then it works as expected without throwing any such error.
Can some one please suggest/help me out how can I be able to use the service name in the shared for forms then providing the actual class reference?
getFormElementConfig() is used for defining Form Element. Not used for defining Form as service. If you wanna define this form as Service, you should define it under getServiceConfig().
Another tips, if you have make an alias, just define the Service name using it's class name.
public function getServiceConfig()
{
return [
'invokables' => [
SampleForm::class => SampleForm::class,
],
'aliases' => [
'sharedSampleForm' => SampleForm::class
],
'shared' => [
SampleForm::class => true
]
];
}
You can call the Form using the alias name like this $this->getServiceLocator()->get('sharedSampleForm');

How to use services for a form fieldset in Zend Framework 2?

I have a form (Zend\Form\Form) with some nested fieldsets (Zend\Form\Fieldset) in it. The construction is pretty similar to that in the Form Collections tutorial.
Storage\Form\MyForm
|_'Storage\Form\Fieldset\FooFieldset'
|_'Storage\Form\Fieldset\BarFieldset'
|_'Storage\Form\Fieldset\BazFieldset'
...
MyForm
class MyForm {
public function __construct()
{
...
$this->add(
[
'type' => 'Storage\Form\Fieldset\FooFieldset',
'options' => [
'use_as_base_fieldset' => true
]
]
);
}
}
FooFieldset
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct()
{
parent::__construct('foo');
$this->setHydrator(new ClassMethodsHydrator())->setObject(new Foo()); // dependencies!
}
}
It works, but the fieldset class has two dependencies in it. I want to inject them. In order to do it, I created a FooFieldsetFactory and extended the /module/MyModule/config/module.config.php by:
'service_manager' => [
'factories' => [
'Storage\Form\Fieldset\FooFieldset' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
],
],
The factory is simply being ignored. I guess, the service locator first tries to find the class by namespace and only if nothing is found, takes a look in the invokables and factories. OK. Then I created an alias:
'service_manager' => [
'factories' => [
'Storage\Form\Fieldset\FooFieldset' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
],
],
'aliases' => [
'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\FooFieldset',
],
... and tried to use it instead of Storage\Form\Fieldset\FooFieldset in my form class. But now I get an exception:
Zend\Form\FormElementManager::get was unable to fetch or create an instance for Storage\Form\Fieldset\Foo
I've also tried this directly:
'service_manager' => [
'factories' => [
'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
],
],
No effect, the same error.
And this also didn't work (the same error):
'form_elements' => [
'factories' => [
'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
],
],
So the referencing a service for a fieldset seems not to work. Or am I doing something wrong?
How to use services for form fieldsets?
UPDATE
With some debuggin I found out, that my Foo fieldset factory cannot be found, because it has not be added to the factories list of the Zend\Form\FormElementManager. Here is the place in the Zend\Form\Factory:
So my config
'form_elements' => [
'factories' => [
'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
],
],
is ignored. How to fix this?
UPDATE Additional information, how I'm creating my Form object.
/module/Foo/config/module.config.php
return [
'controllers' => [
'factories' => [
'Foo\Controller\My' => 'Foo\Controller\Factory\MyControllerFactory'
]
],
'service_manager' => [
'factories' => [
'Foo\Form\MyForm' => 'Foo\Form\Factory\MyFormFactory',
],
],
];
/module/Foo/src/Foo/Form/Factory/MyFormFactory.php
namespace Foo\Form\Factory;
use ...;
class MyFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$form = new MyForm();
$form->setAttribute('method', 'post')
->setHydrator(new ClassMethods())
->setInputFilter(new InputFilter());
return $form;
}
}
/module/Foo/src/Foo/Controller/Factory/MyControllerFactory.php
namespace Foo\Controller\Factory;
use ...;
class MyControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$fooPrototype = new Foo();
$realServiceLocator = $serviceLocator->getServiceLocator();
// $myForm = $realServiceLocator->get('Foo\Form\MyForm'); <-- This doesn't work correctly for this case. The FormElementManager should be used instead.
$formElementManager = $realServiceLocator->get('FormElementManager');
$myForm = $formElementManager->get('Foo\Form\MyForm');
return new MyController($myForm, $fooPrototype);
}
}
This issue is because you are adding your form elements in the forms __construct() method rather than init() as suggested in the documentation.
You can use a factory instead of an invokable in order to handle dependencies in your elements/fieldsets/forms.
And now comes the first catch.
If you are creating your form class by extending Zend\Form\Form, you must not add the custom element in the __construct-or (as we have done in the previous example where we used the custom element’s FQCN), but rather in the init() method:
The reason is that the new form's factory (which is used to create new elements using add()) must have the application's form element manager injected after the form's constructor has been called This form element manager instance contains all the references to your custom forms elements which are registered under the form_elements configuration key.
By calling add() in the form __construct the form factory will lazy load a new instance of the form element manager; which will be able to create all default form elements but will not have any knowledge of your custom form element.

How to hide Controller name & action name in yii2

Can anyone suggest me how to hide both controller & action name from url in yii2?
I tried by writing rules but did not work.
this is my anchor tag:
<?php echo Html::a($model->title, ['category/view/', 'type' => $model->category->urlValue,'parameter' => $model->urlValue]); ?>
MY current url is like this :
http://localhost/project/category/view/news-and-events/dosarrest-strong-performer-in-2015-forrester-wave-for-ddos-service-providers-1
But I want it like this:
http://localhost/project/news-and-events/dosarrest-strong-performer-in-2015-forrester-wave-for-ddos-service-providers-1
It finally worked by writing a rule in main.php file as follows :
'<type:[A-Za-z0-9-]+>/<param:[A-Za-z0-9 -_.]+>' => 'category/view',
YOu chould create your own UrlRule. Something like:
class CustomUrlRule extends Object implements UrlRuleInterface {
public function createUrl($manager, $route, $params)
{
$parts = explode('/', $r);
if ($route === 'category/view'
&& isset($params['type'])
&& isset($params['parameter'])
) {
$url = generate some url;
unset($params['view'], $params['parameter']);
if (count($params)) {
$url .= '?' . http_build_query($params);
}
return $url;
}
return false;
}
public function parseRequest($manager, $request)
{
//parse request url and return true if it's url for category/view
}
}
and dont forget to add to config
config/web.php:
...
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'app\components\CustomUrlRule',
],
...
],
...

event that adds a parameter to routing

Is it possible to hook up (ideally in the controller) to add an additional parameter to routing?
I know that sounds unclear and at first glance it may sounds ridiculous - because to reach the controller we already must have routing. But I want to change only default variables.
I'll try to explain what I want to achieve:
Config:
return [
'router' => [
'routes' => [
'some' => [
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => [
'route' => '/some/:project',
'defaults' => [
'__NAMESPACE__' => 'Some\Controller',
'controller' => 'Some\Controller\Some',
'action' => 'some',
'extra' => 'default-value'
],
],
]
]
]
];
Controller:
class SomeController extends AbstractActionController {
protected $project = null;
public function setEventManager(EventManagerInterface $events)
{
parent::setEventManager($events);
$controller = $this;
$events->attach(
'dispatch', function (\Zend\Mvc\MvcEvent $e) use ($controller) {
$params = $e->getRouteMatch()->getParams();
$this->project = $params['project'] ;
// and there should be something that I want to
// achieve but do not know how (and if it is possible)
if ($this->project == 1) {
// magic action which modify config default param
// "extra" from "default-value" to "changed-value"
}
return;
}, 50
);
}
protected function attachDefaultListeners()
{
parent::attachDefaultListeners();
$eventManager = $this->getEventManager();
$eventManager->attach(
\Zend\Mvc\MvcEvent::EVENT_DISPATCH,
function(\Zend\Mvc\MvcEvent $event) {
$ViewModel = $event->getResult();
if ($ViewModel instanceof \Zend\View\Model\ViewModel) {
$ViewModel->setVariable('project',$this->project);
}
},
-99);
}
public function someAction() {
echo $this->params()->fromRoute("extra"); // return "default-value";
// but i want
echo $this->params()->fromRoute("extra"); // return "changed-value";
return new ViewModel();
}
}
View
<?php
echo "project: ".$this->project;
echo $this->url('some',['project'=>1]); // result: "/some/1"
I know this seems very strange. But for some reason (readable links, seo) is necessary to me.
Are you sure, you want to change the default param?
if ($this->project == 1) {
$e->getRouteMatch()->setParam('extra', 'changed-value');
}
You can set default params globally for assembling:
$serviceLocator->get('router')->setDefaultParam('extra', 'changed-value');
There is no way to change the defaults-Property of Zend\Mvc\Router\Http\Segment
If you really need it you must extend this class (but I would not recommend that, because I think your approach is already wrong)

Zend2: Specify currency prefix?

In Zend2 you can do this:
<?php echo $this->currencyFormat(120, 'ZAR'); ?>
This will result in:
ZAR 120.00
However, I want to end up with:
R 120.00
How can I set the prefix to rather be the currency symbol, as apposed to the code? The following doesn't work (obviously):
<?php echo $this->currencyFormat(120, 'R'); ?>
Figured it out myself. Easy as this:
$helper->setCurrencyPattern('R #0.#');
So the complete code which allows me to control everything in one place (Module.php) is as follows:
class Module
{
public function getConfig()
{
return array(
'view_helpers' => array(
'factories' => array(
'currencyFormat' => function($sm)
{
$helper = new \Zend\I18n\View\Helper\CurrencyFormat;
$helper->setCurrencyCode("ZAR");
$helper->setLocale('us_ZA');
$helper->setCurrencyPattern('R #0.#');
return $helper;
},
)
),
);
}
}
Enjoy...

Resources