My application uses Zend Framework 2 and I am trying to pass some options to it when ran via command line:
php index.php generate --date="2015-01-01"
However I am getting the error: Invalid arguments or no arguments provided
My controller looks like:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class GenerateController extends AbstractActionController
{
public function indexAction()
{
$longopts = array(
'date::',
);
$opts = getopt('', $longopts);
if (isset($opts['date'])) {
$date = $opts['date'];
} else {
$date = date('Y-m-d');
}
var_dump($date);
die();
}
}
I would like the var_dump to show the date provided in the options or today's date. The script runs but just gives the above error. Any help is greatly appreciated.
My module.config.php is functioning correctly:
// Placeholder for console routes
'console' => array(
'router' => array(
'routes' => array(
'get-happen-use' => array(
'options' => array(
//php index.php get happen --verbose apache2
// add [ and ] if optional ( ex : [<doname>] )
'route' => 'generate',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'generate',
'action' => 'index'
),
),
),
)
)
),
You need to define your console params or flags in route. According documentation, your route definition should looks like
'route' => 'generate [--date=]',
for optional value flag date, or if flag date is mandatory:
'route' => 'generate --date=',
Then you can access value of this flag in controller from request (documentation):
$date = $this->getRequest()->getParam('date', null); // default null
Related
I'm working on zf2 to make one of my routes only accessible when a query string parameter is passed. Otherwise, it will not. I've added a filter on the route section but when accessing the page without the query parameter, it is still going thru.
'router' => array(
'routes' => array(
'show_post' => array(
'type' => 'segment',
'options' => array(
'route' => '[/]show/post/:filter',
'constraints' => array(
'filter' => '[a-zA-Z0-9-.]*',
),
'defaults' => array(
'controller' => 'blog_controller',
'action' => 'show'
)
),
),
),
),
http://example.com/show/post/?postId=1235 = This should work
http://example.com/show/post?postId=1235 = This should work
http://example.com/show/post/ = This should not work
http://example.com/show/post = This should not work
The way you currently have this setup you would have to structure your url like this
http://example.com/show/post/anything?postId=1235
I think what you are wanting is to structure your route like this
'route' => '[/]show/post',
Not sure what you are trying to accomplish with [/] before show though, you are making that dash optional there?
I would write it like this
'route' => '/show/post[/:filter]',
This way you can structure your urls like this
http://example.com/show/post/anything?postId=1235
or
http://example.com/show/post?postId=1235
Then in your action you can access those parameters like this
$filter = $this->params('filter');
$post_id = $this->params()->fromQuery('post_id');
or just
$post_id = $this->params()->fromQuery('post_id');
***************UPDATE***************
It looks like zf2 used to include what you are trying to do and removed it because of security reasons.
http://framework.zend.com/security/advisory/ZF2013-01
Don't try to bend ZF2 standard classes to your way. Instead write your own route class, a decorator to the segment route, which will do exactly as you please:
<?php
namespace YourApp\Mvc\Router\Http;
use Zend\Mvc\Router\Http\Segment;
use use Zend\Mvc\Router\Exception;
use Zend\Stdlib\RequestInterface as Request;
class QueryStringRequired extends Segment
{
public static function factory($options = [])
{
if (!empty($options['string'])) {
throw new Exception\InvalidArgumentException('string parameter missing');
}
$object = parent::factory($options);
$this->options['string'] = $options['string'];
return $object;
}
public function match(Request $request, $pathOffset = null, array $options = [])
{
$match = parent::match($request, $pathOffset, $options);
if (null === $match) {
// no match, bail early
return null;
}
$uri = $request->getUri();
$path = $uri->getPath();
if (strpos($path, $this->options['string']) === null) {
// query string parametr not found in the url
// no match
return null;
}
// no query strings parameters found
// return the match
return $match;
}
}
This solution is very easy to unit test as well, it does not validate any OOP principles and is reusable.
Your new route definition would look like this now:
// route definition
'router' => array(
'routes' => array(
'show_post' => array(
'type' => YourApp\Mvc\Router\Http\QueryStringRequired::class,
'options' => array(
'string' => '?postId=',
'route' => '[/]show/post/:filter',
'constraints' => array(
'filter' => '[a-zA-Z0-9-.]*',
),
'defaults' => array(
'controller' => 'blog_controller',
'action' => 'show'
)
),
),
),
),
How should I prepare my routes to deal with it, instead of addictional parts in url?
$routes = array(
/**
* Static
*/
'news' => new Zend_Controller_Router_Route('news/:page',
array('controller' => 'news', 'action' => 'index', 'page' => 1 )
),
/**
* Dynamic
*/
'thread' => new Zend_Controller_Router_Route(':slug/:page',
array('controller' => 'Thread', 'action' => 'index', 'page' => 1 )
),
e.g. example.com/thread-name-slug it shows thread with slug thread-name-slug but when I visit example.com/news it wants to show thread with slug news. I want static page here.
Thanks in advance.
The router matches routes in reverse order of their declaration. Given the request url /news, the router will attempt to match first against the route :slug/:page and, of course, finds a match, so it never gets to examine your news/:page route.
The solution is to reverse the order in which you declare the routes. Generally speaking, one wants to add generic routes before specific ones.
As the latest version of zendframework is 3.x I'll post a sample solution for Zf3, because it's not easy a complete article on zend routes.
Supouse you wanna centralize your admin requests by using only one controller; so you can check permisions, roles, etc in order to serve your site's admin pages.
We'll perform the next tasks:
Edit the "module.config.php" file to have a easy to read code.
Create a DefineRoutes.php file
Write a simple regular expression to set wildcard matching places for all posible admin tasks.
I'll supouse we creates an admin module properly registered in "modules.config.php" file
Editing the module.config.php file:
<?php
/**
* #Filename: zendframework/module/Admin/config/module.config.php
* The module required settings.
* #author: your name here
*/
return [
'controllers' => [
'factories' => include __DIR__ . '/ControllerFactories.php'
],
'router' => [
'routes' => include __DIR__ . '/DefineRoutes.php',
],
'view_manager' => ['template_path_stack' => [__DIR__ . '/../view',],],
];
Note: we do not use the close tag ?> in our files
Creating the "DefineRoutes.php" file.
<?php
/**
* #Filename: zendframework/module/Admin/config/DefineRoutes.php
* Declares site's admin routes
* #author: your name here
*/
namespace Admin;
use Zend\Router\Http\Segment;
// first a couple of useful functions to make our life easy:
// Creates a regexp to match all case-variants of a word
function freeCaseExt($toCase){
$len = strlen($toCase);
$out = '';
if($len < 1){ return $out; }
for ($i=0; $i<$len; $i++){
$s = strtolower(substr($toCase, $i, 1));
$out .= '['.$s.strtoupper($s).']';
}
return $out;
}
// To append slash child routes elsewhere
function SlashUri($controller, $action){
return [
'type' => \Zend\Router\Http\Literal::class,
'options' => [
'route' => '/',
'defaults' => ['controller' => $controller, 'action' => $action ]]];
}
$adminvariants = freeCaseExt('admin'); // to constrain our main route
// Our route family tree:
'admin' => [
'type' => Segment::class,
'options' => [
'route' => '/:admin[/:case][/:casea][/:caseb][/:casec][/:cased][/:casee][/:casef][/:caseg][/:caseh]',
'constraints' => [
'admin' => $adminvariants,
'case' => '[a-zA-Z0-9][a-zA-Z0-9_-]*',
'casea' => '[a-zA-Z0-9][a-zA-Z0-9_-]*',
'caseb' => '[a-zA-Z0-9][a-zA-Z0-9_-]*',
'casec' => '[a-zA-Z0-9][a-zA-Z0-9_-]*',
'cased' => '[a-zA-Z0-9][a-zA-Z0-9_-]*',
'casee' => '[a-zA-Z0-9][a-zA-Z0-9_-]*',
'casef' => '[a-zA-Z0-9][a-zA-Z0-9_-]*',
'caseg' => '[a-zA-Z0-9][a-zA-Z0-9_-]*',
'caseh' => '[a-zA-Z0-9][a-zA-Z0-9_-]*'
],
'defaults' => [
'controller' => Controller\AdminController::class,
'action' => 'index'
]
],
'may_terminate' => TRUE,
'child_routes' => [
'adminslash' => SlashUri(Controller\AdminController::class, 'index'),
]
],
// Now you have declared all the posible admin routes with or without
// slaches '/' at 9 deep levels using the AdminController::Index() method
// to decide wath to do.
IMPORTANT: As we defined a first level wildcard :admin a proper constraint is required or it overlaps other first level routes.
The controllers logics is a few out of skope.
Hope this idea helps somebody.
Luis
I am trying to redirect the page if condition is true I dont want to use core php function header() because I am using zend so, I have tried many things but in vain.
Here is my code.
$viewer = Engine_Api::_()->user()->getViewer();
$table = Engine_Api::_()->getItemTable('sitebusiness_business');
$select = $table->select()->where('owner_id = ?' , $viewer->getIdentity());
$result = $table->fetchAll($select);
if(count($result) == 0){
$url = Zend_Controller_Front::getInstance()->getRouter()->assemble(array('action' => 'package'), 'sitebusiness_general', true); // url is /mysite/businessitems/package
$this->_redirect($url); //Not Working ----
$this->_helper->redirector($url); //Not Working ----
$this->_redirector->gotoSimple($url); //Not Working ----
$this->_redirector->gotoUrl($url); //Not Working ----
}
Everytime I get the message: Fatal error: Call to a member function redirector() [whatever the function name is] on a non-object.
Thanks in advance.
you can use the following one to redirect in zf2
$this->redirect()->toRoute('routename');
Generaly route name is the function name in the controller.
like addEmployeeAction(), editEmployeeAction()...
which is routes defined in module.config.php
'zfcadmin' => array(
'type' => 'segment',
'options' => array(
'route' => '/admin',
'defaults' => array(
'controller' => 'ZfcAdmin\Controller\AdminController',
'action' => 'index',
),
),
'may_terminate' => true,
I would like to make navigation buttons in my view, for example index.phtml but it's not working. I did know how to do it in Zend1 but in Zend2 I have a problem. My code looks like this (file index.phtml):
$container = new \Zend\Navigation\Navigation($tableActions);
var_dump($container);
echo '<div class="table-column">';
echo $this->navigation($container)->menu();
echo '</div>';
Variable $tableAction looks like this:
public $tableActions = array(
array(
'label' => 'On/Off',
'module' => 'import',
'controller' => 'import',
'action' => 'setstatus',
'params' => array('id' => null),
),
);
I did not get any error, just whole site die on this line. var_dump returns object(Zend\Navigation\Navigation) so it's fine so far. Problem is, how to show it...
The navigation pages have dependencies which aren't being met by just creating a new container class in a view. The Mvc page needs a RouteStackInterface (Router) instance and a RouteMatch instance. Similarly Uri pages need the current Request instance.
You can see this clearly if you take a look at the Zend\Navigation\Service\AbstractNavigationFactory and its preparePages and injectComponents methods.
The view is not the right place to be instantiating menus, instead put the menu configuration spec in your module.config.php...
<?php
return array(
'navigation' => array(
'table_actions' => array(
array(
'label' => 'On/Off',
'module' => 'import',
'controller' => 'import',
'action' => 'setstatus',
'params' => array('id' => null),
),
),
),
);
Write a factory extending the AbstractNavigationFactory class and implement the getName() method which returns the name of your menu spec key (table_actions in this example)
<?php
namespace Application\Navigation\Service;
use Zend\Navigation\Service\AbstractNavigationFactory;
class TableActionsFactory extends AbstractNavigationFactory
{
/**
* #return string
*/
protected function getName()
{
return 'table_actions';
}
}
Map the factory to a service name in the service_manager spec of module.config.php ...
<?php
return array(
'navigation' => array(// as above ... )
'service_manager' => array(
'factories' => array(
'TableActionsMenu' => 'Application\Navigation\Service\TableActionsFactory',
),
),
);
Now you can call the view helper using the service name TableActionsMenu you just mapped
<div class="table-column">
<?php echo $this->navigation('TableActionsMenu')->menu(); ?>
</div>
Finally, if, as I suspect, you need to change an attribute of the page depending on the view, you can do that too, navigation containers have find* methods which can be accessed from the navigation helper and used to retrieve pages.
Here's an example looking for the page with a matching page label, then changing it before rendering (obviously not an ideal search param, but it gives you the idea)
$page = $this->navigation('TableActionsMenu')->findOneByLabel('On/Off');
$page->setLabel('Off/On');
// and then render ...
echo $this->navigation('TableActionsMenu')->menu();
There was a similar thread but it didn't address this exact problem so I thought I would create a new thread to make this clear.
Code/problem explained:
This is my SystemsController.
Here I have viewsystemAction(). This is loaded, and from the view a script is called to load ajaxviewsystemAction().
In the viewsystemAction(), I use the params function to get the "id" parameter from my route. For example systems/viewsystems/222 ( <-- 222 is id. ). I echo this out just to show that it is correct, and it gives the correct id for the page.
The ajaxviewsystemsAction is kind of where the problem is. This is because the route of ajaxviewsystemsAction id is not the same as viewsystemsAction. If I echo the id from the params here, it displays as 0.
Although if i go to this page in the browser for example ajaxviewsystemsAction/222 then it is working perfectly. However, nothing is rendered here except the ajax table, as remember it is called in viewsystemAction from a script.
What i need to do, is somehow pass the id route value from viewsystemAction into ajaxviewsystemAction, to both use this same route id.
This is so when someone clicks on the link, it loads viewsystems/222, the correct id is executed in both viewsystemsAction and ajaxviewsystemsAction.
Is this possible? If not how could i make something similar like this. I am using zftable which integrates ajax. I need to pass this id parameter through into a query.
private function getSourceViewAllSystems($id)
{
return $this->getSystemsTable()->fetchViewAllSystems($id); //paramater to model which executes sql ->where system = $id
}
public function viewsystemAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
echo $id; //i see the correct id for example 220 from the route in the browser
}
public function ajaxviewsystemAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
echo $id; //to see the id of the route with the ajax page
//displays 0 and not the route id from the viewsystemAction
$table = new TableExample\Advance();
$table->setAdapter($this->getDbAdapter())
->setSource($this->getSourceViewAllSystems($id))
->setParamAdapter($this->getRequest()->getPost())
;
return $this->htmlResponse($table->render('custom' , 'custom-b2'));
}
--- update ---
<?php
return array(
'controllers' => array(
'invokables' => array(
'Systems\Controller\Systems' => 'Systems\Controller\SystemsController',
),
),
// The following section is new and should be added to your file
'router' => array(
'routes' => array(
'systems' => array(
'type' => 'segment',
'options' => array(
'route' => '/systems[/][:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Systems\Controller\Systems',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'systems' => __DIR__ . '/../view',
),
),
);