Zend:Fetching Data from Multiple tables - php

Please find my code below
module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Shopping\Model\ShopTable' => function($sm) {
$tableGateway = $sm->get('ShopTableGateway');
$table = new ShopCategoriesTable($tableGateway);
return $table;
},
'ShopTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new ShopCategories());
return new TableGateway('shop_goods', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
shoppingcontroller.php
public function getShopTable()
{
if (!$this->shopTable)
{
$sm = $this->getServiceLocator();
$this->shopTable = $sm->get('Shopping\Model\ShopTable');
}
return $this->shopTable;
}
As you can see on my first code shop_categories is my database table from which iam fetching data ,above code works fine.But now i need to fetch data from an other table named as shop_goods how do i configure module.php?

Try this :
module.php
<?php
public function getServiceConfig()
{
return array(
'factories' => array(
'Application\Model\ShopgoodsTable' => function($sm) {
$tableGateway = $sm->get('ShopgoodsTableGateway');
$table = new ShopgoodsTable($tableGateway);
return $table;
},
'ShopgoodsTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Shopgoods());
return new TableGateway('shops_goods', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
And in your controller
public function getShopgoodsTable()
{
if (!$this->shopGoodsTable)
{
$sm = $this->getServiceLocator();
$this->shopGoodsTable= $sm->get('Shopping\Model\ShopgoodsTable');
}
return $this->shopGoodsTable;
}

Well you have to use modify your query, use JOIN for your sql query but this will be a problem as you mapper might not know other table values to be populated with results. So, you have two options.
1) Use join and Modify your mapper -- not a clean approach, i will say
2) Learn to use doctrine and it will handle such things. You are using TableGateway. It is good only if you are doing transaction per table per mapper. If you want to use one/one-many relationship scenario you might have to trick your code just like in point 1 which will lead in complications. So Doctrine is the solution

Here is an example of how I accomplished this. My module name is Application and the two tables I'm fetching data from are 'projects' and 'users'.
Module.php
namespace Application;
// Project db
use Application\Model\Project;
use Application\Model\ProjectTable;
// User db
use Application\Model\User;
use Application\Model\UserTable;
// db connection
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
class Module {
public function onBootstrap(MvcEvent $e) {...}
public function getConfig() {...}
public function getAutoloaderConfig() {...}
public function getServiceConfig() {
return array(
'factories' => array(
'Application\Model\ProjectTable' => function($sm) {
$tableGateway = $sm->get('ProjectTableGateway');
$table = new ProjectTable($tableGateway);
return $table;
},
'ProjectTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Project());
return new TableGateway('projects', $dbAdapter, null, $resultSetPrototype);
},
/*** Add other table gateways here ***/
'Application\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('users', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}
in my controller...
public function indexAction() {
return new ViewModel(array(
'projects' => $this->getProjectTable()->fetchAll(),
'users' => $this->getUserTable()->fetchAll(),
));
}
So, in your shoppingcontroller.php file, as long as your controller class is extending AbstractActionController and you've included...
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
you should be able to return a ViewModel object that contains the data fetched from your separate database tables. Then you can use as you'd like in your view. For example, I loop through $projects and $users in my view to display the contents.

Related

How to configure module.php if I have two tablse and display data in different views using different controllers

How to configure module.php?
I am trying to fetch data from two tables with in 2 different views using different controllers.
Below is my code that shows you what I am doing in my module, business controller and registration controller.
Module.php
public function getServiceConfig(){
return array(
'factories' => array(
// Instantiating StudentTable class by injecting TableGateway
'TaskForce\Model\RegistrationTable'=>function($sm){
$registerationGateway = $sm->get('RegistrationTableGateway');
$table = new RegistrationTable($registerationGateway);
return $table;
},
//Instantiating TableGateway to inject to StudentTable class
'RegistrationTableGateway'=>function($sm){
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Registration());
return new TableGateway('users', $dbAdapter,null,$resultSetPrototype);
},
'TaskForce\Model\BusinessTable'=>function($sm){
$businessGateway = $sm->get('BusinessTableGateway');
$businesstable = new BusinessTable($businessGateway);
return $businesstable;
},
//Instantiating TableGateway to inject to StudentTable class
'BusinessTableGateway'=>function($sm){
$dbAdapter2 = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype2 = new ResultSet();
$resultSetPrototype2->setArrayObjectPrototype(new Business());
return new TableGateway('business', $dbAdapter2,null,$resultSetPrototype2);
},
)
);
}
BusinessController.php
public function indexAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
return new ViewModel(array(
// Fetching data from database
'business'=>$this->getBusinessTable()->fetchAll()
));
}
and RegistrationController.php
public function indexAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
$form = new RegistrationForm();
$request = $this->getRequest();
if ($request->isPost()) {
$registration = new Registration();
//$form->get('submit')->setAttribute('value', 'Add New User');
$post = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
$form->setData($post);
if ($form->isValid()) {
$registration->exchangeArray($form->getData());
$this->getRegistrationTable()->saveRegistration($registration);
// Redirect to list of users
return $this->redirect()->toRoute('registration');
}
}
return new ViewModel(array(
'form' => $form
));
}
If there is a relationship between the Business and the Registration records, you may wish to clarify it. However, if it is simply a matter of code arrangement, you can do this:
BusinessController.php
public function indexAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
return new ViewModel(array(
// Fetching data from database
'business'=>$this->getBusinessTable()->fetchAll(),
'registration' => $this->getRegistrationTable()->fetchAll(),
));
}
RegistrationController.php
public function indexAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
return new ViewModel(array(
// Fetching data from database
'business'=>$this->getBusinessTable()->fetchAll(),
'registration' => $this->getRegistrationTable()->fetchAll(),
));
}
// rename your index action in registrationcontroller.php to form
// so that the form is displayed on the formAction
public function formAction(){
// Setting layout for this action
$this->layout("layout/main_layout");
$form = new RegistrationForm();
$request = $this->getRequest();
if ($request->isPost()) {
$registration = new Registration();
//$form->get('submit')->setAttribute('value', 'Add New User');
$post = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
$form->setData($post);
if ($form->isValid()) {
$registration->exchangeArray($form->getData());
$this->getRegistrationTable()->saveRegistration($registration);
// Redirect to list of users
return $this->redirect()->toRoute('registration');
}
}
return new ViewModel(array(
'form' => $form
));
}

Sequence of declaring a model variable in Zend Framework 2

I am a beginner of Zend Framework2. Following the example of "Zend Framework 2.0 by Example Beginner's Guide" I got stuck in a weird problem.
Here is my project structure.
I have a simple function creatureUser() in RegisterController.php:
<?php
namespace Users\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Users\Form\RegisterForm;
use Users\Form\RegisterFilter;
use users\Model\User;
use Users\Model\UserTable;
class RegisterController extends AbstractActionController
{
public function indexAction()
{
//$form = new RegisterForm();
$form = $this->getServiceLocator()->get('RegisterForm');
$viewModel = new ViewModel(array('form' => $form));
return $viewModel;
}
public function confirmAction()
{
$viewModel = new ViewModel();
return $viewModel;
}
public function processAction()
{
if (!$this->request->isPost()) {
return $this->redirect()->toRoute(NULL , array(
'controller' => 'register',
'action' => 'index'
));
}
$post = $this->request->getPost();
//$form = new RegisterForm();
//$inputFilter = new RegisterFilter();
//$form->setInputFilter($inputFilter);
$form = $this->getServiceLocator()->get('RegisterForm');
$form->setData($post);
if (!$form->isValid()) {
$model = new ViewModel(array(
'error' => true,
'form' => $form,
));
$model->setTemplate('users/register/index');
return $model;
}
// Create user
$this->createUser($form->getData());
return $this->redirect()->toRoute(NULL , array(
'controller' => 'register',
'action' => 'confirm'
));
}
protected function createUser(array $data)
{
$user = new User();
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new \Zend\Db\ResultSet\ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new \Users\Model\User);
$tableGateway = new \Zend\Db\TableGateway\TableGateway('user', $dbAdapter, null, $resultSetPrototype);
//$user = new User();
$user->exchangeArray($data);
$userTable = new UserTable($tableGateway);
$userTable->saveUser($user);
return true;
}
}
When run the above code I get an error:
Fatal error: Class 'users\Model\User' not found in C:\WebApp\ZF2Skeleton\module\Users\src\Users\Controller\RegisterController.php on line 90.
But If I move $user = new User(); below. Like this one:
protected function createUser(array $data)
{
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new \Zend\Db\ResultSet\ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new \Users\Model\User);
$tableGateway = new \Zend\Db\TableGateway\TableGateway('user', $dbAdapter, null, $resultSetPrototype);
$user = new User();
$user->exchangeArray($data);
$userTable = new UserTable($tableGateway);
$userTable->saveUser($user);
return true;
}
It will work perfectly. Can anyone tell me how this happens, please? Is it a sequence problem? Thank you!
It's a simple typo in your controller:
use users\Model\User;
should be:
use Users\Model\User;
(note the capital 'U' in 'Users').

Fatal Error when using Service from vendor module in Zend framework 2

I have a ZF2 application with 1 module and I am trying to use a class from another module called "CommonRestClient" located in the "vendor" directory.
The directory structure of this "vendor" directory is as under:
vendor
-->CommonRestClient
---->config
------>module.config.php
-->src
---->CommonRestClient
------->Service
--------->CommonRestClient.php
-->Module.php
vendor\CommonRestClient\config\module.config.php
================================================
<?php
return array();
?>
vendor\src\Module.php
======================
<?php
namespace CommonRestClient;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\Http\Client as HttpClient;
use CommonRestClient\Service\CommonRestClient as CommonRestClient;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
}
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 getServiceConfig()
{
return array(
'factories' => array(
'CommonRestClient\Service\CommonRestClient' => function($sm) {
$httpClient = $sm->get('HttpClient');
$httpRestJsonClient = new CommonRestClient($httpClient);
return $httpRestJsonClient;
},
'HttpClient' => function($sm) {
$httpClient = new HttpClient();
$httpClient->setAdapter('Zend\Http\Client\Adapter\Curl');
return $httpClient;
},
),
);
}
}
vendor\src\CommonRestClient\Service\CommonRestClient.php
=========================================================
<?php
namespace CommonRestClient\Service;
use Zend\Http\Client as HttpClient;
use Zend\Http\Request;
use Zend\Stdlib\Parameters;
class CommonRestClient
{
protected $httpClient;
public function __construct(HttpClient $httpClient)
{
$this->httpClient = $httpClient;
}
public function get($url)
{
return $this->dispatchRequestAndDecodeResponse($url, "GET");
}
public function post($url, $data)
{
return $this->dispatchRequestAndDecodeResponse($url, "POST", $data);
}
public function put($url, $data)
{
return $this->dispatchRequestAndDecodeResponse($url, "PUT", $data);
}
public function delete($url)
{
return $this->dispatchRequestAndDecodeResponse($url, "DELETE");
}
protected function dispatchRequestAndDecodeResponse($url, $method, $data = null)
{
$request = new Request();
$request->getHeaders()->addHeaders(array(
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
));
$request->setUri($url);
$request->setMethod($method);
if ($data){
$request->setPost(new Parameters($data));
}
$response = $this->httpClient->dispatch($request);
# should interogate response status, throwing appropiate exceptions for error codes
return json_decode($response->getBody(), true);
}
}
So, in the main application module, I am trying to use the above class in a Model file, which looks like this:
<?php
namespace MyApplication\Model;
use CommonRestClient\Service\CommonRestClient as CommonRestClient;
class Users
{
protected $commonRestClient;
public function __construct(CommonRestClient $commonRestClient)
{
$this->commonRestClient = $commonRestClient;
}
public function getListOfUsers()
{
$url = 'http://xyz.google.com/getusers';
$jsonResponse = $this->commonRestClient->get($url);
return $jsonResponse;
}
}
I have configured MyApplication's application.config.php to use the "CommonRestClient" module.
The error I am recieving is:
Catchable fatal error: Argument 1 passed to
MyApplication\Model\Users::__construct() must be an instance of
CommonRestClient\Service\CommonRestClient, none given, called in
C:\Users\Public\myapp\myapplication\module\MyApplication\src\MyApplication\Controller\UsersController.php
on line 27 and defined in
C:\Users\Public\myapp\myapplication\module\MyApplication\src\MyApplication\Model\Users.php
on line 23
Can any one help me with what I could be missing here?
Thanks
In the constructor you defined for your Users class you specified a required argument of CommonRestClient which you are not supplying when creating the instance from your controller, so that's why you are getting the error.
You can either supply the argument yourself:
$users = new Users($this->getServiceLocator()->get('CommonRestClient\Service\CommonRestClient'));
or tell ZF how to do that using a factory:
public function getServiceConfig()
{
return array(
'factories' => array(
'Users' => function($sm) {
$commonRestClient = $sm->get('CommonRestClient\Service\CommonRestClient');
$users = new Users($commonRestClient);
return $users;
},
),
);
}
and then use the service locator to create the instance for you:
$users = $this->getServiceLocator()->get('Users');

Zend Framework comm-app cannot find class

I'm following this book, and I'm in chapter 3 and this code is returning me the following error: Fatal error: Class 'Users\Model\User' not found in /var/www/CommunicationApp/module/Users/src/Users/Controller/RegisterController.php on line 70
I want to know what is wrong with the code, or if it's not the code than what is it?
<?php
namespace Users\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Users\Form\RegisterForm;
use Users\Form\RegisterFilter;
use Users\Model\User;
use Users\Model\UserTable;
class RegisterController extends AbstractActionController
{
public function indexAction()
{
$form = new RegisterForm();
$viewModel = new ViewModel(array('form' => $form));
return $viewModel;
}
public function processAction()
{
if (!$this->request->isPost()) {
return $this->redirect()->toRoute(NULL , array(
'controller' => 'register',
'action' => 'index'
));
}
$post = $this->request->getPost();
$form = new RegisterForm();
$inputFilter = new RegisterFilter();
$form->setInputFilter($inputFilter);
$form->setData($post);
if (!$form->isValid()) {
$model = new ViewModel(array(
'error' => true,
'form' => $form,
));
$model->setTemplate('users/register/index');
return $model;
}
// Create user
$this->createUser($form->getData());
return $this->redirect()->toRoute(NULL , array(
'controller' => 'register',
'action' => 'confirm'
));
}
public function confirmAction()
{
$viewModel = new ViewModel();
return $viewModel;
}
protected function createUser(array $data)
{
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new \Zend\Db\ResultSet\ResultSet();
$resultSetPrototype->setArrayObjectPrototype (new \Users\Model\User); //line 70
$tableGateway = new \Zend\Db\TableGateway\TableGateway('user' /* table name */, $dbAdapter, null, $resultSetPrototype);
$user = new User();
$user->exchangeArray($data);
$userTable = new UserTable($tableGateway);
$userTable->saveUser($user);
return true;
}
}
for a correct autoloading check if the model file is in the following directory
/module/Users/src/Users/Model/User.php
if is not zend can't autoload your model file and that triggers your error if (as you pointed out your classname and namespace in the model file is correct) the file is not placed there.

Where do Zend\Db\ResultSet\ResultSet objects store the retrieved data?

In a Zend Framework application, that is built pretty similar to the album application from the ZF2 Getting Started tutorial, I use a ResultSet object to transport the data from the model over the controller to the view (for details see the code below).
This works fine, but I don't get, where the ResultSet object holds the data. I can loop it e.g. with foreach and get the data row byrow (or better model object by model object). But when I debug it in my IDE or simply with var_dump(...), it seems to be empty.
How/where does a Zend\Db\ResultSet\ResultSet object hold the data, retrieved from the database?
The relevant parts of the code:
Module settings:
class Module implements ConfigProviderInterface, ServiceProviderInterface, AutoloaderProviderInterface {
...
public function getServiceConfig() {
try {
return array (
'factories' =>array(
...
'SportTable' => function ($serviceManager) {
$tableGateway = $serviceManager->get('SportTableGateway');
$table = new SportTable($tableGateway);
return $table;
},
'SportTableGateway' => function ($serviceManager) {
$dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Sport());
return new TableGateway('sports', $dbAdapter, null, $resultSetPrototype);
},
...
)
);
}
...
}
Model (table):
class CourseTable {
...
public function findAllByCityNameAndSportTitle($cityName, $sportTitle) {
$select = new Select();
$where = new Where();
...
$resultSet = $this->tableGateway->selectWith($select);
return $resultSet;
}
...
}
Model (mapper):
class Course implements ArraySerializableInterface {
public $id;
...
public function exchangeArray(array $data) {
$this->id = (isset($data['id'])) ? $data['id'] : null;
...
}
...
}
Controller:
class CatalogController extends AbstractActionController {
...
public function listCoursesAction() {
$cityName = $this->params()->fromRoute('city', null);
$sportTitle = $this->params()->fromRoute('sport', null);
return new ViewModel(array(
'city' => $cityName,
'sport' => $sportTitle,
'courses' => $this->getCourseTable()->findAllByCityNameAndSportTitle($cityName, $sportTitle)
));
}
...
}
View:
<?php foreach ($courses as $course) : ?>
<div>
<div>id: <?php echo $this->escapeHtml($course->id); ?></div>
...
</div>
<?php endforeach; ?>
Zend\Db\ResultSet\ResultSet or rather Zend\Db\ResultSet\AbstractResultSet is holding the answer to your question. This object has 10-12 methods most of them providing iterative functionality. To answer your question the Zend\Db\ResultSet\ResultSet holds the information retrieved from the Db in its dataSource paramter (Zend\Db\ResultSet\ResultSet::$dataSource).
The paradox of results being iterated and loaded with foreach but not seen by var_dump() can be explained by the fact that the results returned are actually hold in buffered.
If you want to access the result set I suggest you to use Zend\Db\ResultSet\ResultSet::toArray() ($resultSet->toArray()). This will return an array of arrays where each array is a row in the DB table.
Hope this helps, feedback will be appreciated :),
Stoyan.

Categories