ZF2 tableGateway select - zend-framework2

I started with the ZendSkeletonApplication and added a model extending Zend\Db\TableGateway\TableGateway.
I have the following method:
public function findByType($type) {
$rowset = $this->select('type' => $type);
return $rowset;
}
This works, but now if i do this:
$foo = $table->findBytype('foo');
$bar = $table->findBytype('bar');
the first one works, the query it executes is:
SELECT * FROM table WHERE 'type' = 'foo'
The second one however executes the following query:
SELECT * FROM table WHERE 'type' = 'foo' AND 'type' = 'bar'
is this expected behavior?
If so how can i have the second time i call the method execute the following query:
SELECT * FROM table WHERE 'type' = 'bar'
thanks in advance!

Should use select in tableGateway like this:
$select = $this->getSql()->select();
$select->where(array('type' => 'foo'))
->where(array('type' => 'bar'));
$rowset = $this->selectWith($select);
select() will be reset the where() paramters when you call it next time.
See more usage in my blog:
http://avnpc.com/pages/advanced-database-select-usage-in-zf2

Related

Ruby on Rails self.joins or self.where doesn't work?

my actual code looks like this
user_lesson = self.where("worked = ? AND passed = ?", true, false).order("lessons.sort")
But it doesn't work ... error is:
undefined method `where' for #<Membership:0x000000059f22e8>
.. I've tried it this way:
user_lesson = Membership.joins("user_lessons").where("id = ? AND worked = ? AND passed = ?",self.id, true, false).order("lessons.sort")
But then I got this error:
Unknown table 'memberships': SELECT `memberships`.*
FROM `memberships` user_lessons
WHERE (id = 4 AND worked = 1 AND passed = 0)
ORDER BY lessons.sort
How should it look like correctly?
Original Query
user_lesson = self.user_lessons.find :first,
:include => [:lesson],
:conditions => ["worked = ? AND passed = ?", true, false],
:order => "lessons.sort"
This is because the where method is defined at the class level rather than the instance level. In your second example (where you're doing Membership.joins) you are doing the right thing by calling joins and where on the Membership class rather than on an instance of that class. The reason you get an error with that second example is probably because you need to run your migrations to create the memberships table (if you have no migration you'll need to create one).

sfWidgetFormDoctrineChoice: bug, error or what?

I'm using sfWidgetFormDoctrineChoice to build select elements in a form. This is how I'm using:
// Fill maquinaemisorid
$this->widgetSchema['maquinaemisorid'] = new sfWidgetFormDoctrineChoice(array('model' => 'SdrivingMaquina', 'add_empty' => 'Seleccione una Máquina', 'table_method' => 'fillChoice'));
// Fill idoperador
$this->widgetSchema['idoperador'] = new sfWidgetFormDoctrineChoice(array('model' => 'SdrivingOperador', 'add_empty' => 'Seleccione un Operador', 'table_method' => 'fillChoice'));
// Fill idturno
$this->widgetSchema['idturno'] = new sfWidgetFormDoctrineChoice(array('model' => 'SdrivingTurno', 'add_empty' => 'Seleccione un Turno', 'table_method' => 'fillChoice'));
For the first widget all is fine and values are taken from DB as should be but for the second one and the third is not working. As you may notice I'm calling a method fillChoice in all widgets table_method. This is the code for the three:
SdrivingMaquinaTable.class.php
public function fillChoice() {
$id_empresa = sfContext::getInstance()->getUser()->getGuardUser()->getSfGuardUserProfile()->getIdempresa();
return Doctrine_Core::getTable('SdrivingMaquina')->createQuery('a')->where('a.idempresa = ?', $id_empresa)->execute();
}
SdrivingOperadorTable.class.php
public function fillChoice() {
$id_empresa = sfContext::getInstance()->getUser()->getGuardUser()->getSfGuardUserProfile()->getIdempresa();
return Doctrine_Core::getTable('SdrivingOperador')->createQuery('a')->where('a.idempresa = ?', $id_empresa)->execute();
}
SdrivingTurno.class.php
public function fillChoice() {
$id_empresa = sfContext::getInstance()->getUser()->getGuardUser()->getSfGuardUserProfile()->getIdempresa();
return Doctrine_Core::getTable('SdrivingTurno')->createQuery('a')->where('a.idempresa = ?', $id_empresa)->execute();
}
The method is the same always just changes the table used for each class. I check the generated queries and all are fine and if I run each on phpMyAdmin for example more than one value is fetched altough in idoperador and idturno just the latest is rendered. This is a very rare behavior and I can't find the error or mistake so I need some help or advice here.
As an adition I tried this in SdrivingRegistrosEmisoresForm.class.php (this is where the widgets are being generated):
$id_empresa = $this->current_user->getSfGuardUserProfile()->getIdempresa();
$choices_operador = Doctrine_Core::getTable('SdrivingOperador')->createQuery('a')->where('a.idempresa = ?', $id_empresa)->execute();
$this->widgetSchema['idoperador'] = new sfWidgetFormSelect(array('choices' => $choices_operador));
And this way works fine but the id for each item fetched isn't right meaning:
id item real_id
0 Item1 2
1 Item2 16
2 Item4 3
I talked about this in this topic but didn't get any answer, any help?
As stated in sfWidgetFormDoctrineChoice, if option *table_method* returns a collection like your methods, it renders choices with options *key_method* and method. By default , they are respectively getPrimaryKey() and *__toString()*.
Can we check you schema.yml and the __toString() ?
As for your last example the option choices of sfWidgetFormSelect should be an array an not a *Doctrine_Collection*

How to use multiple on clause in joining in zend framework 2

I am doing like this sql into zend framework sql pattern.
SELECT
jobs . *,
c.id AS cid,
c.name AS name,
c.companyImage AS companyImage,
c.logo AS logo,
count(app.userId) AS t_app,
app.applyStatus AS applyStatus,
app.userId AS appUserId
FROM
jobs
LEFT JOIN
companies AS c ON jobs.companyName = c.id
LEFT JOIN
applicants AS app ON jobs.id = app.jobId AND app.applyStatus = 1
WHERE
jobs.ownerId = 16 AND jobs.draftId != 0
GROUP BY jobs.id
ORDER BY jobs.id DESC
LIMIT 3
For this sql I already write this code for zend framework 2
$adapter = $this->tableGateway->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->from('jobs')
->join(array('c' => 'companies'), 'jobs.companyName = c.id', array('cid' => 'id', 'name', 'companyImage', 'logo'), 'left')
->join(array('app' => 'applicants'), ' jobs.id = app.jobId AND app.applyStatus = 1', array('t_app' => new Expression('count(app.userId)'), 'applyStatus', 'appUserId' => 'userId'), 'left')
->where("jobs.ownerId ={$userId} AND jobs.draftId != 0")
->group('jobs.id')
->order('jobs.id DESC')
->limit(3);
$statement = $sql->getSqlStringForSqlObject($select);
$results = $adapter->query($statement, $adapter::QUERY_MODE_EXECUTE);
but does not work properly and its give a message like below.
SQLSTATE[42S22]: Column not found: 1054 Unknown column '1' in 'on clause'
The issue is this part:
app.applyStatus = 1
The framework is escaping 1 as if it were a column name, 1.
You need to enclose this part in an Expression too
new Expression('jobs.id = app.jobId AND app.applyStatus = 1')
I think the use of Expressions in the 'ON' parameter of the join method may depend on the version of ZF2 you are using, I think it was added 2.1+
Building on this answer. If you also want your table & column identifiers to be escaped, use this syntax:
use Zend\Db\Sql\Expression;
...
$onExpression = new Expression('? = ? AND ? = ?',
['jobs.id', 'app.jobId', 'app.applyStatus', 1],
[Expression::TYPE_IDENTIFIER, Expression::TYPE_IDENTIFIER,
Expression::TYPE_IDENTIFIER, Expression::TYPE_LITERAL]
);
$select->from('jobs')
->join(array('app' => 'applicants'), $onExpression, array('t_app' => new Expression('count(app.userId)'), 'applyStatus', 'appUserId' => 'userId'), 'left');
The Expression constructor accepts the string, then arguments, then argument types.
public function __construct($expression = '', $parameters = null, array $types = [])
This will create a security issue. Zf2 changes your query to this:
Select * from tableA inner join tableB
on `tableA`.`column` = `tableB`.`column`
AND `tableB`.`column` = `1`
It adds
`
to each part for security issues! By using new Expression you are bypassing it and if you get applyStatus from user entry, get sure about its filtering!

How to add Sql\Expression in front of column Name in ZF2?

How to get Sql like this :
select * from foo where LOWER(foo_name) = 'test';
what i get is if Sql\Expression in right, not in left.
You can user code snippet like that.
$where = new Where();
$sql = new Sql($adapter);
$select = $sql->select();
$where->addPredicate(new Predicate\Expression('LOWER(foo_name) = ?', 'test' ));
$select->from('foo')->where($where);
However I dont think Sql\Expression on right side is possible on Zend Framework 2.
You can do it like this:
$sql = new SQL($adaptor);
$select = $sql->select()->from(array('f'=>'foo'));
$select = $select->where('foo_name' => new \Zend\Db\Sql\Expression("LOWER('test')"));
Above query would return as:
SELECT `f`.* FROM `foo` AS `f` WHERE `foo_name` = LOWER('test');
For others out looking for similar, there are actually quite a few different ways to achieve this as of ZF 2.2
Chaining (same as the accepted answer)
<?php
$sql = new Sql($adapter);
$select = $sql->select();
$select->from( array( 'f' => 'foo' ) )
->where
->addPredicate( new Predicate\Expression( 'LOWER(f.foo_name) = ?', 'test' ) );
//SELECT `f`.* FROM `foo` AS `f` WHERE LOWER(f.foo_name) = :where1
//:where1 = 'test'
?>
Note the absence of the execution command "()" of Select::$where allowing you to continue the method chaining.
Select::$where has a __get Magic method catch which returns the protected Select::$_where property within the Select object which is an instance of Sql\Where.
Predicate\Literal 1
<?php
$select->where( "LOWER(f.foo_name) = 'test'" );
//SELECT `f`.* FROM `foo` AS `f` WHERE LOWER(f.foo_name) = 'test'
?>
Predicate\Literal 2
<?php
$select->where( array( "LOWER(f.foo_name) = 'test'" ) );
//SELECT `f`.* FROM `foo` AS `f` WHERE LOWER(f.foo_name) = 'test'
?>
The two above automatically create a Predicate\Literal object for you if the indexed value (column identifier) of the array or argument supplied to the Select::where method is a string.
Predicate\Expression (manual)
<?php
$select->where( new Predicate\Expression( "LOWER(f.foo_name) = 'test'" ) );
//SELECT `f`.* FROM `foo` AS `f` WHERE LOWER(f.foo_name) = 'test'
?>

retrieve data from database - hash

I have a table called audits which has a column 'changes' storing data in the form of hash
I would like to retrieve all entries with the following conditions:
- auditable_type = 'Expression'
- action = 'destroy'
- changes = { :EXP_SUBMISSION_FK =>'9999992642'}
I first tried the following code which returns me with nothing:
#deleted_history = Audit.find(:all, :conditions => ["auditable_type =? AND action = ? AND changes = ?",'Expression', 'destroy' , { :EXP_SUBMISSION_FK =>'9999992642'} ])
I then tried the following code which retrieves all entries in the 'audits' table with auditable_type = 'Expression' and action = 'destroy'.
I then loop through the resultset and discards all entries where EXP_SUBMISSION_FK is not equal to 9999992642. The code below returns me 5 entries/records
#deleted_history = Audit.find(:all, :conditions => ["auditable_type =? AND action = ?",'Expression', 'destroy' ])
#deleted_history.each do |test|
if test.changes['EXP_SUBMISSION_FK'] != 9999992642
#deleted_history = #deleted_history.reject { test }
end
end
I would like to know where did I go wrong with the first code example and whether there is a way of retrieving all entries with the aforementioned conditions in a much simpler way.
Thanks a lot for your help.
i'd do:
#deleted_history.select!{|hist| hist.changes['EXP_SUBMISSION_FK'] == '9999992642'}
One potential cause of failure is that you're looking for 9999992642 but you state before the value is '9999992642'
You just use something like below. I am storing element_values as a hash and i am selecting records based on the key/value pair.
scope :find_by_field_values, lambda {
|field_name, field_value|
(where("element_values like ?", "%\"#{field_name}\":\"%#{field_value}%"))
}
just try this based on your scenario.

Resources