Lets say I create a table object in magento -
$model = Magento::getModel('table1')
$model->getCollection()->getFirstItem->setname('newname');
But I dont save it . I dont want to store it in db now.
Now I do
$model2 = Mage::getSingleton('table1')
# It should return same table object.
$name = $model->getCollection()->getFirstItem->getname();
I dont get $name as newname, above line fires a sql and gets the name from DB, logically if I am getting same object from singleton then I should be able to retrieve the $name value as newname.
The first request for your model uses getModel. This retrieves an instance model.
The second request for your model users getSingleton. This instantiates an instance model and registers it as a singleton. From this point on, future requests to getSingleton or getModel will return the same object. However, models instantiated with getModel prior to registers the model as a singleton will maintain their instance state.
"Works as Designed"
Related
When using Eloquent on Laravel, I have a relationship which I can call via:
$business = $this->business()->first();
Unfortunatley each time this code is run it returns a new instance of the related model. e.g.
$business1 = $this->business()->first();
$business2 = $this->business()->first();
$business1->value = 5;
In the above code $business2->value should equal 5, but it doesn't.
Is there a way to force eloquent to return a reference to the model if it already exists in memory rather than creating a new one each time?
I can't get my head around this:
$fragment = factory(Fragment::class)->create();
$this->assertCount(0, $fragment->values);
fragment->fetch(); // updates the 'values' by adding one Value object.
var_dump($fragment->id); // i.e. 6
var_dump(Fragment::first()->id); // 6
var_dump($fragment->values->count()); // 0
var_dump(Fragment::first()->values->count()); // 1
$this->assertCount(1, $fragment->values);
I use DatabaseTranscations, so after a Fragment is created, there is always one and only one. Thus, $fragment and Fragment::first() are the exact same instance. Yet... the values relationship is different. How can this be the case?
Note that this happens only during testing, when I manually test this through my controller (and the values are passed to the blade template page) it works just fine. I am confused :S.
Any ideas?
Relationship attributes ($fragment->values) are only loaded once. They are not kept up to date when you add or delete items from the relationship. They do not hit the database every time to check for changes.
Your second line is $this->assertCount(0, $fragment->values);. Accessing $fragment->values here lazy loads the relationship, and as your assert proves, it is empty.
You then call $fragment->fetch(), in which your comment says it adds a Value object to the fragment. However, your relationship attribute ($fragment->values) has already been loaded from the previous statement, so it will not reflect the additional Value object you added to the relationship.
Therefore, even after the call to fetch(), $fragment->values is still going to be an empty collection. Fragment::first()->values will contain the newly related Value though, because it is getting a new instance of the Fragment, and when it loads the values for the first time, it will pick up the related Value.
When you need to reload the relationship, you can use the load() method. If you add this after your call to fetch() (or put it in your fetch() method, whichever makes sense for you), your test will work fine.
$fragment = factory(Fragment::class)->create();
$this->assertCount(0, $fragment->values);
$fragment->fetch(); // updates the 'values' by adding one Value object.
var_dump($fragment->id); // i.e. 6
var_dump(Fragment::first()->id); // 6
var_dump($fragment->values->count()); // 0
// reload the values relationship
$fragment->load('values');
var_dump($fragment->values->count()); // 1
var_dump(Fragment::first()->values->count()); // 1
$this->assertCount(1, $fragment->values);
The other option you have is to use the relationship query by accessing the relationship method instead of the relationship attribute. If you do $fragment->values()->count() (note: values(), not values), that will hit the database every time and always return the current count.
I have an Eloquent class Member with relationships defined as District, Profession
An instance of Member class can be passed to a method which replaces placeholders from a string using this instance.
The placeholders are of format %placeholder%, where placeholder can be either an attribute of Member class or an attribute from its relation using dot notation like %name%, %district.name%
The problem I face is that I get Member instance without relations eager loaded.
So I have to reload the instance like this.
$member = Member::with(['district', 'profession'])->find($member->id);
Then I replace the placeholders using this syntax.
$member = $member->toArray();
$placeholders = array_keys($member);
foreach($placeholders as &$placeholder) {
$placeholder ='%'.$placeholder.'%';
}
$finalString = str_replace($placeholders, array_values($member), $string);
Please guide whether I am doing it efficiently or there is some other way to achieve this. Especially I don't want to make another db call to eager load relations so that they can be converted to array.
You don't have to reload the member. Use load to lazy eager load the relations:
$member->load('district', 'profession');
$newMembership = JTable::getInstance('MembershipSold', 'Table');
$newMembership->load($this->membership_sold_id);
$this->membership_sold = $newMembership;
$dispatcher->trigger('onAfterMembershipChanged', array($newMembership));
return parent::store();/* whats the use of above code */
$newMembership = JTable::getInstance('MembershipSold', 'Table');
This line is getting is a static method to get an instance of a JTable class, specifically one called "MembershipSold". You can read about JTable (Joomla's abstract table class) here, the document is a little out of date but you can read the relevant JTable class in your Joomla installation at /libraries/joomla/database/table.php
$newMembership->load($this->membership_sold_id);
This line uses the membership_sold_id to load a record from the table in the database.
$this->membership_sold = $newMembership;
This line inserts the JTable object (now holding the record loaded from the table) into the $this.
$dispatcher->trigger('onAfterMembershipChanged', array($newMembership));
This line appears to be triggering an event and passing in the $newMembership object (Joomla supports a basic event system for plugins etc to act on), you can read more about it in this document "Supporting plugins in your component"
return parent::store();
This line is calling the current objects parent's store() method. See PHP:parent
I'm coding an API and I'm doing the create method. I'm doing the following without needing a form:
$params = array('title' => 'test', 'parent_id' => 781);
// bind data
$place = new Place();
$place->bind($params);
// validate params
$errors = $this->validator->validate($place);
I need to check that parent_id is a correct value (its object exist - i know how to do this) and after that, I need to set some values dependent on the parent. So at the end the Place object will have the fields: title, parent_id, level, country_id for example.
How would you do this? On the validation? How? If not, how to avoid calling two times the DB to get the parent object?
You should first validate & then set any additional values afterward. Anything that modifies the value does not belong in the validator.
If your using doctrine, it should load the parent object into memory when you first access it, so it won't need to actually query the database again when you access the parent object a second time.