Hi i have this problem: i want to count rows in ZF2 in database and i use this code in controller:
public function getProductTable()
{
if (!$this->productTable) {
$sm = $this->getServiceLocator();
$this->productTable = $sm->get('Product\Model\ProductTable');
}
return $this->productTable;
}
public function productCounter($user_id){
//product Count
$productCount = $this->getProductTable()->select(); // error reported on this line
return $productCount->from("product")->where(array('user_id' => $user_id))->count();
}
function getProductTable() is working because i use it on other lines. mistake is reported on marked line in code. Where is my mistake? .. Thanks for answers
Change the productCounter function to this
public function productCounter($user_id) {
return $this->getProductTable()->select(array('user_id' => $user_id))->count();
}
Select method returns the results right away, not the Select object.
I hope along with getProductTable() and productCounter() functions you also have the following constructor too;
protected $tableGateway;
.....
...
public function __construct(TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
}`
If so then try this -
public function productCounter($user_id) {
return $this->tableGateway->select(array('user_id' => $user_id))->count();
}
This should work fine.
Now if you don't have such a constructor then there is lot to be done if you want to use the TableGateway for executing the queries -
Have such a constructor first. //Important
In Product\Module.php -
'Product\Model\ProductTable' => function($sm) {
$tableGateway = $sm->get('ProductTableGateway');
$table = new ProductTable($tableGateway);
return $table;
},
'ProductTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Product());
return new TableGateway('product', $dbAdapter, null, $resultSetPrototype);
},
Now try that productCounter() function.
I hope it helps.
Related
can somebody try to explain me how to use multiple normalizers when serializing data from multiple classes with the Symfony serializer?
Lets say that I have the following classes:
class User
{
private $name;
private $books;
public function __construct()
{
$this->books = new ArrayCollection();
}
// getters and setters
}
class Book
{
private $title;
public function getTitle()
{
return $this->title;
}
public function setTitle($title)
{
$this->title = $title;
}
}
And I want to serialize an user who has multiple books.
$first = new Book();
$first->setTitle('First book');
$second = new Book();
$second->setTitle('Second book');
$user = new User();
$user->setName('Person name');
$user->addBook($first);
$user->addBook($second);
dump($this->get('serializer')->serialize($user, 'json'));
die();
Let's say that I also want to include a hash when serializing a book, so I have the following normalizer:
class BookNormalizer implements NormalizerInterface
{
public function normalize($object, $format = null, array $context = array())
{
return [
'title' => $object->getTitle(),
'hash' => md5($object->getTitle())
];
}
public function supportsNormalization($data, $format = null)
{
return $data instanceof Book;
}
}
And I am getting the expected result:
{"name":"Person name","books":[{"title":"First book","hash":"a9c04245e768bc5bedd57ebd62a6309e"},{"title":"Second book","hash":"c431a001cb16a82a937579a50ea12e51"}]}
The problem comes when I also add a normalizer for the User class:
class UserNormalizer implements NormalizerInterface
{
public function normalize($object, $format = null, array $context = array())
{
return [
'name' => $object->getName(),
'books' => $object->getBooks()
];
}
public function supportsNormalization($data, $format = null)
{
return $data instanceof User;
}
}
Now, the books aren't normalized using the previously given normalizer, and i get the following:
{"name":"Person name","books":[{},{}]}
I tried to find a way (documentation and other articles) to always call the normalizers for the given types (eg. always call the book normalizer when the type is Book, even if the data is nested and used in another normalizer) but could not succeed.
I think i have misunderstood something about normalizers but don't know what. Can somebody explain to is what i want possible and how to do it?
You have to use the NormalizerAwareTrait so you can access the normalizer for books
add interface
use trait
call normalize() method for books
code:
class UserNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
use NormalizerAwareTrait;
public function normalize($object, $format = null, array $context = array())
{
return [
'name' => $object->getName(),
'books' => $this->normalizer->normalize($object->getBooks(), $format, $context)
];
}
public function supportsNormalization($data, $format = null)
{
return $data instanceof User;
}
}
I'm having difficulty reading logged user's session in user model.
When retrieve user data from any other model it works perfectly.
MODULE.PHP
'session' => function ($sm) {
$config = $sm->get('config');
if (isset($config['session'])) {
$session = $config['session']['config']['options']['name'];
//Various Session options
$manager = new \Zend\Session\SessionManager();
if(filter_input(INPUT_SERVER, 'APPLICATION_ENV') === 'production'){
$manager->getConfig()
->setCookieHttpOnly(true)
->setCookieSecure(false);
$manager->start();
}
return new Session($session);
}
},
BaseTable.php
public function getIdentity($property = null) {
$storage = $this->getServiceLocator()->get('session');
if (!$storage) {
return false;
}
$data = $storage->read();
if ($property && isset($data[$property])) {
return $data[$property];
}
return $data;
}
When i call getIdentity function where tb_usuario instantiated I get this error:
Fatal error: Call to a member function get() on a non-object in
C:\wamp\www\sigaAvaliacoes\module\application\src\Application\Model\BaseTable.php
on line 73
Sorry my english, thanks!
Sorry guys, i found the problem, in Module.php i not instance serviceLocator:
'Usuario' => function($sm) {
$tableGateway = new TableGateway('tb_usuario', $sm->get('db_adapter_main'));
return new Model\Usuario($tableGateway);
},
Now work:
'Usuario' => function($sm) {
$tableGateway = new TableGateway('tb_usuario', $sm->get('db_adapter_main'));
$updates = new Model\Usuario($tableGateway);
$updates->setServiceLocator($sm);
return $updates;
},
Thanks =D
Recently I made my first ZF2 application. I was walking through the code to see if I could make the code somewhat cleaner. Then I noticed that my controller classes have a huge block of code that supplies the controller of the TableGateway classes it needs. And I wondered is there a shorter/cleaner way to do this? It just seems silly that half of my controller class is dedicated to this simple task of fetching some TableGateWay classes.
protected $appointmentTable;
protected $customerTable;
protected $serviceTable;
protected $locationTable;
// ... some action methods that actually do the work.
public function getAppointmentTable()
{
if (!$this->appointmentTable) {
$sm = $this->getServiceLocator();
$this->appointmentTable = $sm->get('Appointment\Model\AppointmentTable');
}
return $this->appointmentTable;
}
public function getServiceTable()
{
if (!$this->serviceTable) {
$sm = $this->getServiceLocator();
$this->serviceTable = $sm->get('Appointment\Model\ServiceTable');
}
return $this->serviceTable;
}
public function getLocationTable()
{
if (!$this->locationTable) {
$sm = $this->getServiceLocator();
$this->locationTable = $sm->get('Appointment\Model\LocationTable');
}
return $this->locationTable;
}
public function getCustomerTable()
{
if (!$this->customerTable) {
$sm = $this->getServiceLocator();
$this->customerTable = $sm->get('Customer\Model\CustomerTable');
}
return $this->customerTable;
}
The way your Controllers should ideally be set up is through the means of proper(!) dependency injection. In Zend Framework 2 you have two main ways to declare controllers within the ControllerManager. The first one being invokables for controllers who have no dependencies and the second one being factories for controllers who have dependencies.
Any TableGateway always is a dependency. To my experience there are no controllers who are invokables at all :P
There's two ways to set up controller factories.
Module.php using getControllerConfig()
Under the controllers[factories] key in your module.config.php using Factory-Classes
For simplicity I'll choose the first approach now:
public function getControllerConfig()
{
return array(
'factories' => array(
'My\Foo\Controller' => function ($cpm) {
//#var $cpm \Zend\Mvc\Controller\ControllerManager
$serviceLocator = $cpm->getServiceLocator();
$tableGateway = $serviceLocator->get('My\Table\Gateway');
return new \My\Foo\Controller($tableGateway);
}
)
);
}
With this, all that's left is for you to modify your controller and have it pass the respective tablegateway inside its constructor:
class Controller
{
protected $tableGateway;
public function __construct(\My\Table\Gateway $tg)
{
$this->tableGateway = $tg;
}
public function indexAction()
{
return new ViewModel(array(
'entries' => $this->tableGateway->select()
));
}
}
And that's all there is to it. It's all about proper dependency injection that makes your life ultimately so much easier.
Obviously this example only covers one table, but you can do the same just passing more tables through the constructor. That is: only if you really need ALL TableGateways in there (which sounds a bit fishy) ;)
Could you just simplify the process in another method? I'm not aware of this function in Zend2, but still, if there is no method on framework level, you can write your own simplified method
My test so far:
public function setTable($method) {
$method = lcfirst(str_replace("get", "", $method));
$this->$method = 'Apointment\Model\\'.ucfirst($method);
return $this->$method;
}
public function getLocationTable() {
$this->setTable(__FUNCTION__);
var_dump(get_object_vars($this));
}
Outputs:
array (size=1)
'locationTable' => string 'Apointment\Model\LocationTable' (length=30)
So you can change setTable() method to use your set() proxy:
public function setTable($method) {
$method = lcfirst(str_replace("get", "", $method));
if (!$this->$method) {
$sm = $this->getServiceLocator();
$this->$method = $sm->get('Apointment\Model\\'.ucfirst($method));
}
return $this->$method;
}
public function getLocationTable() {
return $this->setTable(__FUNCTION__);
}
public function getServiceTable() {
return $this->setTable(__FUNCTION__);
}
Or you can get all your tables in array, iterate through it and pass the name to your setTable() method, which will set inner properties.
My string test (because I don't have ZF2 right here, and testing if the proper string which you are passing to the set() proxy is built:
class Tables {
public function setTable($method) {
$method = lcfirst(str_replace("get", "", $method));
$this->$method = 'Apointment\Model\\'.ucfirst($method);
/*if (!$this->$method) {
$sm = $this->getServiceLocator();
$this->$method = $sm->get('Apointment\Model\\'.ucfirst($method));
}*/
return $this->$method;
}
public function getLocationTable() {
return $this->locationTable;
}
public function getServiceTable() {
return $this->serviceTable;
}
public function getAppointmentTable() {
return $this->appointmentTable;
}
public function setAllTables() {
foreach (get_class_methods(__CLASS__) as $method) {
if (strpos($method, 'get')!== false && strpos($method, 'Table')!==false)
$this->setTable($method);
}
}
}
$tables = new Tables();
$tables->setAllTables();
var_dump(get_object_vars(($tables)));
Outputs:
array (size=3)
'locationTable' => string 'Apointment\Model\LocationTable' (length=30)
'serviceTable' => string 'Apointment\Model\ServiceTable' (length=29)
'appointmentTable' => string 'Apointment\Model\AppointmentTable' (length=33)
Now all your get____Table() methods are valid getters. E.g.:
var_dump($tables->getServiceTable());
returns
string 'Apointment\Model\ServiceTable' (length=29)
I need to retrive data from 2 tables using join.
I have this code, but it fails with Call to undefined method Zend\Db\ResultSet\ResultSet::from():
public function getUsers($id){
$id = (int) $id;
$rowset = $this->tableGateway->select()->from(array('u' => 'user'))
->join(array('l' => 'levels'),
'u.user_id = l.id_user');
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
The SQL command would be:
select user.*,levels.name from user left join levels on user.user_id=levels.id_user
Thanks
UPDATE
Using #Mohamad changes I get:
The table name of the provided select object must match that of the table
My UsersTable.php looks like this now:
<?php
// module/Users/src/Users/Model/UsersTable.php:
namespace Users\Model;
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Select;
class UsersTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$select = new Select();
$select->from('levels');
$select->join('user', 'levels.id=user.user_id',Select::SQL_STAR,Select::JOIN_RIGHT);
$rowset = $this->tableGateway->selectWith ( $select );
$resultSet = $rowset->current();
if (!$resultSet) {
throw new \Exception("Could not find row $id");
}
return $resultSet;
}
i think you must pass two TableGetway to UserTable construct. you have to change Module.php
look this:
public function getServiceConfig()
{
return array(
'factories' => array(
'User\Model\UserTable' => function($sm) {
$userTableGateway = $sm->get('UserTableGateway');
$levelTableGateway = $sm->get('LevelTableGateway');
$table = new UserTable($userTableGateway,$levelTableGateway);
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);
},
'LevelTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Level());
return new TableGateway('level', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
then in your model:
protected $userTableGateway;
protected $levelTableGateway;
public function __construct($userTableGateway,$levelTableGateway)
{
$this->userTableGateway = $userTableGateway;
$this->levelTableGateway = $levelTableGateway;
}
public function fetchAll()
{
$select = new Select();
$select->from('levels');
$select->join('user', 'levels.id=user.user_id',Select::SQL_STAR,Select::JOIN_RIGHT);
$rowset = $this->levelTableGateway->selectWith ( $select );
$resultSet = $rowset->current();
if (!$resultSet) {
throw new \Exception("Could not find row $id");
}
return $resultSet;
}
i hope helped you
I'm simply trying to fetch all records in a given table by extending Zend AbstractTableGateway and making use of inherited select() function. this select() function returns type Zend ResultSet however I'm not able get an array of results using toArray().
I get the following message:
Rows as part of this DataSource, with type object cannot be cast to an array
Update
I worked it out
assuming you have extended AbstractTableGateway
$resultSet = $this->select();
foreach($resultSet as $row) { echo $row->yourProperty }
You should use HydratingResultSet like this :
class MyClassTable extends AbstractTableGateway
{
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new HydratingResultSet();
$this->resultSetPrototype->setObjectPrototype(new MyClass());
$this->initialize();
}
public function fetchAll()
{
$resultSet = $this->select();
return $resultSet;
}
public function fetchAllToArray()
{
$aData = $this->fetchAll()->toArray();
return $aData;
}
You can also try this
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('table');
$statement = $sql->prepareStatementForSqlObject($select);
$results = $statement->execute();
$resultSet = new ResultSet();
$resultSet->initialize($results);
print_r($resultSet->toArray());
With Zend\Db\ResultSet\ResultSet;
Just try to use
(array)$resultSet
I've used this sometimes on ZF and works fine.
Mine issue was as #Fatmuemoo noted.
If you register your custom object prototype, code eg.
$resultSetPrototype = new ResultSet($entityClassName, new $entityClassName);
$instance->setResultSetPrototype($resultSetPrototype);
you have to implement toArray() method in yout Entity class.
public function toArray()
{
return get_object_vars($this);
}