I'm building a Task in Symfony with Doctrine. I'm getting all the places to make a batch update to a particular field. This has to be done in two languages. I'm using setBaseQuery() to make the JOIN on the query with the language I want.
If I do the following in an action, it works without any problem. However, If I do it in a task; it doesn't work as expected. The task runs perfectly two times (one in english and the other in english too!).
Any ideas on what I have to do different on tasks?
thanks!
$languages = array('es' => 'Spanish', 'en' => 'English');
foreach($languages as $lang => $value) {
// get all the places
$q = Doctrine::getTable('Place')
->createQuery('p')
->leftJoin('p.Translation ptr')
->addWhere('ptr.lang = ?', $lang);
$treeObject = Doctrine::getTable('Place')->getTree();
$rootColumnName = $treeObject->getAttribute ( 'rootColumnName' );
$treeObject->setBaseQuery($q);
// all the continents
foreach ( $treeObject->fetchRoots() as $continent ) {
$this->log(date("Y-m-d H:i:s").' '.$lang.' Continent '.$continent->title);
..
}
}
To gain database access in your tasks you'll need to call the following in your execute() method before any other database calls:
$databaseManager = new sfDatabaseManager($this->configuration);
http://www.symfony-project.org/book/1_2/16-Application-Management-Tools#chapter_16_sub_custom_tasks_new_in_symfony_1_1
so the solution I've found is adding $model->Translation[$lang]->title. It's strange because the title should have been loaded through the setbasequery; but it seems not.
// all the continents
foreach ( $treeObject->fetchRoots() as $continent ) {
$this->log(date("Y-m-d H:i:s").' '.$lang.' Continent '.$continent->Translation[$lang]->title);
..
}
Update
I'm getting the translation but $continent->save() didn't save the changes in Spanish (however it's saving it in English). I had to do a manual query in Doctrine:
$con = Doctrine_Manager::getInstance()->connection();
...
$con->execute("update model_translation set field='".$field."' where id='".$model->id."' and lang='".$lang."'");
now everything works...
Related
I am still very new to Zend and running into some issues on exporting my data to a CSV.
I found a great resource that explains the headers and download part here however I am running into issues when trying to export the actual data.
If I create a variable like $content = "test" the export works fine using the code above.
However when I duplicate my indexAction code, make some changes, and bring it into my downloadAction, I am getting issues that I believe are due to my content being returned as an Object rather than an array or string.
My Module is grabbing the SQL by using:
public function fetchAllMembers($order = null , $order_by = null, $selectwhere = null) {
$session = new SessionContainer('logggedin_user');
$sql = new Sql($this->adapter);
$select = new Select();
$select->from(array('u' => 'tbl_all_data'));
if ($selectwhere != null){
$select->where($selectwhere);
}
$select->order($order_by . ' ' . $order);
$selectString = $sql->getSqlStringForSqlObject($select);
$results = $this->adapter->query($selectString, Adapter::QUERY_MODE_EXECUTE);
$results->buffer();
return $results;
}
and my Controller is calling that SQL by using:
$content = $modulesTable->fetchAllMembers($order, $order_by, $where);
Any help would be greatly appreciated, and I don't need anyone to write the code for me just help with pointoing me in the right direction.
$this->adapter->query returns a Zend\Db\ResultSet object. So you need to call $results = $results->toArray(); to send an array.
Also you need to loop through the array and echo it out in your view file.
Results, returned by adapter are ResultSet type. I guess you need to call at least
current()
method to grab some data. And they will be of array type, so, again you need to do something with them.
toArray() is often used to quickly get data.
More sophisticated way to get data, is to use next() method with current():
$firstThing = $result->current();
$result->next();
$result->next();
$thirdThing = $result->current();
It's just an example, but it can be useful in some cases.
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!
I'm attempting to write a search function for a database table that needs to access information from related tables using Entity Framework. However, I'm running into problems getting the data back out of my initial query after doing a join on the parent table and the related tables. My code currently looks like this. I initialize my queryable object
IQueryable<PurchaseOrder> po = _context.PurchaseOrders;
Where PurchaseOrder is an Entity type. Then there is a series of blocks like this.
if (!String.IsNullOrEmpty(searchViewModel.Comment)){
var helper = _context.PurchaseOrderComments.Where(x => x.CommentText.Contains(searchViewModel.Comment));
var mid = po.Join(helper, r => r.PurchaseOrderID, u => u.PurchaseOrderID, (r, u) =>
new
{
PurchaseOrderID = r.PurchaseOrderID,
PurchaseOrderNumber = r.PurchaseOrderNumber,
VendorID = r.VendorID,
ContractNumber = r.ContractNumber,
BuyerUserID = r.BuyerUserID
});
po = mid.Select(x => new PurchaseOrder
{
PurchaseOrderID = x.PurchaseOrderID,
PurchaseOrderNumber = x.PurchaseOrderNumber,
VendorID = x.VendorID,
ContractNumber = x.ContractNumber,
BuyerUserID = x.BuyerUserID
});
}
After each block, po is passed to the next search parameter. However, as you might guess, my program complains that I can't build a complex type in mid's Select statement. I've also tried building PurchaseOrder objects from the contents of mid, inserting them into a new List of PurchaseOrders, and converting that list into a queryable to assign to po to pass on to the next block. However, that changes po's data type from System.Data.Object.ObjectSet to System.Collections.Generic.List, which then throws an InvalidOperationException the next time I try and iterate through it using a foreach.
So my question is, are there any obvious mistakes in my approach or any suggestions for other ways to approach the problem? Thanks very much for any help.
I think you're making this more complicated than it needs to be. If I understand what you're trying to do, you should be able to do something like this:
if (!String.IsNullOrEmpty(searchViewModel.Comment)){
po = po.Where(
o => o.PurchaseOrderComments.Any(
c => c.CommentText.Contains(searchViewModel.Comment)));
}
StriplingWarrior's solution is the best way. In case that your PurchaseOrder class really doesn't have a navigation collection of PurchaseOrderComments (which would force you to use a join) the following should work and is simpler as your double projection:
po=po.Join(helper, r => r.PurchaseOrderID, u => u.PurchaseOrderID, (r, u) => r);
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!
edit #2: Question solved halfways. Look below
As a follow-up question, does anyone know of a non-intrusive way to solve what i'm trying to do below (namely, linking objects to each other without triggering infinite loops)?
I try to create a asp.net-mvc web application, and get a StackOverFlowException. A controller triggers the following command:
public ActionResult ShowCountry(int id)
{
Country country = _gameService.GetCountry(id);
return View(country);
}
The GameService handles it like this (WithCountryId is an extension):
public Country GetCountry(int id)
{
return _gameRepository.GetCountries().WithCountryId(id).SingleOrDefault();
}
The GameRepository handles it like this:
public IQueryable<Country> GetCountries()
{
var countries = from c in _db.Countries
select new Country
{
Id = c.Id,
Name = c.Name,
ShortDescription = c.ShortDescription,
FlagImage = c.FlagImage,
Game = GetGames().Where(g => g.Id == c.GameId).SingleOrDefault(),
SubRegion = GetSubRegions().Where(sr => sr.Id == c.SubRegionId).SingleOrDefault(),
};
return countries;
}
The GetGames() method causes the StackOverflowException:
public IQueryable<Game> GetGames()
{
var games = from g in _db.Games
select new Game
{
Id = g.Id,
Name = g.Name
};
return games;
}
My Business objects are different from the linq2sql classes, that's why I fill them with a select new.
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
edit #1: I have found the culprit, it's the following method, it triggers the GetCountries() method which in return triggers the GetSubRegions() again, ad nauseam:
public IQueryable<SubRegion> GetSubRegions()
{
return from sr in _db.SubRegions
select new SubRegion
{
Id = sr.Id,
Name = sr.Name,
ShortDescription = sr.ShortDescription,
Game = GetGames().Where(g => g.Id == sr.GameId).SingleOrDefault(),
Region = GetRegions().Where(r => r.Id == sr.RegionId).SingleOrDefault(),
Countries = new LazyList<Country>(GetCountries().Where(c => c.SubRegion.Id == sr.Id))
};
}
Might have to think of something else here :) That's what happens when you think in an OO mindset because of too much coffee
Hai! I think your models are recursively calling a method unintentionally, which results in the stack overflow. Like, for instance, your Subregion object is trying to get Country objects, which in turn have to get Subregions.
Anyhow, it always helps to check the stack in a StackOverflow exception. If you see a property being accessed over and over, its most likely because you're doing something like this:
public object MyProperty { set { MyProperty = value; }}
Its easier to spot situations like yours, where method A calls method B which calls method A, because you can see the same methods showing up two or more times in the call stack.
The problem might be this: countries have subregions and subregions have countries. I don't know how you implement the lazy list, but that might keep calling GetCountries and then GetSubRegions and so on. To find that out, I would launch the debugger en set breakpoints on the GetCountries and GetSubRegions method headers.
I tried similar patterns with LinqToSql, but it's hard to make bidirectional navigation work without affecting the performance to much. That's one of the reasons I'm using NHibernate right now.
To answer your edited question, namely: "linking objects to each other without triggering infinite loops":
Assuming you've got some sort of relation where both sides need to know about the other... get hold of all the relevant entities in both sides, then link them together, rather than trying to make the fetch of one side automatically fetch the other. Or just make one side fetch the other, and then fix up the remaining one. So in your case, the options would be:
Option 1:
Fetch all countries (leaving Subregions blank)
Fetch all Subregions (leaving Countries blank)
For each Subregion, look through the list of Countries and add the Subregion to the Country and the Country to the Subregion
Option 2:
Fetch all countries (leaving Subregions blank)
Fetch all Subregions, setting Subregion.Countries via the countries list fetched above
For each subregion, go through all its countries and add it to that country
(Or reverse country and subregion)
They're basically equialent answers, it just changes when you do some of the linking.