Using 'chunks' together with 'with' on Laravel query builder - database

dunno if this is possible at all.. I'm trying to query a large set of data with relations like so:
Parent::with([
'child' => function($query) {
$query->('published', '=', true);
$query->with('child.of.child', 'some.other.child');
$query->chunk(400, function($childs) {
// how is it now possible to add the $childs to the parent result??
});
}
]);

$parent = [];
Parent::with(
[
'childs' => function ($query) use (&$parent) {
$query->where('STATUS', '!=', 'DELETED');
$query->with('some.child', 'some.other.child');
$parent['models'] = $query->getParent()
->getModels();
$query->chunk(
400, function ($result) use ($query, &parent) {
$query->match($parent['models'], $result, 'child-relations-name');
});
}
])
->get();
Now $parent['models'] contains the tree with all the nested child relations... Dunno if this is the smartest way to do so, but it works for now.

Related

Hos to get a json nested in laravel

I'm use laravel 7
I want a json like this:
"declaracion": {
"situacionPatrimonial": {
"datosGenerales": {
"nombre": "Pedro",
"primerApellido": "Perez",
"segundoApellido": "García",
"curp": "BADD110313HCMLNS09",
}
}
}
This branch works fine, I have no problem to generate it:
"datosGenerales": {
"nombre": "Pedro",
"primerApellido": "Perez",
"segundoApellido": "García",
"curp": "BADD110313HCMLNS09",
}
My code looks like this
$records = [];
foreach ($declaraciones as $declaracion) {
$record = [];
$record['datosGenerales']=$declaracion->datosGeneralesApi($id,$declaracion->servidor_publico);
$records[] = $record;
}
return $records;
datosGeneralesApi it's a trait
But i don´t know how add above o nest this branches
"declaracion": {
"situacionPatrimonial": {
Please any ideas? Thanks in advance
I may not quite understand your question, but I hope I can help
$records = [];
foreach ($declaraciones as $declaracion) {
// Here we create the nested items:
$record = [
"declaracion" => [
"situacionPatrimonial" => []
]
];
// Now access it
$record["declaracion"]["situacionPatrimonial"]['datosGenerales'] = $declaracion->datosGeneralesApi($id,$declaracion->servidor_publico);
$records[] = $record;
}
return $records;
You could also consider doing this a couple of other ways, without accessing with keys:
$record = [
"declaracion" => [
"situacionPatrimonial" => $declaracion->datosGeneralesApi($id,$declaracion->servidor_publico);
]
];
$records[] = $record;
Or create it in a much more structured way:
// Create the last element:
$situacionPatrimonial = $declaracion->datosGeneralesApi($id,$declaracion->servidor_publico);
// Wrap that in the next element:
$declaration = ["situacionPatrimonial" => $situacionPatrimonial];
// Now create your record, with the wrapped element:
$record = ["declaracion" => $declaration];
$records[] = $record;
I hope this explains what you don't understand about nesting even if it doesn't directly answer your question.
I would recommend using Eloquent API Resources. You can easily nest different resources in each other and structure them in any way you want.

How to use laravel pagination with filter

I have getCanSeeAttribute function in post model, and I try to get posts with pagination using filter()
$posts = Post::where(function ($query1) use ($users) {
$query1->where('posted_type', 'user')->whereIn('posted_id', $users);
})
->orWhere(function ($query2) use ($stores) {
$query2->where('posted_type', 'store')->whereIn('posted_id', $stores);
})
->with('likes', 'postable')
->withCount('comments', 'likes')
->latest()->paginate($paginate)->filter(function($post){
return $post->can_see == true;
});
The problem is when I use filter, it gets data attribute only, but I need all pagination attributes.
first_page_url": "http://localhost:8000/api/timeline?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "http://localhost:8000/api/timeline?page=1",
"next_page_url": null,
"path": "http://localhost:8000/api/timeline",
"per_page": 10,
"prev_page_url": null,
"to": 6,
"total": 6
can_see not column in table it is Accessor
First of all, I hope you know what are you doing. Assuming you need to get results that has can_see field set to true, you should rather use:
$posts = Post::where('can_see', true)
->where(function($q) {
$q->where(function ($query1) use ($users) {
$query1->where('posted_type', 'user')->whereIn('posted_id', $users);
})->orWhere(function ($query2) use ($stores) {
$query2->where('posted_type', 'store')->whereIn('posted_id', $stores);
})
})->with('likes', 'postable')
->withCount('comments', 'likes')
->latest()
->paginate($paginate);
As you see I additionally wrapped (where .. orWhere) in additional where closure to make sure valid query will be generated.
Otherwise you should use:
$posts = Post::where(function($q) {
$q->where(function ($query1) use ($users) {
$query1->where('posted_type', 'user')->whereIn('posted_id', $users);
})->orWhere(function ($query2) use ($stores) {
$query2->where('posted_type', 'store')->whereIn('posted_id', $stores);
})
})->with('likes', 'postable')
->withCount('comments', 'likes')
->latest()
->paginate($paginate);
$posts = $posts->setCollection($posts->getCollection()->filter(function($post){
return $post->can_see == true;
})
);
However it's very unlikely the 2nd way is better one in your case. Assuming you have 1 mln of matching records and then of them has can_see set to true, and the rest have it set to false, it would cause that you will get 1 mln of records from database and then you will filter only 10 of them what would be performance killer for your application.
You can add this following code, define after $post
$post->appends($request->only('posted_type'));

how to show an array using Ajax and Symfony

i am trying to show a consult which have an array with arrays in symfony using Ajax and json, this is my ajax's script :
<script>
var boton=document.getElementById("form_Boton");
function ajax() {
var nombre=$('#form_nombre').val();
$.ajax({
type: 'POST',
url: "{{ path('buscar_porCriterio') }}",
data: ({nombre: nombre}),
dataType:"json",
beforeSend:function () {
alert("enviará a: "+nombre);
},
success:function (resp) {
if(resp!=""){
$('#resultados').html(resp["nombre"]+" "+resp["apellido"]+" "+resp["residencia"]);
}
if(resp==""){
alert("NO SE ENCONTRO NADA");
}
}
})
}
boton.addEventListener("click",ajax);
</script>
And this is my controller:
public function PorCriterioAction(Request $request){
if(!$request->isXmlHttpRequest())
{
throw new Exception("Error, NO ES AJAX");
}
$nombre=$request->request->get('nombre');
$em=$this->getDoctrine()->getManager();
$encontradas=$em->getRepository('FormulariosBundle:persona')->findBynombre($nombre);
if ($encontradas == null) {
$response = new Response("VACIO " . $nombre . " Sorry");
return $response;
}
else{
$persona_encontrada = (array("id" => $encontradas->getId(),
"nombre" => $encontradas->getNombre(),
"apellido" => $encontradas->getApellido(),
"residencia" => $encontradas->getResidencia()
));
$response= new JsonResponse($persona_encontrada);
return $response;}}
what i need is get all data from my DB whose name be $nombre, and show every data in my div 'resultados'. but. when i realize my search, symfony show me this exception:
Exception
my question is: How can i do to pass every data of that consult to my div 'resultados'?
as you see, i want to show such consult in a div whose id is "resultados" but does not work, can you help me please? i am a beginner in symfony and i have to make this University Proyect and finish my study, thanks for your answer
EDIT # 2
this is the change to my controller:
public function PorCriterioAction(Request $request){
if(!$request->isXmlHttpRequest())
{
throw new Exception("Error, NO ES AJAX");
}
$nombre=$request->request->get('nombre');
$em=$this->getDoctrine()->getManager();
$encontradas=$em->getRepository('FormulariosBundle:persona')->findBynombre($nombre);
if ($encontradas == null) {
$response = new Response("VACIO " . $nombre . " Sorry");
return $response;
}
else{
foreach ($encontradas as $Item){
$persona_encontrada = (array("id" => $Item->getId(),
"nombre" => $Item->getNombre(),
"apellido" => $Item->getApellido(),
"residencia" => $Item->getResidencia()
));
array_push($persona_encontrada,$Item);
}
$response= new JsonResponse($persona_encontrada);
return $response;
}
}
is this what you need? responseText
I believe $encontradas is a results set so try this:
foreach( $encontradas as $item){
$persona_encontrada = (array(
"id" => $item->getId(),
"nombre" => $item->getNombre(),
"apellido" => $item->getApellido(),
"residencia" => $item->getResidencia()
));
}
Let us know the result.
EDIT #2
I see the problem. Since it iterates through the array, you want $persona_encontrada to be an array and then use the PHP array_push to add array elements to it. You could do it like so:
$persona_encontrada = array();
foreach( $encontradas as $item){
$element = array(
"id" => $item->getId(),
"nombre" => $item->getNombre(),
"apellido" => $item->getApellido(),
"residencia" => $item->getResidencia()
);
array_push( $persona_encontrada, $element);
}
By the way, although this will work for you, it might not be the best way to do something like this. But it will work.

Multiple matching() and contain(), condition on related records count

With CakePHP 3.x, I have 3 models : StudentProfile, Diploma1 and Diploma2.
StudentProfile hasMany Diploma1
StudentProfile hasMany Diploma2
Diploma1 has an integer "state" field.
I need to get StudentProfiles which :
have one (or more) related Diploma1 where Diploma1.state = 2
OR
have one (or more) Diploma2 (no condition on Diploma2 fields)
I need to retrieve the matching Diploma1 and Diploma2 with my StudentProfiles.
I'm using the Search and Paginator components, so I have to do this with one query.
For now, I'v been able to get the first part by doing :
$query = $this->StudentProfiles
->find('search', $this->StudentProfiles->filterParams($this->request->query))
->contain(['Diploma1' => function ($q) {
return $q->where(['Diploma1.state' => 2]);
}])
->matching('Diploma1', function($q) {
return $q->where(['Diploma1.state' => 2]);
})
->distinct(['StudentProfiles.id'])
;
$this->set('studentProfiles', $this->paginate($query));
Combining matching and contain allows me to add the condition and get related Diploma1 (as I understand it).
Now I need to get also all the StudentProfiles with a related Diploma2, this is where I get stuck. If I add
->contain(['Diploma2'])
...to my query, I only get Diploma2 for StudentProfiles that have a matching Diploma1 (where state=2), but I don't get StudentProfiles with related Diploma2 only (without matching Diploma1), which is perfectly normal.
So I have 2 questions :
how can I get all StudentProfiles that have a related Diploma2 (i.e add a condition using count(...) > 0 maybe ?)
how can I combine this with a matching clause with a condition (state=2) ?
I hope this is clear.
Thanks
A slightly different approach, but maybe it helps
$query = $this->Profile->find();
$query->select([
'Profile.id',
'Profile.name',
'D1.id',
'D1.name',
'D1.status',
'D1.profile_id',
'D2.id',
'D2.name',
'D2.status',
'D2.profile_id',
'd1c' => 'COUNT(D1.id)',
'd2c' => 'COUNT(D2.id)',
]);
$query->contain([
'D1' => function($q) {
$q->where(['D1.status' => 2]);
return $q;
},
'D2'
]);
$query->leftJoinWith('D1', function($q) {
return $q->where(['D1.status' => 2]);
});
$query->leftJoinWith('D2', function($q) {
return $q;
});
$query->having(function($q) {
return $q->or_([
'd1c >' => 0,
'd2c >' => 0,
]);
});
$query->group('Profile.id');
I couldn't really get contain to create a join, so I had to add those leftJoinWith

CakePHP: Rename field name without change the hierarchy

I have this function write in a CakePHP model:
public function getPeopleByName($name){
$this->unbindModel(array('hasMany' => array('OfficePersonTask')));
$options['fields'] = array("Person.id", "CONCAT(Person.first_name, ' ', Person.last_name) AS full_name");
return $this->find('all', $options);
}
This gave me the following json:
{
People:[
{
0:{
full_name:"Groucho Marx"
},
Person:{
id:"1"
}
},
{
0:{
full_name:"Giovanni Ferretti"
},
Person:{
id:"2"
}
}
]
}
I would that *full_name* will be part of Person group (actually is in a group called 0, all alone). How I can do that?
Use a virtual field in the model rather than a MySQL function in your find. There are some ways to query for data as you are trying to, but you have to account for data being returned in an indexed array rather than the normal associative.

Resources