How to simulate "not in" with a join in Zend framework? - zend-framework2

I have two relation table "demande" and "reponse" which are linked and I'd like to retrieve all the lines of "demande" not in "reponse".
I try this with a join :
$select = new Select ();
$select->columns(array("id"));
$select->from ("demande" );
$select->where->lessThan("dateArretMarche",$stringDate );
$select->join(
array("rep" => 'reponse'), // table name,
'demande.id = rep.id_demande',array(),
$select::JOIN_RIGHT);
$select ->where->isNull("rep.id");//<== it doesn't work
But I can't select "null" lines".
I guess it's possible with "not in" but Zend Framework provide only "in" predicate.
Thank all.

What if you just include it in the query? Like this:
$select ->where('rep.id IS NULL');

If you want to use isNull condition.So do you need to use with Predicate.Try with following code.
$select->where(array(
new \Zend\Db\Sql\Predicate\IsNotNull("rep.id")
)
);

Related

Yii2: How to do a inner join of three tables?

I have a many-to-many relationship so I have three tables (administrators, offices and the intermediate table):
I need to do a very simple innerjoin of the three tables to show lastnames and their offices with Active Record. I tried but I couldn't.
This is what I tried:
$admins = Admins::find()
->joinWith(Oficinas::tableName())
->all();
echo '<pre>';
print_r($admins);
echo '</pre>';
die();
Also I would like to know how to show the SQL query so it can help me to find a solution.
You need to specify the relation name for joinWith() rather than table names. Since there isn't any info on the relation names I will use simple innerJoin using table names as per your requirements to display the last name and the office name for the admins.
Admins::find()
->alias('a')
->select('a.lastnameadm, o.nombreofi')
->innerJoin('admin_oficinas ao','ao.idadm = a.idadm')
->innerJoin('oficinas o','o.idofi = ao.idofi')
->all();
Try this:
TABLE_NAME_1::find()
->join('inner join',
'table_name_2',
'table_name_2.column = table_name_1.column'
);
->join('inner join',
'table_name_3',
'table_name_3.column = table_name_2.column'
)->all();
but if you can also use Via like the following example:
public function getClassschedule()
{
return $this->hasOne(TABLE_NAME_2::className(), ['table_name_1.column' => 'table_name_2.column'])
->via('tableName3');
}
when excuded, the results should be obtained like the previous example. so there's no need to repeated relations. full documentation can be seen here :
https://www.yiiframework.com/doc/guide/2.0/en/db-active-record

Using combine and order together with Table Gateway in ZF2

When adding $select->order(...) to a previously combined Select in Zend Framework 2 the "order by" will only be added to the first Select statement.
SELECT `user`.*
FROM `user` WHERE `user_id` = :where1
ORDER BY `starttime_dt` ASC )
UNION
( SELECT `user`.*
FROM `user`
WHERE `user_id` != :subselect1where1 )
What I need is that the sorting will be applied to the full Select. A solution is already described here
https://github.com/zendframework/zf2/issues/5162#issuecomment-36294281
But this solution works with an SQL-Adapter.
How can I do that with a Table Gateway?
My code looks currently like this (resulting to the above statement)
$select = $this->tableGateway->getSql()->select();
$select2 = clone $select;
$select->where->equalTo('user_id', $user_id);
$select2->where->notEqualTo('user_id', $user_id);
$select->combine($select2);
$select->order('starttime_dt');
$resultSet = $this->tableGateway->selectWith($select);
You would do it with table gateway the same way it was illustrated in the link you provided.
Your code would look like
$select = $this->tableGateway->getSql()->select();
$select2 = clone $select;
$select->where->equalTo('user_id', $user_id);
$select2->where->notEqualTo('user_id', $user_id);
$select->combine($select2);
$combinedSelect = (new Zend\Db\Sql\Select)->from(['sub' => $select])->order('starttime_dt');
$statement = $this->sql->prepareStatementForSqlObject($combinedSelect);
$result = $statement->execute();
$resultSet = clone $this->resultSetPrototype;
$resultSet->initialize($result);
You wouldn't be able to use the TableGateway's selectWith method because it's going to check that the provided Select's table matches the TableGateway's table.

LINQ to SQL - Filtering the dataset between two nested collections

I have an MVC 3 project in Visual Studio c#. I have a LINQ to SQL query which works fine and by following an example listed elsewhere on stackoverflow:
Comparing two lists using linq to sql
I have been able to successfully reduce my results where my two nested collections match. This is the bit of code that did the trick (example from the link above):
var anyDesiredSkills = canidateSkills.Any( c => desiredSkills.Select( ds => ds.SkillId ).Contains( c.SkillId ) );
I've adapted this successfully, but now I need to be able to filter records using more than one condition. I was wondering if anyone would be able to adapt the above to show how you could include more than one condition?
To give you some background on what my goal is:
A search page where you can select any number of contacts
Each contact added to the search criteria may/may not have a 'role' assigned. If a role is present this should be factored in to the query.
Results returned based on this dynamic criteria.
Thanks in advance for any and all help :O)
It sounds like you're looking for something like:
var desiredSkillIds = desiredSkills.Select(_=>_.SkillId).ToList();
var matchingContacts =
from contact in Contacts
where contact.Role == null || desiredRoles.Contains(contact.Role)
where contact.Skills.Any(cs=> desiredSkillIds.Contains(cs.SkillId))
select contact;
Or in method-based syntax:
var matchingContacts = Contacts
.Where(contact => contact.Role == null || desiredRoles.Contains(contactRole))
.Where(contact => contact.Skills.Any(cs => desiredSkillIds.Contains(cs.SkillId)));
Here's the final code I used:
servicelist = servicelist.Where(
d => d.ContactSelection.Any(
h => model.ContactFilter.Select(ds => ds.StaffNumber).Contains(h.StaffNumber)
&&
model.ContactFilter.Select(ds => ds.ContactRole).Contains(h.ContactRole) || model.ContactFilter.Select(ds => ds.StaffNumber).Contains(h.StaffNumber) && model.ContactFilter.Select(ds => ds.ContactRole).Contains("0"))
);
Note that the last filter .Contains("0) is the value of '-- select role --' which is an option injected in to the drop down. Hope this helps anyone else!

In ZF2, Getting last insert id after insertion without using TableGateway

I need last insert id after executing a insert statement. Now I am not using TableGateway so $this->lastInsertValue is not available to me. What other options are available if I need to use Insert statement through Sql Object not a Table Gateway Object.
$objInsert = new Insert('name_master');
$objInsert->values(array( 'username' => $name,
'price' => 0,
'is_approval_needed' => 'n'
));
$sql = new Sql($this->adapter);
$result = $sql->prepareStatementForSqlObject($objInsert)->execute()->getAffectedRows();
As I need to execute multiple insert statements in different tables using last insert id of previous insert, Now I want to do it in a single method of my Model.
The Zend\Db\Adapter\Driver\DriverInterface specifies a getLastGeneratedValue() method, so presumably this should work...
$lastId = $this->adapter->getDriver()->getLastGeneratedValue();
$dbAdapter = $this->tableGateway->adapter;
$lastId = $dbAdapter->getDriver()->getConnection()->getLastGeneratedValue();

autocomplete, search multiple database tables/fields - Symfony

I have 3 models:
article [name, title]
photo [name, description]
video [name, description, transcription]
Now, I want to create an autocomplete search that will search each of those models and db fields for matching string in the input field.
Is it possible to do a search over these 3 tables?
If so, how would I go about it?
UNION operator is what you're looking for.
I guess your using propel.
Its absolutetly possible to do this, but if these table are not related to anything that could result in some messy code when saving. But if you absolutely need to search in those tables, my approach would be to create an action like:
public function executeAutocomplete(sfWebRequest $request)
{
$q = $request->getParameter('q');//The value to be searched
$limit = $request->getParameter('limit');//Not completly necessary but recommendable
if(count($q) == 0)
{
return sfView::NONE;//With no input, no search
}
$results = array( 'article' => array(), 'photo' => array(), 'video' => array());
$article_search = ArticlePeer::search($q,$limit);
$photo_search = PhotoPeer::search($q,$limit);
$video_search = VideoPeer::search($q,$limit);
$this->process_search($results,$article_search,$photo_search,$video_search);
//Process those three arrays to fit your need
return $this->renderText(json_encode($result));
}
Now, the search function on the Peer classes could look like this:
ArticlePeer>>
public static function search($q,$limit = null)
{
$c = new Criteria();
$c->add(self::NAME,'%'.$q.'%',Criteria::LIKE);
if(!is_null($limit))
{
$c->addLimit($limit);
}
return self::doSelect($c);
}
Finally as for the widget, i have used and adapted sfWidgetJQueryAutocomplete and it work pretty good so you should check it out.
EDIT: The short way to an embbed search field si creating sfForm wit the jQuery widget i mentioned before and leave configuration and js to the widget. You'll have to find a way to handle search resutls.
Well i hope this helped you!

Resources