cakephp parse data through function on get - php

whenever I get a User from the database, I want to say "if this field for this user is empty..."
This is for the current user and every user that is retrieved from the database. Where would I put this if statement? Would it go in the model or is there a generic function that I can use the in the user controller before rendering any user?
Many thanks

You can use afterFind in your model to perform such checks, and this will work for data returned for find operation, like:
//like for User model's some field
public function afterFind($results, $primary = false) {
foreach ($results as $key => $val) {
if (empty($val['User']['some_field'])) {
$results[$key]['User']['some_field'] = "Empty Field";
}
}
return $results;
}
Note:- You can define such functions in your Model Class or AppModel as well.

Related

Filter results in has many relationship

I'm struggling to filter some results.. I have a table called "Process", and another called "Actors". Process has many Actors. Here's the model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Process extends Model
{
public function actors()
{
return $this->hasMany(Actor::class)->orderBy('actor');
}
}
So I have a view where I show all process and their actors. The thing is, I want to make an option to filter, where I would check if the Auth::user()->username is the same as Actor->actor.
I tried something along the lines of:
public function index()
{
$processes = Process::all();
$processes ->actors()->where('actor', 'Test')->get();
return view('process.process', compact('processes '));
}
(In the Where I compare to Test for testing purposes, if I did get it to work I would change it to Auth::user()->username obviously)
This shows the following error:
BadMethodCallException Method
Illuminate\Database\Eloquent\Collection::actors does not exist.
I've tried some variations(running a foreach in the controller for example, but either I did it wrong or thats not the way to do it...) but to no avail. Any help is greatly apreciated!
I assume that you want to grab all processes of the current authenticated user if yes this is what you need.
public function index()
{
$processes = Process::whereHas('actors',function($query){
$query->where('id',Auth::user()->id);
});
return view('process.process', compact('processes '));
}

Eager load extra model attributes

I am using Eloquent with Laravel.
The case: I'm building an API where there is possibility to include relations for a Resource. So for example /api/teams?include=users will add the User model for every Team. For the logic that includes the relationship I'm using Fractal. So I need to have some logic that determines which relationship has to be included, so I can create a optimized query for it.
Problem: When I want to render a collection of a Team with the related User models. I can eager-load the models just fine. The problems comes when I have custom attributes on the User model. These will cause a N+1 query problem because for every eager-loaded team, because the query for the custom attributes will be executed for every model.
Example code:
// The Team model with the custom attribute
class Team extends Model {
protected $appends = ['is_member'];
public function getIsMemberAttribute() {
$loggedUser = Auth::currentUser();
$result = DB::table('team_user')
->where('team_id', $this-id)
->where('user_id', $loggedUser->id)
->get();
return !is_null($result);
}
}
// The controller code
$team = Team::findOrFail($teamId);
// So this will return all the User models that belong to the Team.
// The problem is this will execute the query inside the getIsMemberAttribute() for every User model.
dd($team->users);
Is there a good pattern to solve this issue?
You could iterate through the User models and see if one of them matches the logged in user. It's more efficient than looking it up in the database.
class Team extends Model {
protected $appends = ['is_member'];
public function getIsMemberAttribute() {
$loggedUser = Auth::currentUser();
foreach ($this->users as $user) {
if ($user->id == $loggedUser->id) {
return true;
}
}
return false;
}
}

Getting Model from within Collection

Something very basic but I'm having a hard time solving this.
I have a list of users in the database that show as online users. I am fetching these users by their user_id
Model
public function scopeloggedInUser($query){
return $query->select('user_id')->get();
}
when I var_dump or dd it shows that its a collection of a list of currently logged in users. (Said it was super simple).
I need to fetch those individual users. How do I dilute this to the individual user within the Online Model.
Within the Controller
public function index(Online $online)
{
$activeuser = $online->loggedInUser();
return view('user.user', compact('activeuser'));
}
In your online-model specify a relationship to the real user like this:
public function user()
{
return $this->hasOne('App\User');
}
In your view you can now access each user in your foreach-loop like this:
foreach ($activeusers as $user)
{
echo $user->user->username; // or whatever fields you need
}
But to be honest: in your case I wouldn't set up a new database table and new model if you need this functionality.
Move your logic to your User model and add a boolean field to your user table and change your query-scope to this (again: in your user model)
public function scopeOnline($query){
return $query->where('online', 1);
}
You also shouldn't do a get() within a scope because then you have no more access to the query builder. For example: you want all logged in users that are female.
With get: not pretty.
Without get:
User::online()->where('gender', '=', 'female')->get();

Dynamically populating the dropdown menus in PHP Cake. Access Model from another Model?

I am building a Cake PHP application. Different users have different properties so I use two objects to store a user for example
User hasOne Student / Student belongs to User
User hasOne Lecturer / Lecturer belongs to User
The profile edit page will allow the User to edit all their details for both objects. I've set up the form and used saveAll so save both objects. My problem is dynamically populating the dropdown menus depending on which role the user has.
For example the counties field. Admin does not have an address whereas Student and Lecturer do. I have setup my Country model to find all my counties and put them into opt-groups in the select box (sorting them by country as shown here Dropdown list with dyanmic optgroup)
I can do this fine inside the Students/LecturersController as they allow me to access the Country model as I set $uses variable. I do not want to do this inside the UsersController as not all user roles have an address and an address is never stored inside the User object. I tried putting the code in the model but then I don't know how to access other Models inside a Model. Up to now I've had no problem building the app and I feel that I may have made a bad design decision somewhere or there's something I'm not understanding properly.
Essentially I'm asking how do I implement the setForForm() function below.
public function edit() {
//get user
$user = $this->Auth->user();
//get role
$role = $user['User']['role'];
if ($this->request->is('post') || $this->request->is('put')) {
//get IDs
$userID = $user['User']['id'];
$roleID = $user[$role]['id'];
//set IDs
$this->request->data[$role]['user_id'] = $userID;
$this->request->data[$role]['id'] = $roleID;
$this->request->data['User']['id'] = $userID;
//delete data for role that is not theirs
foreach ($this->request->data as $key => $value) {
if($key !== 'User' && $key !== $role) {
unset($this->request->data[$key]);
}
}
if ($this->User->saveAll($this->request->data)) {
//update logged in user
$this->Auth->login($this->User->$role->findByUserId($userID));
$this->Session->setFlash('Changes saved successfully.');
} else {
$this->Session->setFlash(__('Please try again.'));
}
}
//set role for easy access
$this->set(compact('role'));
//sets required variables for role form
$this->User->$role->setForForm();
//fills in form on first request
if (!$this->request->data) {
$this->request->data = $user;
}
//render form depending on role
$this->render(strtolower('edit_' . $role));
}
//this is the method I would like to implement in the Student/Lecturer model somehow
public function setForForm() {
$counties = $this->Country->getCountiesByCountry();
$homeCounties = $counties;
$termCounties = $counties;
$this->set(compact('homeCounties', 'termCounties'));
}
Not sure if I get your question correct, but I think what you want is the following:
User hasOne Student / Student belongs to User
and
Student hasOne Country / Country belongsTo Student
(and the same for Lectureres)
then from your UsersController you can do:
$this->User->Student->Country->findCountiesByCountry();
hope that helps
--
EDIT:
if you want to want to use $role instead of Student/Lecturer you would have to do it like this:
$this->User->{$role}->Country->findCountiesByCountry();
In the end I decided to just load counties in the user controller regardless of whether the form will need them or not since Admin is the only user that doesn't need them.
Try something like this:
public function setForForm() {
App::import('model', 'Country');
$Country = New Country();
$counties = $Country->getCountiesByCountry();
$homeCounties = $counties;
$termCounties = $counties;
$this->set(compact('homeCounties', 'termCounties'));
}
I don't know is this the best solution or not but it is working at least :)
Edited
Here is another mistake. Its not recommended to set variable from model to view , you can return data that will be set then in edit function normally set it to the view , but anyways if you need to set from model to the view you can load controller class to your model using App::import(); and use set function.

Retrieving inserted IDs from saveAll() in CakePHP

Using saveAll() to save multiple records in CakePHP, I am able to save them successfully in a table. But the problem arises while retrieving the IDs of those saved rows. LastInsertID() returns only a single last ID here. How can I get all the last inserted IDs which I have inserted using saveAll()?
afterSave function is called after each individual save in a saveAll execution, so you could do:
In your AppModel
class AppModel extends Model {
var $inserted_ids = array();
function afterSave($created) {
if($created) {
$this->inserted_ids[] = $this->getInsertID();
}
return true;
}
}
You can place this code into any model and it should work fine. Then to return the IDs after the saveAll in your controller, you would do so like this:
if($this->Post->saveAll($posts)) {
$post_ids=$this->Post->inserted_ids; //contains insert_ids
}
Hope it helps

Categories