Join two table in zend_Validate_Db_NoRecordExists - postgresql

I need to join two tables in zend_validate_Db_NoRecordExists. I need to use exclude for each table. I am using postgresql as db.
The usual way of invoking zend_validate_Db_NoRecordExists is as follows:
$validator = new Zend_Validate_Db_NoRecordExists(
array (
'table' => 'table1',
'field' => 'flag',
'exclude' => 'delete=0',
)
);

I think you must me able to use
$validator->getSelect()->_joinUsing($type, $name, $cond);

Related

Cakephp find order by an associated model

After spending few hours to find a solution for the following issue I´m hoping you can help me.
I have two tables:
Event hasmany Appointments and Appointment belongsto Event
Now I perform in my EventsController:
$this->Event->find('all')
Now I want to order the Events by Appointments. So that the Event with the earliest Appointment is first in the array and so on. I´ve tried many ways, with Containable, Joins, Grouping, Subselects but nothing works.
To perform the find('all') on $this->Event->Appointment is not a solution due to the fact that I want every Event just ones.
Edit #1:
My only solution so far was
$events = $this->Event->find('all', array(
'joins' => array(
array(
'table' => '(SELECT event_id, MIN(start) start FROM appointments GROUP BY event_id)',
'alias' => 'Appointment',
'type' => 'LEFT',
'conditions' => array(
'Event.id = Appointment.event_id'
)
)
),
'order' => array(
'Appointment.start ASC'
)
));
But this is not the best solution!
An option is to create a virtual field representing the earliest appointment date that you can sort by
Put this in your Event model:
function __construct($id = false, $table = null, $ds = null) {
$this->virtualFields['firstappt'] = 'SELECT MIN(Appointment.created) FROM appointments AS Appointment WHERE Appointment.event_id = Event.id';
parent::__construct($id, $table, $ds);
}
You should be able to use this code in your controller:
$this->Event->find('all',array('order' => array('firstappt')));

joinLeft Zend Framework, the same field names in different tables

I've got a problem. I'm trying to left join two tables with Zend Framework using $select object. Unfortunatly my tables has common field 'name' and when I'm joining one with the other the results I get is that name field from table overwrites the name field from the other.
My code is something like that:
$select->joinLeft ( array ('users' => 'users' ), $this->_name . '.employee_id = users.user_id', array ('*' ) );
How I can join tables and avoid this issue?
Use table aliases as you would in any normal sql query!
With Zend_Db aliases are written like this:
$select = $db->select()
->from(array('p' => 'products'),
array('product_id', 'product_name'))
->join(array('l' => 'line_items'),
'p.product_id = l.product_id',
array() ); // empty list of columns
The non-zend query would look like this:
SELECT p.product_id, p.product_name
FROM products AS p
JOIN line_items AS l ON p.product_id = l.product_id;
I guess it's bit late but to get all fields from two tables you must alias all the fields
$select = $db->select()
->from(array('u' => 'users'),
array('u.id'=>'u.id','u.employee_id'=>'u.employee_id','u.name'=>'u.name'))
->joinLeft(array('e' => 'employees'),
'e.id = u.employee_id',
array('e.id'=>'e.id','e.name'=>'e.name') );
And your array would look like:
array(
0=>array(
'u.id'=>'1',
'u.employee_id'=>'1',
'u.name'=>'John Doe',
'e.id'=>'1',
'e.name'=>'Worker'
),
1=>array(
...
));

Yii fail to retrieve max column value

I have two models, one is Auction, the other is Bid.
An Auction has many Bids. they are associated by foreign key auction_id in Bid
Now, I want to find the max value of the Bid's price for each Auction.
$dataProvider = new CActiveDataProvider('Auction', array('criteria' => array(
'with' => array(
'bids' => array(
'alias'=>'b',
'group' => 'auction_id',
'select' => 'max(b.price) as maxprice'
)
)
)
)
);
And I have defined a maxprice property in Auction's model class.
However, if I try to retrieve the maxprice property, it returns NULL.
To be more specific, I render the $dataprovider to a view page, it fails to get the maxprice property.
PS:
I executed the query in mysql, the query result turns out to be correct.
So, there must be something wrong with the Yii code
SQL code:
SELECT `t`.`id` , max(b.price) as maxprice
FROM `auction` `t`
LEFT OUTER JOIN `bid` `b` ON (`b`.`auction_id`=`t`.`id`) GROUP BY auction_id
Put the value you want before the relation, like so:
$dataProvider = new CActiveDataProvider('Auction', array('criteria' => array(
'select' => 't.*, max(b.price) as maxprice',
'with' => array(
'bids' => array(
'alias'=>'b',
'group' => 'auction_id',
'together'=>true,
)
You can replace the "t.*" with specific field names if you like.
OR you can simply use the select, join and group attributes on your Auction model and skip the relation altogether.

Zend_Validate_Db_RecordExists against 2 fields

I usualy use Zend_Validate_Db_RecordExists to update or insert a record. This works fine with one field to check against. How to do it if you have two fields to check?
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => $this->_name,
'field' => 'id_sector,day_of_week'
)
);
if ($validator->isValid($fields_values['id_sector'],$fields_values['day_of_week'])){
//true
}
I tried it with an array and comma separated list, nothing works... Any help is welcome.
Regards
Andrea
To do this you would have to extend the Zend_Validate_Db_RecordExists class.
It doesn't currently know how to check for the existence of more than one field.
You could just use two different validator instances to check the two fields separately. This is the only work around that I can see right now besides extending it.
If you choose to extend it then you'll have to find some way of passing in all the fields to the constructor ( array seems like a good choice ), and then you'll have to dig into the method that creates the sql query. In this method you'll have to loop over the array of fields that were passed in to the constructor.
You should look into using the exclude parameter. Something like this should do what you want:
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => $this->_name,
'field' => 'id_sector',
'exclude' => array(
'field' => 'day_of_week',
'value' => $fields_values['day_of_week']
)
);
The exclude field will effectively add to the automatically generated WHERE part to create something equivalent to this:
WHERE `id_sector` = $fields_values['id_sector'] AND `day_of_week` = $fields_values['day_of_week']
Its kind of a hack in that we're using it for the opposite of what it was intended, but its working for me similar to this (I'm using it with Db_NoRecordExists).
Source: Zend_Validate_Db_NoRecordExists example
Sorry for the late reply.
The best option that worked for me is this:
// create an instance of the Zend_Validate_Db_RecordExists class
// pass in the database table name and the first field (as usual)...
$validator = new Zend_Validate_Db_RecordExists(array(
'table' => 'tablename',
'field' => 'first_field'
));
// reset the where clause used by Zend_Validate_Db_RecordExists
$validator->getSelect()->reset('where');
// set again the first field and the second field.
// :value is a named parameter that will be substituted
// by the value passed to the isValid method
$validator->getSelect()->where('first_field = ?', $first_field);
$validator->getSelect()->where('second_field = :value', $second_field);
// add your new record exist based on 2 fields validator to your element.
$element = new Zend_Form_Element_Text('element');
$element->addValidator($validator);
// add the validated element to the form.
$form->addElement($element);
I hope that will help someone :)
Although, I would strongly recommend a neater solution which would be to extend the Zend_Validate_Db_RecordExists class with the above code.
Enjoy!!
Rosario
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
'validators' => array('EmailAddress', $obj= new Zend_Validate_Db_NoRecordExists(array('adapter'=>$dbAdapter,
'field'=>'email',
'table'=>'user',
'exclude'=>array('field'=>'email','value'=>$this->_options['email'], 'field'=>'is_deleted', 'value'=>'1')
))),
For those using Zend 2, If you want to check if user with given id and email exists in table users, It is possible this way.
First, you create the select object that will be use as parameter for the Zend\Validator\Db\RecordExists object
$select = new Zend\Db\Sql\Select();
$select->from('users')
->where->equalTo('id', $user_id)
->where->equalTo('email', $email);
Now, create RecordExists object and check the existence this way
$validator = new Zend\Validator\Db\RecordExists($select);
$validator->setAdapter($dbAdapter);
if ($validator->isValid($username)) {
echo 'This user is valid';
} else {
//get and display errors
$messages = $validator->getMessages();
foreach ($messages as $message) {
echo "$message\n";
}
}
This sample is from ZF2 official doc
You can use the 'exclude' in this parameter pass the second clause that you want to filter through.
$clause = 'table.field2 = value';
$validator = new Zend_Validate_Db_RecordExists(
array(
'table' => 'table',
'field' => 'field1',
'exclude' => $clause
)
);
if ($validator->isValid('value') {
true;
}
I am using zend framework v.3 and validation via InputFilter(), it uses same validation rules as zend framework 2.
In my case I need to check, if location exists in db (by 'id' field) and has needed company's id ('company_id' field).
I implemented it in next way:
$clause = new Operator('company_id', Operator::OP_EQ, $companyId);
$inputFilter->add([
'name' => 'location_id',
'required' => false,
'filters' => [
['name' => 'StringTrim'],
['name' => 'ToInt'],
],
'validators' => [
[
'name' => 'Int',
],
[
'name' => 'dbRecordExists',
'options' => [
'adapter' => $dbAdapterCore,
'table' => 'locations',
'field' => 'id',
'exclude' => $clause,
'messages' => [
'noRecordFound' => "Location does not exist.",
],
]
],
],
]);
In this case validation will pass, only if 'locations' table has item with columns id == $value and company_id == $companyId, like next:
select * from location where id = ? AND company_id = ?

zend mapping one to many fetchall

I have 2 tables user and user_comment where user has many user_comments, i laid down the mapping being
User
$_dependentTables = array('User_Comments);
and
User_Comments
$_referenceMap = array(
'User' => array(
'columns' => 'id',
'refTableClass' => 'User',
'refColumns' => 'id'
)
);
Is there a way for me to do user->fetchAll() and get the user_comments without doing loop query (in cakephp it will do one query on user_comments where in (ids) then format it back to an array but i cant use cake). Is this possible in zend with me doing it manually? Thanks
Try this one
$sql=$this->getAdapter()->select()
->from("user_comment")
->join("user", "user.id=user_comment.userid")
->where("user_comment.id=?",$userId);
$result=$this->getAdapter()->query($sql)->fetchAll();
This might help u....