Balancing between filter and getting the name of foreign key in eloquent - filtering

I have a controller that will list all items like this:
$users = User::all();
return view('auth.userslist', compact('users'));
And In my Users Model, function that will display the name of foreign key items:
public function role() {
return $this->belongsTo('App\Models\Roles');
}
Displayed in blade like this:
<td>{{$user->name}}</td>
<td>{{$user->role->role_name}}</td>
Which works fine. Now, I want to add a filter for my user list(Active and Inactive). Based on docs, I need to do it like this:
$users = DB::table('users')
->where('user_delete', '=', 0)
->get();
return view('auth.userslist', ['users' => $users]);
But it will return an error message Undefined property: stdClass::$role. If I remove all the foreign key fields, it will filter just fine.

Use with() or join
$users = User::with('role')->where('user_delete', '=', 0)
->get();

Related

CakePHP 3 - Exclude fields by default in query unless specifically selected

Title pretty much says it all. I have some tables with fields that contain a lot of data. To save some performance I would like to not SELECT these by default.
The emphasis on the new default behaviour, differentiating the question from e.g. Select all except one field in cakephp 3 query
Example:
$cities = $this->Cities->find();
// A $city does not include the field `shape` (which is a huge polygon)
$cities = $this->Cities->find(['id', 'name', 'shape']);
// A $city now does include the `shape` property
I looked at the accessible and hidden properties of an entity, but these don't seem to affect the SELECT statement.
EDIT: The selectAllExcept query seems usefull. I combined this with the beforeFilter event like this:
public function beforeFind($event, $query, $options, $primary)
{
$query->selectAllExcept($this, ['shape']);
}
This works well for empty queries, shape is now excluded. But now I have no control over the other fields that might want to include or not:
$this->Cities->find()->select(['id', 'shape']) will then also select the other fields because the selectAllExcept().
You can simple overwrite find('all') method in your table.
For example in UsersTable:
public function findAll(Query $query, array $options)
{
$query->selectAllExcept($this, ['password']);
return $query;
}
then in your controller:
// select all except password
$users = $this->Users->find();
debug($users);
OR
// we try to select some fields, without success
$users = $this->Users->find()->select(['id', 'username', 'password']);
debug($users);
OR
// we try to select some fields incl. password, with success
$users = $this->Users->find()->select(['id', 'username', 'password'], true); // <-- this overwrite select / selectAllExcept in custom finder
debug($users);

Retrieve 'username' from Articles table

I have two tables, 'users' and 'articles'. Articles have a column 'user_id' which is a foreign key that references the user_id in 'users'.
I have in the Articles model this function which should return the user data:
public function user()
{
return $this->belongsTo('App\User');
}
And this works fine when I pass my articles to my viewer and call it in blade template:
#foreach($articles as $article)
<p>{{$article->user->name}}</p>
#endforeach
But I am trying to use the RESTful approach, so I am rather retrieving my data from JS (VueJS)
axios.get('/api/articles')
that should fire my Controller's function:
public function index()
{
$books = bookpost::all();
return $books;
}
So I was wondering if there's a way to append the user names to the JSON array of articles before returning it because in JS I couldn't get to find a way to get the username.
You can use "eager loading" in your query to help:
$books = bookpost::with('user')->get();
You may even eager load nested relationships:
$books = bookpost::with('user.friends')->get();
Have a look at the documentation for further help.

Yii2: How to do a simple join query?

I am learning how to do simple queries using the Yii2 framework. I use PostgreSQL.
I am trying to join two tables and get the data from both tables with a where condition.
The tables are called Admins and Persons.
The join use field called idadm.
The condition is idadm = 33. This works great but the result has data only from the Admins table and I need data from the other table.
Here is my example:
$query = \app\models\Admins::find()
->select('*')
->leftJoin('persons', 'persons.idadm = admins.idadm')
->where(['admins.idadm' => 33])
->with('persons')
->all();
I am following the Yii2 official guide: http://www.yiiframework.com/doc-2.0/guide-db-active-record.html
Update: Here I show the updated code that doesn't solve de problem:
You need to write all column name in select().
$query = \app\models\Admins::find()
->select('admin.*,persons.*') // make sure same column name not there in both table
->leftJoin('persons', 'persons.idadm = admins.idadm')
->where(['admins.idadm' => 33])
->with('persons')
->all();
And also you need to define person table attributes in Admin model.
Second way is get records as array,so you dont need to define attributes in Admin model.
$query = \app\models\Admins::find()
->select('admin.*,persons.*') // make sure same column name not there in both table
->leftJoin('persons', 'persons.idadm = admins.idadm')
->where(['admins.idadm' => 33])
->with('persons')
->asArray()
->all();
Ensure that active record has required relations, e.g. something like follows:
class Admins extends \yii\db\ActiveRecord {
public function table() {
return "admins";
}
public function getPersons()
{
return $this->hasMany(Person::className(), ['idadm' => 'idadm']);
}
}
class Person extends \yii\db\ActiveRecord {
public function table() {
return "persons";
}
}
Then use joinWith to build query:
$query = Admins::find()
->joinWith('persons')
->limit(1);
$result = $query->createCommand()->getSql();
echo $result;
Here is produced query:
SELECT `admins`.* FROM `admins`
LEFT JOIN `person` ON `admins`.`idadm` = `person`.`idadm` LIMIT 1

Laravel Eloquent - orderBy column find in related model

INFORMATIONS
Database
events | id | to_user_id | from_user_id |
event_details | id | event_id | when |
Event.php
class Event extends Eloquent {
protected $table = 'events';
public function event_detail() {
return $this->hasOne('EventDetail');
}}
EventDetail.php
class EventDetail extends Eloquent {
protected $table = 'event_details';
public function event() {
return $this->belongsTo('Event', 'event_id');
}}
QUESTION
I want to get all events (Event model) and order by 'when' column in related EventDetail model. I wrote a query and it works:
$event = Event::join('event_details as p', 'p.event_id', '=', 'event.id')
->orderBy('p.when', 'asc')
->select('events.*')
->with('event_detail')
->get();
but when i would like to add ->where('to_user_id', '=', 0) clause i get error. How can I fix it?
Moreover I want to know if this query is correct with good practise?
Can you write it better?
Ok, had to recreate your project/tables
All tests are running correctly but I have noticed a few things you may consider changing.
$events = Event::with(['event_detail'=> function($query) {
$query->orderBy('when', 'asc');
}])
->where('to_user_id', 0)
->get();
Also your code may be better if you have an Event
public function event_detail(){
//considering you will have multiples? or just the one event detail?
return $this->hasMany('EventDetail');
}
As you can see, the one event I stored has 2 event details & they are all ordered by ASC.
You can use the other method that doesnt utilize 'with()' but I prefer it. Very nice for json results where you can daisychain a lot of related models.
Hope this helps
I solved the problem with this query. I should add ->where('events.to_user_id', '=', 0) so
$event = Event::join('event_details as p', 'p.event_id', '=', 'event.id')
->orderBy('p.when', 'asc')
->select('events.*')
->where('events.to_user_id', '=', 0)
->with('event_detail')
->get();
However, I would like to know if this query is correct with good practise? Can you write it better?

Load relations only when a field in parent table is true

I have a parent table named Post which has a boolean column named is_anonymous. The Post table has a relation to Users table. I want to load this relation only when is_anonymous set to false. Is there a way I can achieve this?
The below relation gives users for all the posts.
$institute = Institute::where('inst_id', '=', $institute_id)->with(
['posts' => function ($posts) {
$posts->with(['user', 'tags']);
}]
)->orderBy('created_at', 'DESC')->skip($skip)->take(10)->get();
I ended up solving this using lazy loading. I think there is no other way I can do this. Please add answers if you find a better way.
$posts = Institute::where('inst_id', '=', $institute_id)->first()->posts()->with('tags')
->orderBy('created_at', 'DESC')->skip($skip)->take(10)->get();
foreach ($posts as $post) {
if (!$post['is_anonymous']) {
$post->load('user');
}
}
Or,
To be performance friendly, I'm currently solving this using the below query and removing the key user, as iterating over a list of 10 items and removing is always better than making 10 queries (worst case)
$posts = Institute::where('inst_id', '=', $institute_id)->first()->posts()->with(['user', 'tags'])
->orderBy('created_at', 'DESC')->skip($skip)->take(10)->get();
foreach ($posts as $post) {
if ($post['is_anonymous']) {
unset($post['user'])
}
}