Using paginator - zend-framework

I'm using paginator first time, and now I have some questions how to and where to do things.
Here my ideas and underneath some code.
I understood to object paginator in my controller action, give the object to my datacollection an give this to my ViewModel Object.
Because I get an error about the ArrayAdapter I will post also the error and my use statements in my controller class.
error:
Class 'Stammdaten\Controller\ArrayAdapter' not found
xyzController.php
use Zend\Paginator\Adapter\AdapterInterface;
use Zend\Paginator\Paginator;
use Zend\Paginator\ScrollingStyle\Sliding;
public function indexAction()
{
$page = $this->params()->fromRoute('page');
$paginator= new Paginator(new ArrayAdapter($this->mandantTable->Ansprechpartnerjoin()->toArray()));
$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage(20);
$paginator->setPageRange(5);
return new ViewModel([
'paginator' => $paginator,
]);
}
First question here: Is this adapter the right one, because I give a tableadapter collection or do I have to change to another adapter?
I modified my routing for using paginator like follows:
module.config.php
'router' => [
'routes' => [
'mandant' => [
'type' => Segment::class,
'options' => [
'route' => '/mandant[/:action[/:id[/:page]]]',
'constraints' => [
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[a-zA-Z0-9\-]*',
],
'defaults' => [
'controller' => Controller\MandantController::class,
'action' => 'index',
],
],
],
'paginator' => [
'type' => 'segment',
'options' => [
'route' => '/list/[page/:page]',
'defaults' => [
'page' => 1,
],
],
],
],
],
Next question here: is it needed to modify the route for MandantController as well or would it be enough to have the paginator route?
And here part of my viewscript, index.phtml:
foreach ($this->paginator->getCurrentItems() as $mandant) :?>
<tr>
<td><?= $this->escapeHtml($mandant['somefield']) ?></td>
</tr>
<?php endforeach;
echo $this->paginator, 'Sliding', 'pagination/control', array('route' => 'mandant')
?>
Next Question here, I gave the paginator object to an array, because of the arrayadapter, but I really would prefer to have an object rather than an array, is this possible or do I have to use another adapter?
And last question: Is everything done or am I missing something somewhere?
EDIT 1:
I tried a bit further, and have now changed to the DbSelect Adapter, but it seems like my tableadapter won't be accepted. This is what I changed now:
xyzController.php
$page = $this->params()->fromRoute('page');
$countQuery = new Select();
$countQuery
->from('t_mandant')
->columns([ DbSelect::ROW_COUNT_COLUMN_NAME => 'id' ]);
$paginator= new Paginator(new DbSelect($this->mandantTable->Ansprechpartnerjoin(),null, $countQuery));
$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage(20);
$paginator->setPageRange(5);
return new ViewModel([
'paginator' => $paginator,
]);
The error message:
Argument 1 passed to Zend\Paginator\Adapter\DbSelect::__construct()
must be an instance of Zend\Db\Sql\Select, instance of
Zend\Db\ResultSet\ResultSet given
This is of course right, my question is, what do I have to do, to give the tableAdapter instance to the paginator constructor.

Now I changed to another solution. I construct the paginator in my model.
It now looks like follows:
$resultSetprototype=new ResultSet();
$resultSetprototype->setArrayObjectPrototype(new Mandant());
$paginatorAdapter= new DbSelect($select, $this->tableGateway->getAdapter(), $resultSetprototype);
$paginator=new Paginator($paginatorAdapter);
return $paginator;
Now it works quite well.

Related

ReCaptcha with ZF3 wrong value

I use the newest Zend Framework available, and now i want to use ReCaptcha on my form. Together with some other elements, the ReCaptcha element is defined by:
$pubKey = 'replaced by the actual pubkey';
$privKey = 'replaced by the actual privkey';
$recaptcha = new \Zend\Captcha\ReCaptcha(['pubKey' => $pubKey, 'privKey' => $privKey]);
$this->add(array(
'attributes' => array (
'data-role' => 'none',
),
'name' => 'captcha',
'type' => 'captcha',
'options' => array(
'captcha' => $recaptcha,
),
));
This code validates the form in the controller:
public function contactAction () {
$contactForm = new ContactForm();
if($this->getRequest()->isPost()) {
$contactForm->setData($this->getRequest()->getPost());
if($contactForm->isValid()){
// send actual mail
return $this->redirect()->toRoute('page', ['lang' => $this->translator->getLocale(), 'page' => 'contact']);
}
}
$viewModel = new ViewModel ([
'contactForm' => $contactForm
]);
$viewModel->setTemplate('application/index/contact');
return $viewModel;
}
And finally, this is the view:
<?= $this->form($contactForm); ?>
To me, this code is pretty straightforward and should work. However, on sending the contact form, it displays the error 'Captcha value is wrong'. Any ideas?
You have to name the element according to the rules of Google. With this code, it works like a breeze
$pubKey = 'replaced by the actual pubkey';
$privKey = 'replaced by the actual privkey';
$recaptcha = new \Zend\Captcha\ReCaptcha(['pubKey' => $pubKey, 'privKey' => $privKey]);
$this->add(array(
'name' => 'g-recaptcha-response',
'type' => 'captcha',
'options' => [
'captcha' => $recaptcha,
]
));
Anyways, as always the ZF Docs are very short and lack examples.

ZF2 access to config in router configuration

i route by hostname and i want to get my domain name by local.php config file in config/autoload in zf2
i know how should i get configs in controller,
but i dont know how can i get it in my router configuration file
i comment what i want in my code
'router' => array(
'routes' => array(
'advertise' => array(
'type' => 'Hostname',
'options' => array(
'route' => 'www.myhome.com', // here i want to get my domain by config
'defaults' => array(
'controller' => 'Advertise\Controller\Advertise',
'action' => 'index',
),
),
.............
You can use the API of the 'router' service (an instance of Zend\Mvc\Router\Http\TreeRouteStack) and add a route dynamically.
How you attach the route to the route stack is up to you, you could extend the default router factory Zend\Mvc\Service\RouterFactory with your own routes from config.
use MyModule\Mvc\Service;
use Zend\Mvc\Service\RouterFactory;
use Zend\ServiceManager\ServiceLocatorInterface;
class MyRouterFactory extends RouterFactory
{
public function createService(ServiceLocatorInterface $serviceLocator, $cName = null, $rName = null)
{
$serviceManager = $serviceLocator->getServiceLocator();
$router = parent::createService($serviceLocator, $cName, $rName);
$config = $serviceManager->get('config');
$router->addRoute('advertise', [
'type' => 'hostname',
'options' => [
'route' => $config['some_other_config_key'],
'defaults' => [
'controller' => 'Advertise\Controller\Advertise',
'action' => 'index'
]
],
'priority' => 123
]);
return $router;
}
}
Remember to register it with the name Router in module.config.php to replace the default implementation.
'service_manager' => [
'factories' => [
'Router' => 'MyModule\Mvc\Service\MyCustomRouterFactory',
],
],
The nice thing with this approach is that the routers construction is all kept in one place; also as you are adding it with a factory class
you have access to other services should you need them.
Alternatively, you could add it via an event, although being triggered via the event manager, this method would likely be more resource intensive.
namespace MyModule;
use Zend\ModuleManager\InitProviderInterface;
use Zend\ModuleManager\ModuleManagerInterface;
use Zend\Mvc\Application;
use Zend\Mvc\MvcEvent;
class Module implements InitProviderInterface
{
// init is called when the module is initilised, we can use this to add a listener to the
// 'bootstrap' event
public function init(ModuleManagerInterface $manager)
{
$eventManager = $manager->getEventManager()->getSharedManager();
$eventManager->attach(Application::class, MvcEvent::EVENT_BOOTSTRAP, [$this, 'addRoutes']);
}
public function addRoutes(MvcEvent $event)
{
$serviceManager = $event->getApplication()->getServiceManager();
$router = $serviceManager->get('Router');
$config = $serviceManager->get('Config');
$router->addRoute('advertise', [
'type' => 'hostname',
'options' => [
'route' => $config['some_other_config_key'],
'defaults' => [
'controller' => 'Advertise\Controller\Advertise',
'action' => 'index'
]
],
'priority' => 123
]);
}
}

Can't manage to make a static page with Zend Framework (about us)

I'm trying to make a website using the Zend Framework because I heard it was really good and I'd like to experiment with frameworks, but I have a simple problem driving me crazy.
I'd like to make a simple mywebsite.com/about page with static content because there is no need to do anything else than display html.
I made an About controller, the phtml associated with it, but when I try to go to /about, I get a 404 error followed by:
The requested controller could not be mapped to an existing controller class.
Controller:
not-found(resolves to invalid controller class or alias: not-found)
So I checked my routing file:
'router' => array(
'routes' => array(
'about' => array(
'type' => 'segment',
'options' => array(
'route' => '/about',
),
'defaults' => array(
'controller' => 'About\Controller\About',
'action' => 'index',
),
),
),
),
so if I'm not wrong this is supposed to call the About controller that I made, but can't manage to find the problem.
If someone could help me understand what I missed or what I didn't get with Zend, I will be very glad.
EDIT: The version of Zend is 2.x if that changes anything
#
EDIT 2: I found the solution thanks to the help of James Kent
My routing file seemed to be wrong, here is the new one :
'router' => array(
'routes' => array(
'about' => array(
'type' => 'Literal',
'options' => array(
'route' => '/about',
'defaults' => array(
'__NAMESPACE__' => 'About\Controller',
'controller' => 'About',
'action' => 'index',
),
),
),
),
),
I also had to change the indexAction of my About controller:
class AboutController extends AbstractActionController
{
public function nolayoutAction() {
$viewModel = new ViewModel();
//$viewModel->setTerminal(true); Uncomment to disable the layout
return $viewModel;
}
public function indexAction()
{
$viewModel = $this->nolayoutAction();
return $viewModel;
}
}
I hope it will help some people.
From what I can recall, something like this should work:
$route = new Zend_Controller_Router_Route_Static(
'about',
array('controller' => 'about')
);
$router->addRoute('about', $route);
In the meantime, I'm going to look for the documentation where I originally learned about this.
Edit: As it turns out, what you may need are Custom Routes, and their documentation is over here.

Zend Navigation, how can i use it with params in the url ? I tried it with params in navigation without changes :(

I have got a problem with the zend navigation.
I use the zend navigation, and its ok when i call something like this in the url:
www.website/article_new, www.website/article_list,
www.website/friends_new, ...
But I want to call the site with some params like this:
www.website/article_new/123452/2335/45633246,
www.website/friends_new/23453/3453524/34554
I try it about to set some params, but this doesnt function.
I put the navigation in the bootstrap and in the layout I use it. Its a Navigation with some breadcumps where display:true and display:false.
Here is a code from my bootstrap:
$navigation = new Zend_Navigation(array(
array(
'label' => 'Home',
'controller' => 'index',
'action' => 'index',
'class' => 'menuF'
),
array(
'label' => 'Article',
'controller' => 'Article_List',
'id' => 'article',
'action' => 'index',
'class' => 'menu',
'pages' => array(
array(
'label' => 'Neu',
'id' => 'article',
'controller' => 'Article_New',
'action' => 'index',
'class' => 'submenu'
)
)
).....
And the code from the layout.phtml. On this code I show if the breadcump is shown or not.
foreach($container as $page) {
$par = $active;
if ($page != $active && $page->getClass()!='menu' && $page->getClass()!='menuF' && $page->getID()!=$par->getID()) {
$page->setClass('submenu');
} else {
$found = $container->findAllBy('ID', $active->getID());
foreach($found AS $p){
if($p->getClass()!='menu'&&$p->getClass()!='menuF'){
$p->setClass('sub');
}
}
}
}
echo $this->navigation()->menu()->renderMenu($this->nav);
Hope anybody can help me!
Thanks for all!
Best regards
Tom
I found myself the mistake!
I want to call something like this:
www.website/article/344435/23452345
surely this throws a mistake, because there isnt any action like 344435
with something like this
www.website/article/show/var1/2435234/var2/2345234352
its ok.
the rest is something for routing!
Big sorry to all!
Greats Tom
Try to use the route name instead of the module, controler and action system.
array(
'label' => 'Article',
'route' => 'Article_List',
'id' => 'article',
'class' => 'menu',
...
)
The router will handle all the URL parsing and return the correct variables.

Building a modular Website with Zend Framework: Am I on the right way?

I´m a little bit confused by reading all the posts and tutorials about starting with Zend, because there a so many different ways to solve a problem.
I just need some feedback about my code to know if I am on the right track.
To simply get a (hard coded) Navigation for my site (depending on who is logged in) I build a Controller Plugin with a postDispatch method:
public function postDispatch(Zend_Controller_Request_Abstract $request)
{
$menu = new Menu();
//Render menu in menu.phtml
$view = new Zend_View();
//NEW view -> add View Helper
$prefix = 'My_View_Helper';
$dir = dirname(__FILE__).'/../../View/Helper/';
$view->addHelperPath($dir,$prefix);
$view->setScriptPath('../application/default/views/scripts/menu');
$view->menu = $menu->getMenu();
$this->getResponse()->insert('menu', $view->render('menu.phtml'));
}
Is it right that I need to set the helper path again?
I did this in a Plugin Controller named ViewSetup. There I do some setup for the view like doctype, headlinks, and helper paths (This step is from the book: Zend Framework in Action).
The Menu class which is initiated looks like this:
class Menu
{
protected $_menu = array();
/**
* Menu for notloggedin and logged in
*/
public function getMenu()
{
$auth = Zend_Auth::getInstance();
$view = new Zend_View();
//check if user is logged in
if(!$auth->hasIdentity()) {
$this->_menu = array(
'page1' => array(
'label' => 'page1',
'title' => 'page1',
'url' => $view->url(array('module' => 'pages','controller' => 'my', 'action' => 'page1'))
),
'page2' => array(
'label' => 'page2',
'title' => 'page2',
'url' => $view->url(array('module' => 'pages','controller' => 'my', 'action' => 'page2'))
),
'page3' => array(
'label' => 'page3',
'title' => 'page3',
'url' => $view->url(array('module' => 'pages','controller' => 'my', 'action' => 'page3'))
),
'page4' => array(
'label' => 'page4',
'title' => 'page4',
'url' => $view->url(array('module' => 'pages','controller' => 'my', 'action' => 'page4'))
),
'page5' => array(
'label' => 'page5',
'title' => 'page5',
'url' => $view->url(array('module' => 'pages','controller' => 'my', 'action' => 'page5'))
)
);
} else {
//user is vom type 'client'
//..
}
return $this->_menu;
}
}
Here´s my view script:
<ul id="mainmenu">
<?php echo $this->partialLoop('menuItem.phtml',$this->menu) ?>
</ul>
This is working so far. My question is: is it usual to do it this way; is there anything to improve?
I´m new to Zend and I've seen deprecated tutorials on the web which often are not obvious. Even the book is already deprecated where the autoloader is mentioned.
You shouldn't be creating a new view. Since you have already created the View object in your Boostrap (and used it to render the rest of the site) you should fetch the already created view object.
If you are using Zend_Application_Resource to setup your view in the bootstrap you can fetch it like this:
$view = Zend_Controller_Front::getInstance()
->getParam('bootstrap')
->getResource('view');
This way there is no need to set the view helper path again and create another view object.
If you are not using the Zend_Application to boostrap your app you could try something like this:
$view = Zend_Layout::getMvcInstance()->getView();
Unless you are working on a relatively small side, I wouldn't do this in the controller,
since you will have to add this to many controllers.
Why not check in the bootstrap or even checking in your layout would make more sense to me although it wouldn't be proper.