Zend-Framework 2 pagination join tables - zend-framework2

I need to add a pagination in this code:
$select = new \Zend\Db\Sql\Select ;
$select->from('school');
$select->join('school_parent','school.school_parent_id = school_parent.school_parent_id');
$resultSet = $this->tableGateway->selectWith($select);
return $resultSet;
I tried this example, but I can't do it with the join table.
Anyone can help me?

public function fetchAll($paginated=false)
{
if($paginated) {
// create a new Select object for the table album
$select = $this->getallAlbum();
// create a new result set based on the Album entity
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
// create a new pagination adapter object
$paginatorAdapter = new DbSelect(
// our configured select object
$select,
// the adapter to run it against
$this->tableGateway->getAdapter(),
// the result set to hydrate
$resultSetPrototype
);
$paginator = new Paginator($paginatorAdapter);
return $paginator;
}
$resultSet = $this->tableGateway->select();
return $resultSet;
}
function getallAlbum(){
$sql = new Select();
$sql->from('album')->columns(array('id', 'artist', 'title'))->join('albumcategory', 'album.catId = albumcategory.catId', array('catName' => 'catName'), Select::JOIN_LEFT);
return $sql;
}

Pagination should work fine with joins. This is what I have, similar to an example you provided:
$select = new \Zend\Db\Sql\Select ;
$select->from('school');
$select->join('school_parent','school.school_parent_id = school_parent.school_parent_id');
return new \Zend\Paginator\Paginator(
new \Zend\Paginator\Adapter\DbSelect(
$select,
$this->tableGateway->getAdapter()
)
);
Please post an exact error that you are getting if the above doesn't work.

Thank you for the answer, but i tried your code, but i had this PDOException message:
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'school_parent_id'
I also tried, to adapat my "join tables" with the example of Rob Allen:
public function fetchAll($paginated=false)
{
if($paginated) {
// create a new Select object for the table album
$select = new \Zend\Db\Sql\Select ;
$select->from('school');
$select->join('school_parent','school.school_parent_id = school_parent.school_parent_id');
// create a new result set based on the Album entity
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new School());
// create a new pagination adapter object
$paginatorAdapter = new DbSelect(
// our configured select object
$select,
// the adapter to run it against
$this->tableGateway->getAdapter(),
// the result set to hydrate
$resultSetPrototype
);
$paginator = new Paginator($paginatorAdapter);
return $paginator;
}
$resultSet = $this->tableGateway->select();
return $resultSet;
}
But the result is the same.

// create a new Select object for the table album
$select = new \Zend\Db\Sql\Select ;
$select->from('school');
$select->join('school_parent','school.school_parent_id = school_parent.school_parent_id');
//change this like the following
// create a new Select object for the table album
$select = $this->yourFunction();
//and define yourFunction like
function youFunction(){
$sql = new Select();
$sql->from('school')->columns(array('schoolid', 'schoolname', 'anotherfield'))->join('school_parent', 'school.school_parent_id= school_parent.school_parent_id', array('schoolName' => 'schoolName'), Select::JOIN_LEFT);
return $sql;
}

Please try the join syntax
$select->from('table1')->join('table2', 'table1 = table2', array('table2.colum_to_return1', 'table2.colum_to_return2'));

Example pagination and sort Url
https://github.com/bigemployee/zf2-tutorial-paginate-sort

Try with another example pagination and sorting
### module_config.php ###
'router' => array(
'routes' => array(
'album' => array(
'type' => 'segment',
'options' => array(
'route' => '/album[/:action][/:id][/page/:page][/order_by/:order_by][/:order]',
'constraints' => array(
'action' => '(?!\bpage\b)(?!\border_by\b)[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
'page' => '[0-9]+',
'order_by' => '[a-zA-Z][a-zA-Z0-9_-]*',
'order' => 'ASC|DESC',
),
'defaults' => array(
'controller' => 'Album\Controller\Album',
'action' => 'index',
),
),
),
),
),
###### AlbumController ###
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Album\Model\Album;
use Album\Form\AlbumForm;
use Zend\Db\Sql\Select;
use Zend\Paginator\Paginator;
use Zend\Paginator\Adapter\Iterator as paginatorIterator;
class AlbumController extends AbstractActionController {
protected $albumTable;
public function indexAction() {
$select = new Select();
$order_by = $this->params()->fromRoute('order_by') ?
$this->params()->fromRoute('order_by') : 'id';
$order = $this->params()->fromRoute('order') ?
$this->params()->fromRoute('order') : Select::ORDER_ASCENDING;
$page = $this->params()->fromRoute('page') ? (int) $this->params()->fromRoute('page') : 1;
$albums = $this->getAlbumTable()->fetchAll($select->order($order_by . ' ' . $order));
$itemsPerPage = 10;
$albums->current();
$paginator = new Paginator(new paginatorIterator($albums));
$paginator->setCurrentPageNumber($page)
->setItemCountPerPage($itemsPerPage)
->setPageRange(7);
return new ViewModel(array(
'order_by' => $order_by,
'order' => $order,
'page' => $page,
'paginator' => $paginator,
));
}
}

Add this line to your code:
$select->columns(array(new Expression('DISTINCT school.school_parent_id')));
OR something like this:
$select->join('school_parent','school.school_parent_id = school_parent.school_parent_id', array('sp_id' => 'school_parent_id'));

Related

How to pass the paramter values to another controller's action in ZF2

Hello friends I am new in zf2. I am creating an action in controller, all things are working correctly. When the form is valid, i would like to pass some of the values to redirect page. how can i do this? Please help me out.
My controller action is
public function studenteditAction(){
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('manager', array(
'action' => 'students'
));
}
$form = new StudentsForm();
$request = $this->getRequest();
if ($request->isPost()) {
$students = new Students();
$form->setData($request->getPost());
if ($form->isValid()) {
$students->exchangeArray($form->getData());
$table = $this->getServiceLocator()->get('Students\Model\StudentsTable');
$table->profileStudents($students);
return $this->redirect()->toRoute('manager',array('controller'=>'manager','action'=>'student-view','id'=>$id,'status' => 'profile-ready'));
}
}
return array(
'id' => $id,
'form' => $form,
);
}
I am unable to get the passed status value on controller's view.
'status' => 'profile-ready'
Thanks in advance
You need to modify your routing configuration to accept both 'id' and 'status' values.
'manager' => array(
'type' => 'Segment',
'options' => array(
'route' => '/manager[/:id][/:status]',
'defaults' => array(
'controller' => 'Application\Controller\Manager',
'action' => 'studentView',
),
'constraints' => array(
'id' => '[0-9]*',
'status' => '[a-z-]*'
),
),
),
Controller:
public function studentViewAction()
{
$id = $this->params()->fromRoute('id');
$status = $this->params()->fromRoute('status');
return new ViewModel(array('id' => $id, 'status' => $status));
}
View
<?php
echo $this->id;
echo $this->status;
?>
This is how i pass the required values to another controller's action

ZF2 form on post losing ID

I cant pass the ID from the view (or from somewhere else). This is the url:
http://zend2.com/users/user-manager/edit/6
The controller :
public function editAction()
{
if ($this->request->isPost()) {
$post = $this->request->getPost();
echo $post->user_id; exit;
$userTable = $this->getServiceLocator()->get('UserTable');
$user = $userTable->getUser($post->id);
$form = $this->getServiceLocator()->get('UserEditForm');
$form->bind($user);
$form->setData($post);
$this->getServiceLocator()->get('UserTable')->saveUser($user);
}
$userTable = $this->getServiceLocator()->get('UserTable');
$user = $userTable->getUser($this->params()->fromRoute('id'));
$form = $this->getServiceLocator()->get('UserEditForm');
$form->bind($user);
$viewModel = new ViewModel(array(
'form' => $form,
'user_id' => $this->params()->fromRoute('id')
));
return $viewModel;
}
And the view:
$form->setAttribute('action', $this->url(NULL,
array('controller' => 'users_manager', 'action' => 'edit')));
$form->setAttribute('method', 'post');
What is the proper way to pass the ID ? I know that i dont pass the ID in the view but i am not even sure that this is right.
I solved it.
$form->setAttribute('action', $this->url(NULL,
array('controller' => 'users_manager', 'action' => 'edit'),null, true));
The 4th parameter for $this->url is "$reuseMatchedParameters", it speaks for itself.
An alternative is :
$options = ['Query' => ['id' => 12]];
echo $this->url('controller' => 'users_manager', 'action' => 'edit', $options);

How do i execute multiple queries in the same function with the same adapter in ZEND 2?

This is the content of the global.php file:
return array(
'db' => array(
'driver' => 'Mysqli',
'database' => 'web_builder',
'username' => 'root',
'password' => ''
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter'
=> 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
This is the content of my model:
namespace Application\Model;
use Zend\Db\Adapter\Adapter;
use Zend\Db\TableGateway\AbstractTableGateway;
class UsersTable extends AbstractTableGateway {
public function __construct(Adapter $adapter) {
$this->adapter = $adapter;
}
public function user_login($getData,$session_id){ // manage the user's login
$email = $getData['login_email'];
$password = $getData['login_password'];
$select = $this->adapter->query ("select count(*) as counter from users where email = '$email' and password = '".md5($password)."'");
$results = $select->execute();
if ($results->current()['counter'] == 1 ){
$select->getDataSource()->getResource()->closeCursor();
$update_user = $this->adapter->query("UPDATE users SET session_id = '".$session_id."' WHERE email = '".$email."'");
$update_session = $update_user->execute();
return 1;
}else{
return 0;
}
}
}
For some reason the update query is not working. If i commented the count query it works. I observed that i cannot execute multiple queries in the same function for some God know reason :P. I'm getting this message: Statement couldn't be produced with sql: ...... . Both query works perfectly if i executed them in phpmyadmin. Can anyone explain me why this cannot work ? I'm a little desperate :| , I spent severals hours on this
It could be a formatting / preparation issue, taking a look at the manual it suggests the following format to prepare your statement:
$adapter->query('SELECT * FROM `artist` WHERE `id` = ?', array(5));
So in your case try formatting it as so:
$select = $this->adapter->query ('select count(*) as counter from users where email = ? and password = ? ', $email , md5($password) );

Create new users with the same group(s) as the user logged in

I'm trying to add new users to sfDoctrineGuard table using my own register form. This is the configure function I made:
public function configure() {
// Remove all widgets we don't want to show
unset(
$this['is_super_admin'], $this['updated_at'], $this['groups_list'], $this['permissions_list'], $this['last_login'], $this['created_at'], $this['salt'], $this['algorithm']
);
$id_empresa = sfContext::getInstance()->getUser()->getGuardUser()->getSfGuardUserProfile()->getIdempresa();
$this->setDefault('idempresa', $id_empresa);
$this->validatorSchema['idempresa'] = new sfValidatorPass();
$this->widgetSchema['first_name'] = new sfWidgetFormInputText(array(), array('class' => 'input-block-level'));
$this->widgetSchema['last_name'] = new sfWidgetFormInputText(array(), array('class' => 'input-block-level'));
$this->widgetSchema['username'] = new sfWidgetFormInputText(array(), array('class' => 'input-block-level'));
$this->widgetSchema['email_address'] = new sfWidgetFormInputText(array(), array('class' => 'input-block-level'));
$this->widgetSchema['password'] = new sfWidgetFormInputPassword(array(), array('class' => 'input-block-level'));
$this->widgetSchema['password_confirmation'] = new sfWidgetFormInputPassword(array(), array('class' => 'input-block-level'));
// Setup proper password validation with confirmation
$this->validatorSchema['password']->setOption('required', true);
$this->validatorSchema['password_confirmation'] = clone $this->validatorSchema['password'];
$this->widgetSchema->moveField('password_confirmation', 'after', 'password');
$this->mergePostValidator(new sfValidatorSchemaCompare('password', sfValidatorSchemaCompare::EQUAL, 'password_confirmation', array(), array('invalid' => 'The two passwords must be the same.')));
}
Now I need to create those new users with the same group(s) that the user logged in but I don't know how. I read this post but don't know if using getGroups() will do the job I mean setting groups_list default, any advice? What's the best way to do this?
there are several way you could do this... I'd recommend adding the groups once validation for the other fields has taken place, and the user object has been saved; so you can override the save() function of the form and add them there:
<?php
class YourUserForm extends PluginsfGuardUserForm
{
/**
* A class variable to store the current user
* #var sfGuardUser
*/
protected $current_user;
public function configure()
{
// Remove all widgets we don't want to show
unset(
$this['is_super_admin'],
$this['updated_at'],
$this['groups_list'],
$this['permissions_list'],
$this['last_login'],
$this['created_at'],
$this['salt'],
$this['algorithm']
);
// save the currrent user for use later in the save function
$this->current_user = sfContext::getInstance()->getUser()->getGuardUser();
$id_empresa = $this->current_user->getSfGuardUserProfile()->getIdempresa();;
$this->setDefault('idempresa', $id_empresa);
$this->validatorSchema['idempresa'] = new sfValidatorPass();
$this->widgetSchema['first_name'] = new sfWidgetFormInputText(array(), array('class' => 'input-block-level'));
$this->widgetSchema['last_name'] = new sfWidgetFormInputText(array(), array('class' => 'input-block-level'));
$this->widgetSchema['username'] = new sfWidgetFormInputText(array(), array('class' => 'input-block-level'));
$this->widgetSchema['email_address'] = new sfWidgetFormInputText(array(), array('class' => 'input-block-level'));
$this->widgetSchema['password'] = new sfWidgetFormInputPassword(array(), array('class' => 'input-block-level'));
$this->widgetSchema['password_confirmation'] = new sfWidgetFormInputPassword(array(), array('class' => 'input-block-level'));
// Setup proper password validation with confirmation
$this->validatorSchema['password']->setOption('required', true);
$this->validatorSchema['password_confirmation'] = clone $this->validatorSchema['password'];
$this->widgetSchema->moveField('password_confirmation', 'after', 'password');
$this->mergePostValidator(new sfValidatorSchemaCompare('password', sfValidatorSchemaCompare::EQUAL, 'password_confirmation', array(), array('invalid' => 'The two passwords must be the same.')));
}
public function save($con = null)
{
// call the parent function to perform the save and get the new user object
$new_user = parent::save($con); /* #var $user sfGuardUser */
// add our groups here by looping the current user's group collection
foreach($this->current_user->getGroups() as $group) /* #var $group sfGuardGroup */
{
// we could use $user->addGroupByName($group->name); here, but it would mean
// an extra db lookup for each group as it validates the name. we know the
// group must exist, so can just add directly
// create and save new user group
$ug = new sfGuardUserGroup();
$ug->setsfGuardUser($new_user);
$ug->setsfGuardGroup($group);
$ug->save($con);
}
// make sure we return the user object
return $new_user;
}
}
You can see I set up a class variable to store the current user, this isn't necessary, but it save having to keep calling sfContext::getInstance()->getUser()->getGuardUser(), and is good practice as your forms get more complex.
Hopefully this helps! :)

Dynamically set SELECT attribute in zend2

What I am actually doing is, fetching a list of companies from the database and passing that to the form SELECT element.
So I created a Model file, which returns an array
//=== return an array of $ID => $name of companies to use in dropdown in reports form
public function getTotalResult($table, $type, $id) {
$this->table = $table;
$select = new Select();
$spec = new Where();
$spec->equalTo('status', 1);
if ($type == 'name') {
$spec->equalTo('id', $id);
}
$select->from($this->table);
$select->where($spec);
$resultSet = $this->selectWith($select);
//$resultSet->buffer();
return $resultSet;
}
public function resultList($table){
$results = $this->getTotalResult($table, '', '');
foreach ($results as $result) {
$this->id[] = $result->id;
$this->name[] = $result->name;
}
$result = array_combine($this->id, $this->name);
return $result;
}
Then I tested this in my Controller, which returned exactly what I wanted:
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use SpangelLogin\Model\Register; // <-- Add this import
use SpangelLogin\Model\companyList; // <-- Add this import
class RegisterController extends AbstractActionController
{
protected $registerTable;
protected $companyList;
public function getcompanyList()
{
if (!$this->companyList) {
$sm = $this->getServiceLocator();
$this->companyList = $sm->get('SpangelLogin\Model\companyList');
}
return $this->companyList;
}
public function indexAction()
{
//== get list of companies
$company_table = 'rs_company';
$sector_table = 'rs_sector';
$companiesList = $this->getcompanyList()->getName($company_table, 2);
}
}
So now I want this companiesList array passed in my form's Select Element. How can I achieve that. Here is my form in which I am using select.
use Zend\Form\Form;
use Zend\Form\Element;
class SectorReportForm extends Form
{
public function __construct($name = null)
{
// we want to ignore the name passed
parent::__construct('sectorreport');
$companiesArray = $this->companiesList();
$sectorsArray = $this->sectorsList();
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/form-data');
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'company',
'attributes' => array(
'id' => 'company',
'multiple' => true,
'options' => $companiesArray,
),
'options' => array(
'label' => 'Company',
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Upload',
'id' => 'submitbutton',
'class' => 'button violet right'
),
));
}
}
From a Design-Perspective, the best approach would be to handle this via Dependency-Injection. That sneaky little buzzword that confuses people so much, but actually is nothing more but to forward data between objects :P
General Dependency-Injection for Forms can be seen looking at the following answer, as well as my Blog article
How to get data from different model for select?
Zend\Form\Element\Select and Database-Values
If you do not want to go this approach, you can handle this at the Controller level, too.
$form = new My\Form();
$select = $form->get('selectCountries');
$model = new My\Countries();
$listData = $model->getCountriesAsArray();
$select->setValueOptions($listData);
I still advise you to go the different approach ;) Keeps the controllers more clean, too, which is always a good thing. Separation of concern!

Resources