symfony pagination with join - symfony1

How do you paginate a query that has a join in symfony? I am trying this code but it times out:
$query=Doctrine_Query::create()
->select('c.name, d.phone')
->from('company c, companyDetails d')
->where('c.companyId=d.companyId');
$pager = new sfDoctrinePager('company',10);
$pager->setQuery($query);
$pager->setPage(1);
$pager->init();
$this->companys=$pager->getResults();

Your paginator code seems fine. I thk the problem is with your query.
Try running it without the pager and see the result.
If you continue facing issues with the query,Give this a try.
$query=Doctrine_Query::create()
->select('c.name, d.phone')
->from('company c')
->innerJoin('c.companyDetails d');
I havent tried it myself but it should work if your schema relations are defined the way i think.
One more thing, probably u already know that.
$pager->setPage(1);
should be something like
$pager->setPage($request->getParameter('page', 1));

I needed to change the count query in the pagination. To do this:
$pager = new Doctrine_Pager($query,$request->getParameter('page',1),10);
$pager->setCountQuery('SELECT COUNT(id) FROM items WHERE city_id='.$city.' AND category_id='.$category);
$this->pager=$pager;
The only thing you have to do is in your pagination helper, use:
$pagerRange = $pager->getRange('Sliding',array('chunk' => 5));
$pages = $pagerRange->rangeAroundPage();

Related

Getting activerecord readonly error when adding a where clause

I have two queries for two different pages:
all_teams = Team.includes(:terms, :labs, people: [:schools], term_enrollments: [:lab])
current_teams = Team.includes(:terms, :labs, people: [:schools], term_enrollments: [:lab]).where(terms: {id: 3)
I am trying to update the term_enrollments with each query. For the first query, everything is good. I do this with the first query:
a = all_teams.first.term_enrollments.first
a.update_attributes term: Term.find(2)
=> true
When I try to do this with the second query, it doesn't work. Here's the code I try to do for the second query:
a = current_teams.first.term_enrollments.first
a.update_attributes term: Term.find(2)
But instead of working it says:
ActiveRecord::ReadOnlyRecord: TermEnrollment is marked as readonly
Both of these queries are in controller actions and feed a page that loops through the activerecord relation and shows an edit form for each instance.
current_teams is probably doing some join which in some cases causes the records to become readonly. You can get around this with
a = all_teams.first.term_enrollments.first.readonly(false)
a.update_attributes(term: Term.find(2))

How do I use join and indexBy in Yii2?

I have this, but it loads each and every ebay row individually, generating thousands of SQL statements:
$products = \app\models\Product::find()
->joinWith('ebay', false, 'inner join')
->indexBy(function($row){return $row->ebay->epid;})
->all();
I tried this, but it gave an error: 'Getting unknown property: app\models\Product::ebay.epid'
$products = \app\models\Product::find()
->joinWith('ebay', false, 'inner join')
->indexBy('ebay.epid')
->all();
Setting eager loading = true doesn't help either. It still loads each row individually then loads them again at the end.
How can I efficiently join a table in Yii and index by a value in the joined table?
You won't be able to do it with indexBy. However, ArrayHelper::index can index an array on a related model field. So here's how it can be done:
$products = \app\models\Product::find()
->with('ebay')
->all();
ArrayHelper::index($products, 'ebay.epid');
The code will run two queries, one to get all products, one to get all related ebay products. Then the array will be indexed with no DB queries at all.
I ended up doing it manually for a subset of the ids and it only uses 2 queries. I'd still be interested in the indexBy though.
$products = Product::find()->joinWith('ebay', true, 'inner join')->where(['ebay.epid' => $productIds])->all();
$ebayProducts = array();
foreach ($products as $p) {
$ebayProducts[$p->ebay->epid] = $p;
}
If you want index by relation recods via joinWith() or with() results you can use following:
->with(['relationName' => function($q) {
$q->indexBy('field_name');
}])

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!

Update multiple rows with Propel 1.4

I need to execute following query (Using Propel 1.4/Symfony 1.4)
update notification
set read=1
where to=6 AND
action=0
For this, I wrote following code in symfony 1.4
$c=new Criteria()
$c->add(NotificationPeer::TO, $memberId, Criteria::EQUAL);
$c->add(NotificationPeer::ACTION, 0, Criteria::EQUAL);
$notification = NotificationPeer::doSelect($c);
foreach($notification as $notice)
{
$notice->setRead(1);
$notice->save();
}
Its working but if there are 100's of notification for any user, it will cost 100s of query and unnecessary load to server. I looked on doUpdate method of propel, I guess it can work for me but unable to figure out how.
IS there any way (I know there is but I don't know it) to do all that stuff in single query?
You should build two criteria:
one for the where clause
the other one for the update clause.
// Build WHERE criteria
$wherec = new Criteria();
$wherec->add(NotificationPeer::TO, $memberId, Criteria::EQUAL);
$wherec->add(NotificationPeer::ACTION, 0, Criteria::EQUAL);
// Build updated field criteria
$updc = new Criteria();
$updc->add(NotificationPeer::READ, 1);
BasePeer::doUpdate($wherec, $updc, $con);
It performs one (could be big) query. See this snippet.

Select attribute from node with XPath

I have a file with the following structure
<admin>
<sampleName>Willow oak leaf</sampleName>
<sampleDescription comment="Total genes">
<cvParam cvLabel="Bob" accession="123" name="Oak" />
</sampleDescription>
</admin>
I'm trying to get out the text "Total genes" after the sampleDescription comment, and I have used the following code:
sampleDescription = doc.xpath( "/admin/Description/#comment" )
sampleDescription = doc.xpath( "/admin/Description" ).text
But neither work. What am I missing?
might be a typo... have you tried doc.xpath("/admin/sampleDescription/#comment").text?
It's not working because there's no Description element. As mentioned by Iwe, you need to do something like sampleDescription = doc.xpath("/admin/sampleDescription/#comment").to_s
Also, if it were me, I would just do sampleDescription = doc.xpath("//sampleDescription/#comment").to_s. It's a simpler xpath, but it might be slower.
And as a note, something that trips up a lot of people are namespaces. If your xml document uses namespaces, do sampleDescription = doc.xpath("/xmlns:admin/sampleDescription/#comment").to_s. If your doc uses namespaces and you don't specify it with xmlns:, then Nokogiri won't return anything.
Try this:
doc.xpath("//admin/sampleDescription/#comment").to_s
doc.xpath returns a NodeSet which acts a bit like an array. So you need to grab the first element
doc.xpath("//admin/sampleDescription").first['comment']
You could also use at_xpath which is equivalent to xpath(foo).first
doc.at_xpath("//admin/sampleDescription")['comment']
Another thing to note is that attributes on nodes are accessed like hash elements--with [<key>]

Resources