Cakephp3 passing an array to where condition - cakephp

I'm working on this piece of code:
public function validateSelected($array = [1, 2])
{
$this->autoRender = false;
$samples = TableRegistry::get('Samples');
$samples->query()
->update()
->set(['validate' => true])
->where(function ($exp, $q) {
return $exp->in('id', $q);
})
->execute();
}
The code is pretty much self explanatory, I want to update all the rows with id's that would be passed in an array to the function.
I've tested the code by doing this:
->where(function ($exp, $q) {
return $exp->in('id', [1, 2, 3]);
})
And its working fine but i cant pass the passed array parameter to this where condition as it gives a syntax error undeclared variable $array.
Any idea about how can i achieve this thing would be great.

you can use the use language construct to include external variables into the anonymous function
$ids = [1, 2, 3];
->where(function ($exp, $q) use($ids) {
return $exp->in('id', $ids ]);
})
but you can simply do
->where(['id IN' => $ids])
or also
->where(['id' => $ids], ['id' => 'integer[]'])
see the manual

Related

Laravel sort by keys

I make an array with collections with code:
$hours = Voucher::where('created_at','>=', Carbon::now()->startOfMonth())->get()->groupBy(function($item)
{
return $item->created_at->format('H');
});
dd($hours);
so I get data like this:
SO keys are hours (00-23).
How I can arrange it starting by 00, 01, 02, 03 ... ...
https://laravel.com/docs/5.6/collections#method-sortkeys
$collection = collect([
'id' => 22345,
'first' => 'John',
'last' => 'Doe',
]);
$sorted = $collection->sortKeys();
Update for 5.1
Since you're using Laravel 5.1 and there is no sortKeys method, you can sort the collection before you group it which should result in the keys being in the correct order.
$collection->sort(function($a, $b) {
return strcmp($a->created_at->format('H'), $b->created_at->format('H'));
})->groupBy(function($item) {
return $item->created_at->format('H');
});
Try this code.
$hours = Voucher::where('created_at','>=', Carbon::now()->startOfMonth())->get()->sortBy(function($item)
{
return $item->created_at->format('H');
});
$hours = $hours->groupBy(function($item)
{
return $item->created_at->format('H');
});
dd($hours);

AngularJs - json_encode returning nothing in certain cases

I'm using $http.get to get some information from the server. First the controller calls the BackendServices, and in the service i call $http.get:
Controller:
app.controller('courseController', ['$scope', 'BackendServices', function ($scope, BackendServices) {
BackendServices.lookForCourses().then(
function (response) {
console.log(response);
},
function (response) {
}
);
$scope.addCourse = function (courseName) {
console.log(courseName);
};
}]);
Service:
app.service('BackendServices', function ($http) {
var backendServices = {};
backendServices.lookForCourses = function () {
return $http.get('app/backend/lookForCourses');
}
return backendServices;
});
The PHP files works under cakePHP framework.
lookForCourses:
public function lookForCourses () {
$this->autoRender = false;
$cursosFind = $this->Curso->find('all', array('fields' => array('nombreCurso')));
$cursos = array();
foreach($cursosFind as $index => $curso) {
$cursos[$index]['nombre'] = $curso['Curso']['nombreCurso'];
}
echo json_encode($cursos);
}
Doing this i get as a response on the console:
Object{data: "", status: 200, config: Object, statusText: "OK"}
If I do this:
var_dump($cursos);
I get the following:
array (size=3)
0 =>
array (size=1)
'nombre' => string 'Tecnologias de la informacion' (length=29)
1 =>
array (size=1)
'nombre' => string 'Propedeutico' (length=12)
2 =>
array (size=1)
'nombre' => string 'Lectura y redaccion' (length=19)
However, if i do the following:
$test = array(array('nombre' => 'Propedeutico'), array('nombre' => 'Tecnologias'));
echo json_encode($test);
I do get that array as a response...
What am I missing? I know this might be a silly mistake, but I haven't been able to solve it so far...
Thanks a lot!!
I made it work doing a little modification, since the result of the request brings back a string with accents, example: "TecnologĂ­a", i had to utf8_encode each one of the elements like this:
public function lookForCourses () {
$this->autoRender = false;
$cursosFind = $this->Curso->find('all', array('fields' => array('nombreCurso')));
$cursos = array();
foreach($cursosFind as $index => $curso) {
$cursos[$index]['nombre'] = utf8_encode($curso['Curso']['nombreCurso']);
}
echo json_encode($cursos);
}
Adding ut8_encode did the trick.

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

How to use functions with ngOptions?

I have these 2 functions,
function functionCall(orderByRelease_date){
orderByClick = "release_date"
orderBy();
console.log ('release')
}
function functionCall(orderByCreated_at){
orderByClick = "created_at"
orderBy();
console.log ('created')
}
These functions set a variable orderByClick for this function,
var orderBy = function(){
$scope.movies = response.data;
var orderBy = $filter('orderBy');
$scope.orderedMovies = orderBy($scope.movies, orderByClick);
var movies = $scope.orderedMovies
var i,j,temparray,chunk = 8, movieGroups=[];
for (i=0,j=movies.length; i<j; i+=chunk) {
temparray = movies.slice(i,i+chunk);
movieGroups.push(temparray);
}
$scope.movieGroupsSuggestions = movieGroups
}
I had created a options list like this,
%select
%option{:onselect => "functionCall(orderByRelease_date)"} Sort by release date.
%option{:onselect => "functionCall(orderByCreated_at)"} Sort by newest
But it doesn't seem to do anything.
So I stumbled on to ngoptions and it seemed the way to go, but it's not clear to me how I can use functions with it.
I've created a scope with the options,
$scope.orderList = [
'created_at',
'release_date'
]
And a ng-options element,
%select{"ng-options" => "option for option in orderList"}
This displays the values from orderList, but how do I hook this up so that the variable oderByClick in my orderBy function changes?
To answer my own question,
I've created a scope with the values I want to insert in my javascript code,
$scope.listOfOptions = [
'release_date',
'created_at',
];
Then create a function that reacts to the ng-options,
$scope.selectedItemChanged = function(){
orderByClick = $scope.selectedItem;
orderBy();
}
So this sets the value from listOfOptions to the variable orderByClick, and then calls orderBy function.
And then in the oderBy function I have,
$scope.orderedMovies = orderBy($scope.movies, orderByClick);
And this is the haml,
%select{"ng-change" => "selectedItemChanged()", "ng-model" => "selectedItem", "ng-options" => "option for option in listOfOptions"}
My problem was not knowing about the ng-change, that's what creates the interaction between controller and the view.

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

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.

Resources