Add WHERE condition to all SQL requests in Laravel - mysql

I'm creating an online tool for companies that each have a set of users in Laravel.
When a user is connected, he has a $connected_company_id variable
For every SELECT request (called by ::all(), find(), ...), i would like to add the condition: where company_id = $connected_company_id. I have found this post: laravel set an automatic where clause, but it doesn't work by overriding newQuery().
For every INSERT request, i would like to add the company_id.
Is this possible without changing my code inside all the controllers ?
I thought about extending Eloquent with customEloquent, and then make my models extend customEloquent, but I don't know how to write the code for customEloquent and if it could work.

Well, you could make use of the Eloquent Model Events. I assume you have the connected_company_id stored in the Session company_id
class BaseModel extends Eloquent{
public static function boot(){
parent::boot();
//Column to inject when inserting
static::creating(function ($obj){
$obj->company_id = Session::get('company_id');
});
//Column to inject when updating
static::updating(function ($obj){
$obj->company_id = Session::get('company_id');
});
}
}
You can extend the BaseModel class on all the models that you want the company_id to be inserted or updated. Take a look at Eloquent Model Events for more information.
The above code will automatically insert or update the company_id to the model that you extend the BaseModel to. When you do a Model::all() or Model::get(), you automatically get the company_id on that Model and you can also perform searches as you requested on Point `
Hope this helps.

well, you can just add the company id to the find query.
Model::where("company_id","=",$company_id):
Or you can create a scope:
class theModel extends Eloquent {
static $company_id;
static for_company($company_id){
self::company_id=$company_id;
return __CLASS__;
}
public function scopeCompany($query)
{
return $query->where('company_id', '=', self::company_id);
}
}
//And later
$scope=theModel::for_company($company_id);
$res=$scope::company->where(...);
Disclaimer: I haven't tried this. Just a solution I constructed. Let me know if this works. This will not work under PHP 5.3

Related

How to make query according to my problem in Laravel 8?

Image drive link: Click
My database looks like the photos. Now I need a query result that i describe in two step for better understandind.
step 01: I need these result where syllab_subjects have a specific syllab id. $query_step1 = SyllabSubject::where('syllab_id',$given_id)->get()
step 02: I need only these subject which is not exist in $query_step1. Simply, In $query_step1 check which subject_id is not available when compare with subject table.
For better understanding, if we make query for syllab_id 10, then query result returns "science" and if syllab_id 5 then it returns "English and Science"
Have you set up models with relationships for these tables? It looks like you haven't. What you need is a model like
class Subject extends Model
{
public function syllab() {
return $this->hasMany(Syllab::class):
}
}
and
class Syllab extends Model
{
public function subject(){
return $this->belongsTo(Subject::class);
}
}
Then you can get the details like
$syllab = Syllab::find(10);
$syllab->subjects->pluck('name');

How to get data from Multiple Tables with Laravel Eloquent

I have 2 tables called jobs & job_records. Its relationship as below:
JobRecords Model
public function job()
{
return $this->belongsTo(Job::class);
}
Job Model:
public function jobRecord()
{
return $this->hasOne(JobRecord::class);
}
jobs table has 2 columns that I need to display alongside my job_records table view. It's total_pges & status.
In my JobRecords Controller, I have tried the following method. It throws me an error of Call to undefined relationship.
JobRecordController:
$job_records = JobRecord::whereStatus('In Progress')
->with('jobs', 'jobs.status', 'jobs.total_pges')
->get();
return DataTables::of($job_records)
I am still beginning with Laravel and PHP. I can sense that there is something wrong with the relationship. But I couldn't figure out what it is exactly. Can anyone help me out with this matter?
In your JobRecord model change the relation ship as
public function job()
{
return $this->hasOne('App\Models\Job','foreign_key','local_key');
}
Similarly, in Job model
public function job()
{
return $this->belongsTo('App\Models\JobRecord','foreign_key','local_key');
}
Replace foreign_key and local_key with appropriate values...
I deleted my previous answer. What are you trying to do exactly? You can't use "jobs" in the "with function" without to define "jobs" as function in the model.
If you change it to "job" (instead of "jobs), then it would work, but I don't know if you want this. With your query you saying that a record have many jobs? But your model doesn't define that.

Use a column value in an other table with laravel query builder

I have two table witch named users & Inbox
In the Inbox table I have a column named sender_id that have the user_id of the sender
I want to show this message in the view. I need a query to get the sender_id from the inbox table and use that to select a certain user from the users table
I need to do this with all messages and all users.
Laravel is basicly straith foward when you use eloquent. You can always customise it.
First, almost all the time, I create a model and a migration at the same time using this : php artisan make:model Something --migration
I know you already make some models and/or migrations, but I'll go step by step to help you understand it.
So, in your case, it'll be php artisan make:model User --migration and php artisan make:model Inbox --migration. Doing this, you get two model named User and Inbox and two migration named date_create_users_table.php and date_create_inboxs_table.php. Maybe you already did the default user table with php artisan make:auth. If it's the case, don't remake one.
I'm not sure about how laravel will name the Inbox model migration... Since, I think, Laravel 5.3, the plurialisation changed and don't always just add an "S" at the end.
Then, now you got your models and migrations, let's add some line into your migration files. Since you want to do a one to many relationship. You don't need to touch the user one. Only the Inbox migration. Each Inbox is related to one User and Users can have many Inboxs. Add something like this in your migration:
public function up()
{
Schema::create('inboxs', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
all other columns...
});
}
There, you can change the column's name if you need to have a sender, a recipient, etc... Do this instead :
public function up()
{
Schema::create('inboxs', function (Blueprint $table) {
$table->increments('id');
$table->integer('sender_id');
$table->foreign('sender_id')->references('id')->on('users');
$table->integer('recipient_id');
$table->foreign('recipient_id')->references('id')->on('users');
all other columns...
});
}
What we just did, it's creating the Foreign key that Laravel will use to build the query. There is one last part before the fun one. We need to create the relation in our Model. Begin with the user one:
App/User.php
public function inboxs() {
return $this->hasMany(Inbox::class);
}
And now into the App/Inbox.php model:
public function user() {
return $this->belongsTo(User::class);
}
If you need to have a Sender/Recipient/etc... go this way instead:
public function sender() {
return $this->belongsTo(User::class);
}
public function recipient() {
return $this->belongsTo(User::class);
}
Note that each of your function need to be writen in the same way it's into your migration. sender_id need a relation named sender().
Now, that our relations are done, we can simply call everything using eloquent.
$inboxs = Inbox::with('sender')->get();
This will return an array of all your Inbox into the inboxs table. You can access the sender this way: $inboxs[0]->sender();
You need the id, do this: $sender_id = $inboxs[0]->sender_id;
The sender name : $sender_name = $inboxs[0]->sender->name;
If you want to get one Inbox and you have the id, just do this $inbox = Inbox::with('sender')->find($id);
This way you don't get an array, only one result and can access the sender directly using $sender_name = $inbox->sender->name; instead of having to add [0] or using a foreach loop.
You can get all messages sended by a user using something like this:
$inboxs = Inbox::where('sender_id', $sender_id)->get();
Finally, you can pass your data to the view using:
return view('path.to.view')->with('inbox',$inbox);
Into the view you do this to show the sender's name:
//If view.blade.php
{{$inbox['sender']['name']}} //work a 100%
{{$inbox->sender->name}} //I'm not sure about this one
//If not using blade
<?php echo $inbox['sender']['name']; ?>
There is a lot of thing you can do using Eloquent and you can add as much condition you want. The only thing I suggest you to really do if you want to use Eloquent, be aware about the n+1 problem. There is a link where I explain it. Look for the EDIT section of my answer.
If you need some documentation:
Laravel 5.3 Relationships
Laravel 5.3 Migrations
Laravel 5.3 Eloquent
I think you should update your code like:
$user_messages = DB::table('messages')
->select('messages.id as msgId','messages.message as message','users.id as userId','users.user_name as user_name')
->join('messages','messages.user_id','=','users.id')
->where('messages.user_id',$user_id)
->get();
return view("view.path")
->with('messages',$user_messages);
Hope this work for you!
In Model :
namespace App;
use Illuminate\Database\Eloquent\Model;
class Messages extends Model
{
protected $table = 'table_name';
public function sender()
{
return $this->belongsTo('App\User', 'sender_id', 'id');
}
}
In Controller :
public function functionName($user_id){
$messages = Messages::where('sender_id', $user_id)->get();
return view("view.path")
->with('messages',$messages);
}
In view, you can access seder details like this $message->sender->name for name for id $message->sender->id

Yii2 - replacement for beforeFind to optimize nested views in MySql

Yii1 used to have beforeFind method in which you could modify the query or whatever else you might want to do.
In Yii2 the suggested alternative is to use the modelQuery solution for example
class MyModel extends \yii\db\ActiveRecord
{
public static function find()
{
return new MyModelQuery(get_called_class());
}
/* ... */
}
and
class MyModelQuery extends \yii\db\ActiveQuery
{
public function init( )
{
/** do something here **/
}
}
But how do I pass or reference MyModel within MyModelQuery?
For example:-
class MyModelQuery extends \yii\db\ActiveQuery
{
public function init( )
{
$sql = "SET #variable = {$MyModel->variable1}";
}
}
EDIT
For completeness, I've added a use case to help others in future.
I have nested views with group by's running under MySql and it runs VERY badly.
In my case, I have orders, order-items and order-item-fees tables, each one-to-many to the next and I want to sum the order totals. I have nested view, one at each level to sum to the level above, but at the order-item and order-item-fee levels MySql is grouping the whole table first (I cannot use algorithm=merge as I have a GROUP BY).
I'm implementing the Pushdown method where you define a SQL variable to use in sub-views to narrow down the search as outlined here: http://code.openark.org/blog/mysql/views-better-performance-with-condition-pushdown
and also here
https://www.percona.com/blog/2010/05/19/a-workaround-for-the-performance-problems-of-temptable-views/
In this way, if I can add a 'WHERE order_id=' to the where clause of the two sub-views, I reduce a 3.5 second query down to 0.003 second query.
So using, Salem's suggestion below, I can execute a SQL statement 'SET #order_id=1234' before my query, which is then picked up in the order-item and order-item-fee views using a function. Note: this is connection specific, so no danger of collisions between sessions.
A bit convoluted but fast.
It would be interesting, though, to see a performance comparison between SQL and looping in PHP perhaps....
EDIT 2
In fact, you normally use find() as a static method, so there is no way of using $this->order_id, so I changed this to over-ride the findOne method
public static function findOne( $orderId )
{
if ( isset($orderId) )
{
$sql = "SET #orderId='{$orderId}'";
Yii::$app->db->createCommand($sql)->execute();
}
return parent::findOne( $orderId );
}
I also use this view with other searches, so in the view I need to check whether the orderId is set or not ...
where (
CASE
WHEN ( NOT isnull( get_session_orderId() ) )
THEN `order`.order_id = get_session_cartref()
ELSE `order`.order_id LIKE '%'
END
)
About how to involve an ActiveQuery class check my answer here:
Yii2 : ActiveQuery Example and what is the reason to generate ActiveQuery class separately in Gii?
But if what you are trying to do doesn't require building named scopes then you may simply override the find method by something like this:
public static function find()
{
return parent::find()->where(['variable' => 'some value']);
}

Codeigniter Noob Question--active record and results?

I'm writing a simple app. I need to block user from a page if their credit is < 0.
I have a table "User_profiles" with a "credit" row.
How can I set up a model in conjunction with the controller to send the user to another page if the value of "credit" is 0?
This should be straightforward, but I'm new at the select->where stuff...
It has to be the row of the current user too--I don't know how to traverse arrays very well yet.
Thanks!
Well, the easiest solution would be to just load a different view...
As for the model, it would look like this:
class UserModel extends Model {
public function getUserCredit($id) {
$this->load->database();
//effectively generates: SELECT `credit` FROM `User_profiles` WHERE `id`=$id
$query = this->db->select('credit')->where('id',$id)->get('User_profiles');
//row() executes the query for a single result, returns the credit property
return $query->row()->credit;
}
}
Then in the controller:
class Users extends Controller {
//....
public function credit() {
$this->load->model('userModel','users');
// assuming the session library has been loaded
$user_id = $this->session->userdata('id');
$credit = $this->users->getUserCredit($user_id);
if ($credit == '0') $this->load->view('users/no_credit');
else $this->load->view('users/credit');
}
}
That's untested, but it should at least help you get the idea.
When you request the page /users/credit/1, CI will call the Users::credit(1) action.
It then loads UserModel as $this->users
You call $this->users->getUserCredit(1), which translates to UserModel::getUserCredit(1), to store as $credit
The model loads the database.
You tell the db to select('credit') (select the credit column), where('id',1) (where the id = 1), then get('User_profiles') (get matching rows from the User_profiles table). That returns a query, which you store as $query for readability.
getUserCredit returns the credit property of the single-row result of the query
If $credit == 0, you load the view views/users/no_credit.php
Otherwise, you load the view views/users/credit.php (it's conventional to name the views after the actions they represent and put them in a folder corresponding to the controller)