I have one problem. I don't know how to use multiple table and join query in zf2.
I'm using service Manager and TableGateway for model. But in this it always use single table.
How can I use multiple table in single controller or model?
Here I'm using Module.php file and configure table gateway.
When I add another table gateway then it gives me errors.
public function getServiceConfig()
{
return array(
'factories' => array(
'User\Model\UserTable' => function($sm) {
$tableGateway = $sm->get('UserTableGateway');
$table = new UserTable($tableGateway);
return $table;
},
'UserTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
I need to insert userItems in user controller by using UseritemTable.php under the User/Model/UseritemTable. How I can achieve this?
Error message
Zend\Mvc\Controller\PluginManager::get was unable to fetch or create an instance for getUseritemTable
Updated Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'User\Model\UserTable' => function($sm) {
$tableGateway = $sm->get('UserTableGateway');
$table = new UserTable($tableGateway);
return $table;
},
'UserTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
},
'User\Model\UseritemTable' => function($sm) {
$tableGateway = $sm->get('UseritemTableGateway');
$table = new UseritemTable($tableGateway);
return $table;
},
'UseritemTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Useritem());
return new TableGateway('useritem', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
UserController.php under this userItemAction
public function userItemAction()
{
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if ($request->isPost()) {
$item = new Useritem();
$data = $request->getPost()->toArray();
$form->setData($data);
if($form->isValid()){
$item->exchangeArray($form->getData());
$this->getUseritemTable()->saveItem($item); // while saveItem cause error using getUseritemTable()
}
}
return array('form' => $form);
}
Here my code for User\Model\UseritemTable.php
namespace User\Model;
use Zend\Db\TableGateway\TableGateway;
class UseritemTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function saveItem(User $item)
{
$this->tableGateway->insert($item);
}
}
Related
I use APIGILITY to create a Web-service, I’d like to resolve a problem. I don’t have a specific database linked to my app ,the database is specified by a parameter in the URL.
For example http://sk.localhost/users-service/1, where 1 is the database’s paramaters “projet” you can see below.
It’s my database .conf:
return array(
'db' => array(
'1' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=projet;host=localhost',
'driver_option' => array(
1002 => 'SET NAMES \'UTF8\''
),
),
'2' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=cgm;host=localhost',
'driver_option' => array(
1002 => 'SET NAMES \'UTF8\''
),
));
And it’s my code to specify the database with the parameter:
class Module
{
private $id_base;
private $conf_Users_tables;
private $conf_Droits_tables;
private $data;
public function init(ModuleManager $moduleManager)
{
$events = $moduleManager->getEventManager();
$events->attach(ModuleEvent::EVENT_MERGE_CONFIG, array($this, 'initDBSConfig'));
}
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$eventManager->attach('route', array($this, 'checkRoute'));
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function checkRoute(MvcEvent $e)
{
$route = $e->getRouteMatch()->getParams();
$this->id_base = $route['id_base'];
}
public function initDBSConfig(ModuleEvent $e)
{
$conf = include __DIR__ . '/../../config/Dbs.conf.php';
$this ->data = $conf['db'];
$this->initConfTables();
}
function initConfTables()
{
$confUsers = include __DIR__ . '/../../config/Users.conf.php';
$confDroits = include __DIR__ . '/../../config/Droits.conf.php';
$this->conf_Users_tables = $confUsers;
$this->conf_Droits_tables = $confDroits;
}
public function getServiceConfig()
{
return array(
'factories' => array(
'Application\Model\UsersTable' => function($sm) {
if(isset($this->data[$this->id_base]))
{
$tableGateway = $sm->get('UsersTableGateway');
$table = new UsersTable($tableGateway);
return $table;
}
else
{
return;
}
},
'UsersTableGateway' => function ($sm) {
$dbAdapter = $sm->get('SwitchDbAdapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype($sm->get('UsersModel'));
return new TableGateway($this ->data['t'.$this->id_base]['users'], $dbAdapter, null, $resultSetPrototype);
},
'UsersModel' => function($sm) {
$usersModel = new UsersModel();
$usersModel->setConfig($this->conf_Users_tables[$this->id_base]);
return $usersModel;
},
'Application\Model\DroitsTable' => function($sm) {
$tableGateway = $sm->get('DroitsTableGateway');
$table = new DroitsTable($tableGateway);
return $table;
},
'DroitsTableGateway' => function ($sm) {
$dbAdapter = $sm->get('SwitchDbAdapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype($sm->get('DroitsModel'));
return new TableGateway($this ->data['t'.$this->id_base]['droits'], $dbAdapter, null, $resultSetPrototype);
},
'DroitsModel' => function($sm) {
$droitsModel = new DroitsModel();
$droitsModel->setConfig($this->$conf_Droits_tables[$this->id_base]);
return $droitsModel;
},
'SwitchDbAdapter' => function ($sm) {
$dbAdapter = new \Zend\Db\Adapter\Adapter($this->data[$this->id_base]);
return $dbAdapter;
},
),
);
}
}
So I’d like the application send HTTP ERROR code 404 if the parameter in the URL doesn’t match to any databases in my config.
public function getServiceConfig()
{
if (empty($this->data[$this->id_base])){
header('HTTP/1.0 404 Not Found');
die('<h1>404 Not Found</h1>Incorrect Database request.');
}
// Rest of you code in method getServiceConfig() ...
}
I have successfully completed the the album table tutorial in Zend Framework 2 manual. I have implemented using tablegateway. I can see that he used only one table named "album" and hence he implemented according to that one table.
Lets say I have another table called "artist" that holds the information of each artists from that "album" table.
Now in manual, he simply uses:
$this->getAlbumTable()->fetchAll();
Now I want to do similar thing with "artists" table so that my query can be like:
$this->getArtistsTable()->fetchAll();
So what should I change or add?? I already have created the artist table in mySql with columns: Name, DOB, Country.
P.S: I am not going to use joins or anything atm. Just want to access the second table in same controller (same module).
SOLUTION:
With the help of Venca, I was able to solve this problem: here is how you should edit the factory setting for 2 tables and more.
public function getServiceConfig()
{
// Given in Manual
return array(
'factories' => array(
'Album\Model\AlbumTable' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
// Added another table named Artist
'Album\Model\ArtistTable' => function($sm) {
$tableGateway = $sm->get('ArtistTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'ArtistTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Artist());
return new TableGateway('artist', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
Now you can access both tables from your controller. Problem Solved. Day well spent.
According to manual
Create model
Create model table
Add factory to your module
return array(
'factories' => array(
'Album\Model\ArtistTable' => function($sm) {
$tableGateway = $sm->get('ArtistTableGateway');
$table = new ArtistTable($tableGateway);
return $table;
},
'ArtistTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Artist());
return new TableGateway('artist', $dbAdapter, null, $resultSetPrototype);
},
),
);
i want to create two controller with different tables fetch records then view,edit and update them my first album controller works fine but when i create another controller then it gives me error.
You need to register the service Album\Model\DemoTable with the service manager; just as you have with the existing Album\Model\AlbumTable.
The documentation shows you how to register the AlbumTable;
So by modifying that example, something like this should work:
// Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Album\Model\DemoTable' => function($sm) {
$tableGateway = $sm->get('DemoTableGateway');
$table = new DemoTable($tableGateway);
return $table;
},
'Album\Model\AlbumTable' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
'DemoTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Demo());
return new TableGateway('demo', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
Obviously you will need to replace the Demo() class with the actual class that the table is mapping to.
I'm using zend framework 2.2 on xampp. I've a module 'Album'.
directory structure :
my database table:'album'
module code :
<?php
namespace Album;
use Album\Model\Album;
use Album\Model\AlbumTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
class Module {
public function getAutoloaderConfig() {
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig() {
return include __DIR__ . '/config/module.config.php';
}
public function getServiceConfig() {
return array(
'factories' => array(
'Album\Model\AlbumTable' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}
controller code :
<?php
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Album\Model\Album;
use Album\Form\AlbumForm;
class AlbumController extends AbstractActionController {
protected $albumTable;
public function getAlbumTable() {
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable');
}
return $this->albumTable;
}
public function indexAction() {
return new ViewModel(array(
'albums' => $this->getAlbumTable()->fetchAll(),
'active' => 'albumindex',
));
}
}
model code :
<?php
namespace Album\Model;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Select;
use Zend\Paginator\Adapter\DbSelect;
use Zend\Paginator\Paginator;
class AlbumTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll($paginated=false)
{
$resultSet =$this->tableGateway->select(function (Select $select) {
$select->order('title ASC');
});
return $resultSet;
}
}
view code :
<?php
// module/Album/view/album/album/index.phtml:
$title = 'My albums';
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>
<p>
Add new album
</p>
<table class="table">
<tr>
<th>Title</th>
<th>Artist</th>
<th> </th>
</tr>
<?php foreach ($albums as $album) : ?>
<tr>
<td><?php echo $this->escapeHtml($album->title);?></td>
<td><?php echo $this->escapeHtml($album->artist);?></td>
<td>
<a href="<?php echo $this->url('album',
array('action'=>'edit', 'id' => $album->id));?>">Edit</a>
<a href="<?php echo $this->url('album',
array('action'=>'delete', 'id' => $album->id));?>">Delete</a>
</td>
</tr>
<?php endforeach; ?>
</table>
I get the output like the following picture.
now I want to fetch data from different table('abm') while 'album' table still will be declared in module code.
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
(and suppose my both data tables have same structure.so view page and controller will be same.)
so what should I do for that ? how can I use TableGateway() in model code for different data table ?
-thanks.
Edit:
I did the following,
Module :
<?php
namespace Album;
use Album\Model\Album;
use Album\Model\AlbumTable;
**use Album\Model\AbmTable;**
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
class Module {
public function getAutoloaderConfig() {
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig() {
return include __DIR__ . '/config/module.config.php';
}
public function getServiceConfig() {
return array(
'factories' => array(
'Album\Model\AlbumTable' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
**'Album\Model\AbmTable' => function($sm) {
$tableGateway = $sm->get('AbmTableGateway');
$table = new AbmTable($tableGateway);
return $table;
},
'AbmTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('abm', $dbAdapter, null, $resultSetPrototype);
},**
),
);
}
}
Controller :
<?php
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Album\Model\Album;
use Album\Form\AlbumForm;
class AlbumController extends AbstractActionController {
protected $albumTable;protected $abmTable;
public function getAlbumTable() {
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable');
}
return $this->albumTable;
}
**public function getAbmTable() {
if (!$this->abmTable) {
$sm = $this->getServiceLocator();
$this->abmTable = $sm->get('Album\Model\AbmTable');
}
return $this->abmTable;
}**
public function indexAction() {
return new ViewModel(array(
'albums' => $this->getAlbumTable()->fetchAll(),
**'abms' => $this->getAbmTable()->fetchAll(),**
));
}
}
Model (a new model page: 'AbmTable.php') :
<?php
namespace Album\Model;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Select;
use Zend\Paginator\Adapter\DbSelect;
use Zend\Paginator\Paginator;
class AbmTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll($paginated=false)
{
$result =$this->tableGateway->select(function (Select $select) {
$select->order('title ASC');
});
return $result;
}
}
then I received '$abms' in view page with 'abm' table data.
Update :
it fetches different tables with same model.
Module :
namespace Album;
use Album\Model\AlbumTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
class Module {
public function getAutoloaderConfig() {
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig() {
return include __DIR__ . '/config/module.config.php';
}
public function getServiceConfig() {
return array(
'factories' => array(
// 'album' table-------------------------------------
'Album\Model\AlbumTable\dbtable=album' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
// 'abm' table-------------------------------------
'Album\Model\AlbumTable\dbtable=abm' => function($sm) {
$tableGateway = $sm->get('AbmTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AbmTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('abm', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}
Controller :
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class AlbumController extends AbstractActionController {
protected $albumTable;
protected $abmTable;
public function getAlbumTable() {
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable\dbtable=album');
}
return $this->albumTable;
}
public function getAbmTable() {
if (!$this->abmTable) {
$sm = $this->getServiceLocator();
$this->abmTable = $sm->get('Album\Model\AlbumTable\dbtable=abm');
}
return $this->abmTable;
}
public function indexAction() {
return new ViewModel(array(
'albums' => $this->getAlbumTable()->fetchAll(),
'abms' => $this->getAbmTable()->fetchAll(),
));
}
}
Model :
namespace Album\Model;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Select;
class AlbumTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll($paginated=false)
{
$result =$this->tableGateway->select(function (Select $select) {
$select->order('title ASC');
});
return $result;
}
}
If i understand you correctly you just have to make another TableGateway for another table 'abm' and make entity class for that then you can fetch both tables and show them in view.
I'm starting programming with Zend and I am using the default Album example they provide as a "getting started" guide.
I would like to have a select drop down field in the form, but I can't find an easy way of doing it like the code is right now
This is how I'm doing it without consulting DB from my UsersForm.php
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'level',
'options' => array(
'label' => 'User level',
'value_options' => array(
'1' => 'admin',
'2' => 'boss',
'3' => 'assistent',
'4' => 'client',
),
),
));
UPDATE
Ok, so following that tutorial using TableGateway I managed to have a selectable but is grabbing data from the 'project' table because the rest of my fields need that table, but I need that selectable to get from 'user' table.
My Module.php looks like this:
public function getServiceConfig()
{
return array(
'invokables' => array(),
'factories' => array(
'Project\Model\ProjectTable' => function($sm) {
$projectTableGateway = $sm->get('ProjectTableGateway');
$usersTableGateway = $sm->get('UsersTableGateway');
$table = new ProjectTable($projectTableGateway, $usersTableGateway);
return $table;
},
'project-model-selectable' => function($sm) {
$tableGateway = $sm->get('selecttable-gateway');
$table = new SelectTable($projectTableGateway, $usersTableGateway);
return $table;
},
'ProjectTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Project());
return new TableGateway('project', $dbAdapter, null, $resultSetPrototype);
},
'UsersTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Users());
return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
},
'selecttable-gateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new SelectOption());
return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
And my getProject function in ProjectTable.php:
public function getProject($id)
{
$id = (int) $id;
$rowset = $this->projectTableGateway->select(array('id' => $id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
My addAction in ProjectController.php
public function addAction()
{
$tableGateway = $this->getServiceLocator()->get('Project\Model\ProjectTable');
$form = new ProjectForm($tableGateway);
$form->get('submit')->setValue('Nuevo');
$request = $this->getRequest();
if ($request->isPost()) {
$project = new ProjectForm($tableGateway);
$form->setInputFilter($project->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$project->exchangeArray($form->getData());
$this->getProjectTable()->saveProject($project);
// Redirect to list of projects
return $this->redirect()->toRoute('project');
}
}
return array('form' => $form);
}
Thanks
public function getProject($id)
{
$id = (int) $id;
$rowset = $this->projectTableGateway->select(array('id' => $id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}