I retrieved a record like so:
$record = $collection->find(array(
'name' => $name
));
Is there any way to update the record directly without having to requery the collection, or is it a shallow copy with no reference?
I guess you need
findAndModify
The findAndModify command atomically modifies and returns a single document. By default, the returned document does not include the modifications made on the update. To return the document with the modifications made on the update,new option can be used.
Related
I have an object that stores another subObject in it's data attribute. The subObject in the data attribute can be called vie a magic method like this:
$object->subObject. The subObject also has a data attribute in which it's value is stored. Currently when I do $object->subObject it automatically returns the value stored in the data attribute of the subObject. So basically the whole structure looks somewhat like this:
object [
data => subObject [
data => 'value'
]
]
$object->subObject //returns 'value'
I hope that this is understandable so far. Now I want to have the ability to execute someFunc() on the subObject: $object->subObject->someFunc(). That is generally not a problem. But I also want that, if I don't call a method on the subObject at all, the value of it's data attribute is returned ('value'). Is it possible to figure out within an object/a class if a method is called on it or not and act accordingly?
This is not possible. When you access a value, you get the same result regardless of what is going to be done with that value. It can't be different depending on whether you're going to call another method on it.
Remember that
$object->subObject->someFunc();
is essentially equivalent to
$temp = $object->subObject;
$temp->someFunc();
If the $object->subObject returned 'value', the first line would set $temp = 'value', and then $temp->someFunc() wouldn't work.
I'm using php sdk to delete some fields from firestore database,
i want to delete a map from an array inside a document, but instead the function used delete all maps inside the parent array.
My firestore database looks like this
What i'm trying to do is remove a specific index ex: index 0 with it's children from imageUrls array not all the maps inside it.
I tried these 2 functions :
$usersRef->update([
['path' => 'imageUrls.image_url', 'value' => FieldValue::arrayRemove(['image.png'])]
]);
and this one
$usersRef->update([
['path' => 'imageUrls.image_url', 'value' => FieldValue::deleteField()]
]);
The first function remove all imageUrls childrens and change imageUrls type from array to map, while the second one nothing happened. All the fields still exist in the document and no deletion occurd
<?php
namespace App\Services;
use Google\Cloud\Firestore\FirestoreClient;
use Google\Cloud\Firestore\FieldValue;
use Google\Cloud\Firestore\FieldPath;
class FirebaseService
{
public function delete()
{
// Create the Cloud Firestore client
$db = new FirestoreClient(
['projectId' => 'MyProjectId']
);
$usersRef = $db->collection('NewStories')->document('1');
$usersRef->update(
[
['path' =>'imageUrls.image_url',
'value' => FieldValue::arrayRemove(['image.png'])]
]);
}
}
This can be achieved using the arrayRemove() method. As the PHP Client for Firestore says
Returns a special value that can be used with set(), create() or update()
that tells the server to remove the given elements from any array value
that already exists on the server. All instances of each element
specified will be removed from the array. If the field being modified is
not already an array it will be overwritten with an empty array.
Update:
Firebase does not support updating an existing element in an indexed array.
More information can be found in the Official Documentation.
Workaround:
Reading the entire array out of the document, make modifications to it in memory, then update the modified array field entirely.**
Credits to this Firestore Update single item in an array field case.
Example: we have test table, which has 3 columns: id, watchers, title.
We have a code:
$test = Test::model()->findByPk(1);
echo $test->watchers; // 0
$test->title = 'another';
$test->save();
When we call save() ir generates sql query like "UPDATE test SET title='another', watchers='0' WHERE id='1'". SO, seams like everything is okay. But the problem is that if some another process will update watchers variable in the time between findByPk and save in current script, the code will generate wrong value. So:
$test = Test::model()->findByPk(1);
echo $test->watchers; // 0
$test->title = 'another';
//HERE WE HAVE A CODE WHICH PERFORMS FOR 1 SECOND. MEANWHILE ANOTHER PROCESS
// UPDATES TABLE WITH WATCHERS = 1
$test->save();
So, this code will save record's watchers field back to 0. How to overcome this? Why Yii ORM doesn't save only changed values? Why it tries to save all values? Thank you.
Since you get each value in $test, so when you do $test->save(); every attribute gets saved with new record or the previous value it contained.
When you query $test = Test::model()->findByPk(1); then $test->watchers; will be the same value which was there when you executed the query, this value will only change (if the value of watchers was changed by another update query) when you do another select query. Hope that makes sense :P
You can try the following update method :
Test::model()->updateByPk(1, array(
'title' => 'another'
));
Which will execute the following query:
UPDATE `test` SET `title`=:yp0 WHERE `test`.`id`=1.
Bound with :yp0='another'
I would tackle the issue as such:
$test = Test::model()->findByPk(1);
$test->title = 'another';
/*according to the api the second parameter only saves the columns
that are mentioned in the array. In this case it will save just the
title
*/
$test->save(true,array('title'));
{or}
$test = Test::model()->findByPk(1);
$test->title = 'another';
/*according to the api the parameter only saves the columns
that are mentioned in the array. In this case it will save just the
title
*/
$test->saveAttributes(array('title'));
As for me, the best solution is to inherit and rewrite the save() method and do it's behaviour the same as it is in Yii2 (getDirtyAttributes() method). W must compar eattributes to fetched from the db attributes and save only those ones, which were modified. I've successfully implemented this and can cinfirm it works.
I want to make a single revision option for saving certain objects in Sonata Admin.
I though to do this in the following way:
user edits entry
form is validated
the new information is saved as a separate entry (i'll call it revision)
the original object is not modified, except for a relation to the revision
So the code looks something like this (source Sonata\AdminBundle\Controller\CRUDController::editAction()):
$object = $this->admin->getObject($id);
$this->admin->setSubject($object);
$form = $this->admin->getForm();
$form->setData($object);
$form->bind($this->get('request')); // does this persist the object ?
// and here is what I basically want to do:
$object->setId(null);
$orig = $em->getRepository("MedtravelClinicBundle:Clinic")->find($id);
$orig->setRevision($object);
$this->admin->update($orig);
The problem is that $orig loads the already modified, so var_dump($orig === $object) is true.
I also tried $em->getUnitOfWork()->getOriginalEntityData($object); - which grabs the correct data, but as an array, not as an object (this will probably be the last resort).
So, how can I get (and save) the original object after the form bind took place ?
I think you should use the clone keyword to get a independent instance of the object you want to store. It should works by following these steps:
Load the original entity ($object)
Clone the original entity to get a new temporary entity ($newObject)
Alter the $newObject to make it a new entry: $newObject->setId(null);
Bind $newObject to the form
Save (persist) $newObject as a revision
Add the revision to ($object) and persist it too
I hope that if the form is invalid you won't lose all the data sent by the user.
Just in case, I used this answer to find the differences between the original entity and the one modified by the form.
I'm not having any luck using merge(). I'm doing almost exactly what is documented:
/* #var $detachedDocument MyDocumentClass */
$detachedDocument = unserialize($serializedDocument);
$document = $dm->merge($detachedDocument);
$document->setLastUpdated(new \MongoDate());
$dm->persist($document);
but the change never sticks. I have to do this instead:
$dm->createQueryBuilder('MyDocumentClass')
->findAndUpdate()
->field('lastUpdated')->set(new \MongoDate())
->getQuery()
->execute();
merge() seems pretty straightforward, so I'm confused why it doesn't work like I think it should.
In your first code example, merge() followed by persist() is redundant, and you omitted a flush(), which is the only operation that would actually write to the database (unless you execute a query manually, as you did in the second example). If you walk through the code in UnitOfWork::doMerge(), you'll see that it's going to either persist the object (if it has no ID) or fetch the document by its ID. The end result is that merge() returns a managed document. Persist ensures that the document will be managed after it is called (it returns nothing itself). If you poke in UnitOfWork::doPersist(), you'll see that passing a managed object to the method is effectively a NOOP.
Try replacing persist() with flush(). Note that you can flush a single document if necessary, but $dm->flush() processes all managed objects by default.
If that still doesn't help, I'd confirm that the lastUpdated field is properly mapped in ODM. You can inspect the output of $dm->getClassMetadata('MyDocumentClass') to confirm. If it isn't a mapped field, UnitOfWork will detect no changes in the document and there will be nothing to flush.
As an aside: in the second code example, you're executing findAndUpdate() without any search criteria (only the set() is specified). Typically, you'd pair the modification with something like equals() (probably the ID in your case) to ensure that a single document is atomically modified and returned.