how to use ObjectId inside $in query in MongoDB? - php

I have the following query in MongoDB
$this->createQueryBuilder()
->field('actor')->in($actorIdArray)
->getQuery()
->execute();
where the field actor is an object reference with annotation
#MongoDB\ReferenceOne(targetDocument="User", simple=true)
which means it will store the object Id instead of the full reference.
When $actorIdArray is an array of id with the form
["5706cb39821b166d3931f34f", "56015f7d4f8bd90b769e6e75"]
the query does not return nothing, which is the expected since the filed actor contains object id.
However, if I build the array this way
[new MongoId("5706cb39821b166d3931f34f"), new MongoId("56015f7d4f8bd90b769e6e75")]
it doesn't work either, which is quite surprising for me.
The log shows the query is made
{ "actor": {"$in":[{"$id":"5706cb39821b166d3931f34f"},{"$id":"56015f7d4f8bd90b769e6e75"}]}}
and I think it should be something like this
{ "actor": {"$in":[ObjectId("5706cb39821b166d3931f34f"),ObjectId("56015f7d4f8bd90b769e6e75"]}}
Not sure if I am doing something wrong,
any ideas?

As you can see in code source of Doctrine\ODM\MongoDB\Query\Builder -> references method:
public function references(object $document) : self
{
$this->requiresCurrentField();
$mapping = $this->getReferenceMapping();
$reference = $this->dm->createReference($document, $mapping);
$storeAs = $mapping['storeAs'] ?? null;
$keys = [];
switch ($storeAs) {
case ClassMetadata::REFERENCE_STORE_AS_ID:
$this->query[$mapping['name']] = $reference;
return $this;
.....
return $this;
}
You must know how the reference is built. Usually, this is by $id.
Use actor.$id as the field name:
$dm = $this->get('doctrine.odm.mongodb.document_manager'):
$documents = array();
foreach($actorIdArray as $id){
$documents[] = new MongoDB\BSON\ObjectId($id);
}
$this->createQueryBuilder()
->field('actor.$id')->in($documents)
->getQuery()
->execute();

Doctrine wants your array to be an array of documents.
You can load document references without query.
$dm = $this->get('doctrine.odm.mongodb.document_manager'):
$documents = array();
foreach($actorIdArray as $id){
$documents[] = $dm->getReference('AppBundle:Actor',$id); // <- this is the key
}
$this->createQueryBuilder()
->field('actor')->in($documents)
->getQuery()
->execute();

Related

Laravel Collection Loop to another Collection

How to loop the eloquent collection from one to another? I'm just getting first line of array. I have more than 4 array in the collection.
$queries = Students::where('year',"=", 1)->get();
$students = new Students();
foreach ($queries as $query) {
$students->name = $query->name;
$students->faculty = $query->faculty ."Add something";
$students->year = $query->year;
}
dd($students);
I want to change the collection a bit before I print to json. For example, I want add something behind the faculty
Use the transform() method to modify collection:
$students = Students::where('year', 1)->get();
$students->transform(function($i) {
$i->faculty = $i->faculty . 'add something';
return $i;
});
You also can use resource classes to transform the data before returning JSON response.
You could use map() to modify collection-
$queries = $queries->map(function($query){
$query->faculty = $query->faculty."kfjhgli";
return $query;
});
return $queries;

How to use IS NOT NULL in Associative Array

I am new in Symfony framework And I want to use Query basis on Condition
which is using associative array and I want to use IS NOT NULL But it is not
working.
$repository = $this->getDoctrine()->getRepository('AppBundle:Order');
$order = $repository->findBy(array('status' => $last_status,'new_coloumn_id'=>"IS NOT NULL"));
How to use IS NOT NULL in array.
You should add custom function into your Order Repository file(class). Example;
public function getOrderStatus($last_status = NULL){
$query = $this->createQueryBuilder('order')
->where('order.new_column_id IS NOT NULL')
->andWhere('status = :status')
->setParameter('status', $last_status);
return $query->getQuery()->getResult();
}
And you can use it;
$order = $this->getDoctrine()->getRepository('AppBundle:Order')->getOrderStatus($last_status)
Try this in your repository class:
public function findOrder($last_status){
$qb = $this->createQueryBuilder('order');
return $qb->where($qb->expr()->isNotNull('order.new_column_id'))
->andWhere($qb->expr()->eq('order.status',':last_status'))
->setParameter('last_status',$last_status)
->getQuery()
->getOneOrNullResult();//getArrayResult,getResult()
}
hope it helps...

Laravel conditions in Controller where clause

I'm trying to build a query based on URL parameters. When the Controller is loaded I need to check which parameters have been provided and build a query from them. It's working with static values, but isn't working with conditional statements. Is my laravel syntax correct?
class OrdenesController extends BaseController {
public function showOrdenes($action)
{
$my_id = Auth::user()->id;
$my_cod = Auth::user()->codprov;
switch ($action)
{
case 'list':
$rows = DB::table('ordens')->count();
if(Input::get("jtSorting"))
{
$search = explode(" ", Input::get("jtSorting"));
$numorden= Input::get("nro_orden");
$filtros =explode(" ", $filtros);
$data = DB::table("ordens")
->select(array('*', DB::raw('SUM(cant_pend) as cant_pend'), DB::raw('SUM(importe) as importe')))
->where('cod_prov', '=', $my_cod)
->where('nro_orden', '=', $numorden)///work
---------- ////no work
if (Input::has('nro_orden')) {
->where('nro_orden', '=', $numorden)
}
---------- /// no work
->groupBy('nro_orden')
->skip(Input::get("jtStartIndex"))
->take(Input::get("jtPageSize"))
->orderBy($search[0], $search[1])
->get();
}
return Response::json(
array(
"Result" => "OK",
"TotalRecordCount" => $rows,
"Records" => $data
)
);
break;
};
}
}
You are missing the variables, no? You haven't told PHP what variable/object to do the where() to in your condition. The magic of Laravel's Eloquent (and a lot of other libraries) is that when you call its methods, it returns itself (the object) back so you can make another method call to it right away.
So when you do this:
$data = DB::table("ordens")
->select(...)
->where(...);
is the same as:
$data = DB::table("ordens");
$data = $data->select(...);
$data = $data->where(...);
But you are trying to do ->where(...) right away after if condition. You need to tell PHP which object/variable you are trying to call the method from. Like this:
$num = Input::get("nro_orden");
$data = DB::table("ordens")
->select(array('*', DB::raw('SUM(cant_pend) as cant_pend'), DB::raw('SUM(importe) as importe')))
->where('cod_prov', '=', $my_cod);
if (Input::has('nro_orden')) {
$data = $data->where('nro_orden', '=', $num);
}
$data = $data->groupBy('nro_orden')
->skip(Input::get("jtStartIndex"))
->take(Input::get("jtPageSize"))
->orderBy($search[0], $search[1])
->get();

Laravel modifying model, after retrieving data

I don't want to modify the object when ever I call it, and I am looking that upon call, the modifications are done automatically.
In a controller, I have the following:
$candidate = Candidate::where('slug', '=', $slug)->first();
And then I do:
if (!is_null($candidate->social_profiles) && !empty($candidate->social_profiles)) {
$candidate->social_profiles = unserialize($candidate->social_profiles);
foreach ($candidate->social_profiles as $key => $value) {
$candidate->{$key} = $value;
}
$candidate->social_profiles = null;
}
Now, I am looking for a way, to do the last part, inside the very own Candidate model, so that whenever a candidate is retrieved, it does the code above, that way I wont have to duplicate the last part above, wherever I get a candidate.
The problem is, that I don't know where to do so. $this in __construct contains only data defined in the class, which is basically an empty model. What else?
This is probably personal taste, but I would create a CandidateRespository class that has a method findBySlug (or whatever you'd like to call it):
public function findBySlug($slug)
{
$candidate = Candidate::where('slug', '=', $slug)->first();
if (!is_null($candidate->social_profiles) && !empty($candidate->social_profiles)) {
$candidate->social_profiles = unserialize($candidate->social_profiles);
foreach ($candidate->social_profiles as $key => $value) {
$candidate->{$key} = $value;
}
$candidate->social_profiles = null;
}
return $candidate;
}
Pass the repository into your controller using dependancy injection and then call it using:
$candidate = $this->candidate->findBySlug($slug);
Here's some more reading: http://laravel.com/docs/ioc & http://culttt.com/2013/07/08/creating-flexible-controllers-in-laravel-4-using-repositories/
Hope that helps.

Copy a Doctrine object with all relations

I want to copy a record with all his relations.
I'm trying with:
$o = Doctrine::getTable('Table')->Find(x);
$copy = $object->copy();
$relations = $o->getRelations();
foreach ($relations as $name => $relation) {
$copy->$relation = $object->$relation->copy();
}
$copy->save();
This code doesn't works, but I think it's on the way.
I never could get the deep copy function to operate correctly.
I manually coded a deep copy function for one of my models like this
public function copyAndSave ()
{
$filters = array('id', 'created');
$survey = $this->copy();
$survey->Survey_Entries = new Doctrine_Collection("Survey_Model_Entry");
$survey->Assignment_Assignments = new Doctrine_Collection("Assignment_Model_Assignment");
$survey->Survey_Questions = new Doctrine_Collection("Survey_Model_Question");
$survey->save();
foreach ($this->Survey_Questions as $question)
{
$answers = $question->Survey_Answers;
$newQuestion = $question->copy();
$newQuestion->survey_surveys_id = $survey->id;
$newQuestion->save();
$newAnswers = new Doctrine_Collection("Survey_Model_Answer");
foreach($answers as $answer)
{
$answer = $answer->copy();
$answer->save();
$answer->survey_questions_id = $newQuestion->id;
$newAnswers->add($answer);
}
$newQuestion->Survey_Answers = $newAnswers;
$survey->Survey_Questions->add($newQuestion);
}
return $survey->save();
}
You can read about copy() here. It takes an optional parameter $deep:
$deep
whether to duplicates the objects targeted by the relations
So
$copy = $object->copy(true);
should do it.
Sorry if I'm resurrecting this thread...
I found myself in search of a solution recently where I needed to copy a record and retain the references of the original. A deep copy $record->copy(true) copies the references, which was no good for me. This was my solution:
$record = Doctrine_Core::getTable('Foo')->find(1);
$copy = $record->copy();
foreach($record->getTable()->getRelations() as $relation) {
if ($relation instanceof Doctrine_Relation_Association) {
$ids = array();
foreach ($relation->fetchRelatedFor($record) as $r) {
$ids[] = $r->getId();
}
$copy->link($relation->getAlias(), $ids);
}
}
if ($copy->isValid()) {
$copy->save();
}
Hope this helps :)
This is how i done, but some fix is needed.
$table = $entidade->getTable();
$relations = $table->getRelations();
foreach($relations as $relation => $data) {
try {
$entity->loadReference($relation);
} catch(Exception $e) {
die($e->getMessage());
}
}
I am using Symfony1.4.1 and that uses Doctrine 1.2.1 (I think).
I have been trying to make a function that did all the above myself, when I found one that already exists.
Try this in any function and look at the results:
$tmp=$this->toArray(TRUE);
var_dump($tmp);
$this->refreshRelated();
$tmp=$this->toArray();
var_dump($tmp);
$tmp=$this->toArray(TRUE);
var_dump($tmp);
exit();
I am going to try two different things:
A/ put $this->refreshRelated() into the constructor of all my model objects.
B/ write a function that takes an array depicting the object graph that I want populated. Calling the function refereshRelatedGraph($objectGraphArray). With the right structure of the array (having all the appropriate relation names at each level), I could control which relations get populated and which don't. One use for this is to populate only children, not parent relations. The other is for when a ERD/Schema/ObjectGraph has an element that is 'owned' by more than one object (many to many, other special circumstances that I have), I could control which side of the relationships get pre(non lazy) loaded.

Categories