symfony propel : wrongly populated object with criteria addJoin - php

This is my first question here, so please try to be patient with me :)
I've stumbled upon a weird behavior populating an object.
I started to convert the objectQuery::create()-> ... ->find() methods used in my project to $c = new Criteria(), $c-> ... objectPeer::doSelect($c) since I've been told Queries shouldn't be used when criteria can be.
I have a function, that returns all the prices of items from the shop. Or at least did. The thing that I cannot figure out is this:
the old code:
static public function shopGetPrices($id){
$prices = itemPriceQuery::create()->
addJoin(itemPricePeer::ITEM_ID, itemPeer::ID, Criteria::LEFT_JOIN)->
addJoin(itemPeer::CATEGORY_ID, categoryPeer::ID, Criteria::LEFT_JOIN)->
addJoin(categoryPeer::SHOP_ID, shopPeer::ID, Criteria::LEFT_JOIN)->
add(shopPeer::ID, $id)->find();
return $prices;
}
returns correctly populated PropelObjectCollection object, through which i can go with foreach, and get/set the itemPrice objects and attributes i need.
now, the new code:
static public function shopGetPrices($id){
$c = new Criteria();
$c->addJoin(itemPricePeer::ITEM_ID, itemPeer::ID, Criteria::LEFT_JOIN)->
addJoin(itemPeer::CATEGORY_ID, categoryPeer::ID, Criteria::LEFT_JOIN)->
addJoin(categoryPeer::SHOP_ID, shopPeer::ID, Criteria::LEFT_JOIN)->
add(shopPeer::ID, $id);
return self::DoSelect($c);
}
returns an array of itemPrice objects, but they are populated with item values related to itemPrice objects through join. that means : when I call print_r(self::DoSelect($c)); it prints
Array
(
[0] => ItemPrice Object
(
[startCopy:protected] =>
[id:protected] => 47 <- id of joined item
[item_id:protected] => 9 <-foreign key to category object of joined item
[price:protected] => 0
[unit:protected] => Axe <- name of item, not unit (unit is like 'golden', 'iron', 'wood' or whatever )
[active:protected] =>
[collItemsOrder:protected] =>
[collItemsOrderPartial:protected] =>
[alreadyInSave:protected] =>
[alreadyInValidation:protected] =>
[polozkyObjednavkasScheduledForDeletion:protected] =>
[prisadyPolozkyObjednavkasScheduledForDeletion:protected] =>
[validationFailures:protected] => Array()
[_new:protected] =>
[_deleted:protected] =>
[modifiedColumns:protected] => Array()
[virtualColumns:protected] => Array()
)
[1] => ItemPrice Object
(
...and so on.
There is probably some crucial difference between criteria and query object, that I'm missing. I searched on Google, StackOverflow, and who knows where, but I didn't find anything resembling a solution to this.
This guy/gal had a vaguely similar problem, but I didn't use addSelectColumn with my criteria, so it's been another dead end for me.
Can anyone please point me in the right direction?

I found the problem. It was that I had overriden method do select in itemPricePeer class
public static function doSelect(Criteria $criteria, PropelPDO $con = null){
$critcopy = clone $criteria;
$critcopy->add(self::ACTIVE, 1);
return self::populateObjects(itemPeer::doSelectStmt($critcopy, $con));
}
I switched self/itemPricePeer with itemPeer in populateObjects arguments. silly me :-/ Thanks for your responses anyway j0k.

Related

use an object of array

Actually coding a laravel web app. I made a function which retrieves me some IDs from mysql that I need to work with.
This function returns me an object ( var_dump)
object(Illuminate\Support\Collection)[335]
protected 'items' =>
array (size=3)
0 =>
object(stdClass)[334]
public 'crschpsup_id' => int 107
1 =>
object(stdClass)[333]
public 'crschpsup_id' => int 108
2 =>
object(stdClass)[340]
public 'crschpsup_id' => int 235
How can I use them one by one, $myobject->items or $myobject[0] as for arrays doesn't work also.
Thanks for help
In most cases laravel uses a collection class to work easily with arrays or sets of objects. Rows selected from database, session bag messages, all of them are collections.
Collections can be used in foreach loop as array.
foreach($collection as $item)
{
// do whatever you want with $item
}
Of course you can still access nth element of collection by using
$collection[$nth]
or
$collection->nth($nth)
And remember. Always read documentation before work with something new, before asking, before overthinking things.

PHP Traversing Multi Dimensional (Array)Object

I have an object that needs to be returned, however I need to perform some pre-return manipulation before returning it.
The object has the following format:
object(PaginationHelper)[3]
public 'current_page' => int 1
public 'items_per_page' => int 10
public 'dataset' =>
array (size=10)
0 =>
object(AdvertSet)[4]
public 'Keywords' => string '' (length=0)
protected 'Adverts' =>
array (size=3) // SIZE = 3 SO REMOVE THIS FROM 'dataset' ARRAY
...
public 'LiveStatus' => boolean false
1 =>
object(AdvertSet)[5]
public 'Keywords' => string '' (length=0)
protected 'Adverts' =>
array (size=1) // SIZE = 1 SO KEEP THIS IN 'dataset' ARRAY
...
public 'LiveStatus' => boolean false
etc etc ....
[End Object]
What I need to do:
Remove all parts of the 'dataset' array that doesn't have an 'Adverts' count of 1, thereby preserving only those datasets that have an 'Adverts' array size of 1.
Retain the fact that it is an object, to be returned.
I've tried multi-dimensional recursive functions to get through this, however the fact that it's an object and not an array is making progress hard, and I'm not sure I would be able to convert from an object to an array and back again without messing up the object's internals.
Can anyone help with this? Here's what I've gotten so far with a foreach...
foreach($results as $key => $value) {
if($key == 'dataset') {
// value is right array to check count
foreach($value as $k => $v) {
echo $v;
}
}
}
It doesn't work, but that's the method I'm currently working on.
I've also tried something like:
if(count($results->dataset->(Array)AdvertSet->Adverts == 1) { }
but I can't cast AdvertSet as Array.. Any help would be greatly appreciated!
Just a quick note: it doesn't have to be removed from the array, I just eventually need the same object without those that have an Adverts count of 3. So this could involve copying to a new array without those that have an Adverts count of <> 1.
My first thought was:
foreach($PaginationHelper->dataset as &$data) {
if(count($data) !== 1)
unset($data);
}
But after reading your question for the third time, I see you want to remove only those elements with a Adverts count not equal to 1.
Looking at your structure, the Adverts array is protected, and therefore there is now way to access it without subclassing Advertset object.
So, my final answer must be: It is not possible to remove them, with this structure!
Your data structure is not really recursive and you don't need recursive traversal.
You only need to iterate over the $object->dataset array and delete items where the count of adverts is not 1. Since you're trying to filter items over a protected property, one approach would be to implement a AdvertSet::count() method that would return number of contained adverts: $object->dataset[$i]->Adverts->count() != 1. I would advise against forcing your way to access the protected property just for the filtering's sake.

CakePHP query array

I am running this query using CakePHP:
$total = $this->Lapse->query("select sum(unix_timestamp(stop) - unix_timestamp(start)) from lapses where id = ".$lastId."");
And i get back this array structure:
Array
(
[0] => Array
(
[0] => Array
(
[sum(unix_timestamp(stop) - unix_timestamp(start))] => 1
)
)
)
So my variable holds this: $updateVal = $total[0][0][0];
Which isn't the prettiest, is there a way i can simplify this OTT array?
Have you tried the find() method passing a custom fields option?:
$this->Lapse->find('all', array(
'fields' => array('sum(unix_timestamp(stop) - unix_timestamp(start)) as elapsed_time'),
'conditions' => array('Lapse.id' => $lastId),
));
The returned array is prettier than the one you're getting, although it's not prettier than elapsed_time being an actual model property.
Another solution would be to set elapsed_time as a virtual field within the model:
class Lapse extends AppModel {
...
public $virtualFields = array(
'elapsed_time' => 'sum(unix_timestamp(Lapse.stop) - unix_timestamp(Lapse.start)',
);
...
}
Then elapsed_time acts as a model property and would be returned as $updateVal['Lapse']['elapsed_time'] in every find() call.

CakePHP models findFirst method issue

I'm not familiar with CakePHP too close. Recently I've ran into problem using Model. I need to get exaclty one row from database, modify some columns values and save it back. Pretty simple, right?
What do I try to do:
$condition = array('some_id_column' => $another_models_id);
$model = $this->MyModel->findFirst($condition);
BUT i get FALSE in $model variable. At hte same time
$condition = array('some_id_column' => $another_models_id);
$model = $this->MyModel->findAll($condition);
returns array. Its structure is something like:
array (
0 =>
array (
'MyModel' =>
array (
'id' => '1',
'some_id_column' => '123456',
'some_field' => 'some text',
...
),
),
I'd go with findAll if it did not return an array of arrays, but array of models (in my case - of one model). What do I want to achieve:
$condition = array('some_id_column' => $another_models_id);
$model = $this->MyModel->findFirst($condition);
$model->some_field = 'some another text';
$model->save();
Could you help me out to understand how it's usually done in CakePHP?
I'd also like to hear why findAll finds row and findFirst fails to find it... It just does not make sense to me... They should work in almost the same way and use the same database APIs...
If I can not do what I want in CakePHP, would you write a receipt how it is usually done there ?
There is no such method as findFirst.
You're probably looking for find('first', array('conditions' => array(...))).

How to work with join data in codeigniter?

I am having a play around with codeigniter and trying to get my head around the active record system and such like.
I have set up a couple of tables and am attempting to run a join on them, as such:
function GetOrganisationsAndBuildingDetails()
{
$this->db->select('organisations.organisation_name,
organisations.organisation_id,
buildings.building_name,
buildings.address1');
$this->db->from('organisations')->join('buildings', 'buildings.organisation_id = organisations.organisation_id');
$query = $this->db->get();
return $query->result();
}
In my database i have one organisation with two related buildings. The above query returns two objects (one for each building) - however, the organisation is duplicated.
stdClass Object (
[organisation_name] => This is an example org
[organisation_id] => 1
[building_name] => test building
[address1] => 123456 )
stdClass Object (
[organisation_name] => This is an example org
[organisation_id] => 1
[building_name] => teeeest building
[address1] => 123456 )
I suppose I was expecting something along the lines of one return object with a series of nested objects for related buildings. Is this possible?
If not, is their a recommend way of arranging the return data so I can easily loop through it in the view? (foreach org, foreach building etc etc).
Apologies if I'm being a little dense here. Im coming from .net and (linq to SQL in particular) where this stuff is a little different)
The query will inevitably return duplicate data as you say, you have to organize them after you get the result like this
$buildings = array();
foreach ( $result_object as $organization ) {
$building_data = array(
'building_name' => $organization->building_name,
'address' => $organization->address,
);
$buildings[$organization->organization_name][] = $building_data;
}
this way organizations will be "compacted" in the first key of the multidimensional array, and one level deeper you will have info about the buildings. Hope this helps.

Categories