Intermediate Table with Laravel - php

I'm working in a Webapp and I have a problems to work with a intermediate table, these are my tables in mysql:
User:
Integer:id
String:name
String:email
String:phone
Exercise:
Integer:id
String:name
String:description
User_Exercise:
Integer:id
Integer:id_user
Integer:id_exercise
Integer:record
So, what I want to do is that when I create an exercise, it be created one row for each user with the exercise-id that I have created it before. Later the user could change his record in this exercise.
I have thought to create a model to handle the user_exercise's table but I don't know if there is some way to do this better or not.
So, There are some way to do this without create a new model?
PD: Sorry for my terrible english

You don't need a seperate model for User_Exercise
You can use $this->belongsToMany from base Model i.e., User
Note :
For insert process you can get the parent id by
$insertUser = User::create($userData);
then
$insertUser->id for taking the last insert id
And then to retrieve with respect to User_Exercise you shall use $this->belongsToMany from your User Model
Example
Have this in your User Model
public function getUser() {
return $this->belongsToMany('App\User', 'excercise_name', 'user_id', 'excercise_id')->select(array('exercise.id', 'excercise.name'));
}
And Get the data you need from any Controller like this
$userData = User::find($userId)->getUser;

Related

get a values using many to many relations on laravel 5 models

i'm really new working with laravel 5.0, so I got this problem when I try to retrieve a result using a model. I have a users table, with a list of users who can be a manager or not, they can have assigned one or more companies, or none, a company table with companies which can have one or many managers, and a pivot table that I called companies_managers. I set up the relations in every model like this:
/***User model***/
public function companies()
{
return $this->belongsToMany('App\Company', 'companies_managers','id', 'manager_id');
}
and the same in Company model
public function managers()
{
return $this->belongsToMany('App\User', 'companies_managers', 'id', 'company_id');
}
I want to get the managers assigned to a company using a company id to get it, but it just gave me an huge object without the values I looking for (the names of the managers assigned to that company). This is the code that I tried:
$managers = Company::find($id)->managers();
I would appreciate any help you can give me
Using ->managers() (with the brackets) doesn't actually return the associated managers, but rather a Builder instance (the "huge object"), which you can then chain with additional parameters before finally retrieving them with ->get() (or another closure, like ->first(), ->paginate(), etc)
Using ->managers (without the brackets), will attempt to access the associated managers, and execute any additional logic to retrieve them.
So, you have 2 options:
$company = Company::with(["managers"])->findOrFail($id);
$managers = $company->managers;
Or
$company = Company::findOrFail($id);
$managers = $company->managers()->get();
Both of those will perform the necessary logic to pull the managers. ->with() and no brackets is slightly more efficient, doing it all in a single query, so bear that in mind.
You just need to split out your code;
// this will find the company based on the id, or if it cannot find
// it will fail so will abort the application
$company = Company::findOrFail($id);
// this uses the active company record and gets the managers based
// on the current company
$managers = $company->managers;
Thank you for your help guys, I solved the issue fixing the relations in the models to this:
return $this->belongsToMany('App\Company', 'companies_managers', 'manager_id', 'company_id');
and this
return $this->belongsToMany('App\User', 'companies_managers', 'company_id', 'manager_id');
The IDs that I had set were not the correct ones for belongsToMany function
And this
$managers = Company::find($id)->managers();
was a problem too, was a dumb mistake of my part. I solved the return of Builder instance using just return instead of dd(), in that way I got the values I looking for. Thanks everyone!

Laravel: Update single field of table using a Resource Controller

I have a Resource Controller (with all the actions: index, create, store, show, edit, update and destroy) and I was wondering what is the best approach to edit a single field column?
Let's say we have a Users table with name, email, password and active (active is a tiny int 0 or 1).
In the users management page, there is a button to activate/deactivate users (makes a request to the server to update the "active" field for the selected user).
Should I create a new method updateStatus in the Controller or is there a way to handle this using the update method?
I don't want, by mistake, allow empty values in the name, email or password when updating the "active" column, so I need to keep the validation rules (in short, all fields are required), but this means when updating the "active" field, I need to pass all the user data in the request.
At this point I'm very confused and all help will be appreciated.
Thanks in advance!
When you send an instance from edit action to the form , all the data will be sent and you can edit one or more columns if you need .
For instance :
public function update(Request $request , $id) {
$data = YourModel::find($id);
$data->someColumn = $request->someColumn;
$data->save();
}
other fields that you didn't send any value for them will be saved as they were before . for this you can set the form like below :
{!! Form::model($yourInstance,['route'=>['someRoute.update','id'=>$yourInstance->id],'method'=>'PATCH',]) !!}
It sounds like you are new to Laravel, and some key concepts can be hard to grasp.
In my opinion the best way to do it would be via a Model class. This is slightly confused by the fact that Laravel has a built in Users model, so I'm going to use a different model as the example of how to update a db field.
php artisan make:model MyData
Will create a new empty model file for the MyData table in app/
The file will look like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class MyData extends Model
{
//
}
Even though there's nothing in there, it now allows you do alter the database table using Eloquent.
In your controller add this to make sure the model is included:
use App\MyData as MyData;
The controller should have a method something like this if updating with user input from a form:
public function updateStatus(MyData $myData, Request $request){
$myData->where('id', $request->id)->update(['active' => $request->active]);
}
You could do the exact same thing like this:
public function updateStatus(Request $request){
$data = MyData::find($request->id);
$data->active = $request->active;
$data->save();
}
Both approaches make sense in different circumstances.
See https://laravel.com/docs/5.5/eloquent#updates

Saving one to one relation in Laravel

A User has one (or zero) Company, and a Company belongs to one and only one User. I try to save a company for a user but it adds a new entry in database every time I re-trigger the save method. It's a one to one relation, so I though save method on User.
So Company has one method user():
public function user() {
return $this->belongsTo(User::class, 'user_id');
}
And User has one method company():
public function company() {
return $this->hasOne(Company::class, 'user_id');
}
I'm trying to save (so create or update) a user's company like this (in a Controller):
$company = new Company();
$company->name = 'Test';
User::findOrFail(1)->company()->save($company);
First time I run this code it creates the entry in database (OK), but second time it adds a new entry for the same user (Not OK). I thought it will only update the database entry.
Is it a glitch (or something I don't understand in one to one relation) in Laravel or am I doing something wrong? (I think and hope it's the second purpose)
Creating and updating need to treat differently. So check the existence of company attribute first.
$user = User::with('company')->findOrFail(1);
if ($user->company === null)
{
$company = new Company(['name' => 'Test']);
$user->company()->save($company);
}
else
{
$user->company->update(['name' => 'Test']);
}
Note that hasOne() does not guarantee that you will have one-to-one relationship, it just telling Eloquent how to create query. It works even you have multiple Company refer to same User, in such case when you call $user->company you will get first Company in the result data set from database.
$user = User::findOrFail(1);
$company = $user->company ?: new Company;
$company->name = 'Test';
$user->company()->save($company);
I'm trying to save (so create or update) a user's company
You can do exactly that with the updateOrCreate method:
User::findOrFail(1)->company()->updateOrCreate([],['name' => 'xyz']);
The first parameter of updateOrCreate is an empty array, because the companies id is determined by the hasOne relationship $user->company().
And by the way, I would recommend not using an auto-increment id field in a hasOne relationship. If you set user_id as primary in your company table, its technically not possible to create duplicate company rows for one user.

If exist Update else Insert Into. MySQL - PHP

I'm asking this question in order to find the best practice to do it.
DB::table('owners')
->where('property_id',$id)
->update(array('person_id'=>$owner));
The problem is that in the table owners might not have a row to update. In that occasion i need to make an INSERT INTO instead of UPDATE.
My problem is that i have to run 2 queries each time, one for checking if the row already exists, and one more to update or insert into. Is it right to run 2 queries each time? Is there a better way to achieve that? I need to keep the queering processes fast for the user.
UPDATE: The table owners is a middle table of a many to many relationship. Unfortunately i cannot use ON DUPLICATE KEY.
well you could try to use firstOrCreate method of Laravel to check if user exists. After that retrieve the user object and pass it to an update function else if the user is not found firstOrCreate method will take care of you as it will create a new user with the data you will provide and will auto increment last user + 1 id.
There is also the option to use firstOrNew which will check if an instance exists based on the array values you passed and if no match is found it will auto create a new instance of the model you are handling for further manipulation.
Here is example with firstOrNew
Example Controller file.
public function getFirstUserOrNew($email)
{
$user = User::firstOrNew(['email' => $email]);
if($user)
{
$this->UpdateUser($user);
}
else
{
$this->CreateUser($user);
}
}
public function UpdateUser(User $user)
{
//Do update stuff
}
public function CreateUser(User $user)
{
//Do create stuff
}
P.S - I'm from Greece, if you want to discuss anything in native language send me a PM :)
EDIT:
Thanks to #Pyton contribution It seems you can also use an updateOrCreate method as it is explained here.
If you want to Update or Insert row You can use updateOrCreate
$owner = Owner::updateOrCreate(['property_id' => $id], ['person_id'=>$owner]);

Best way to filter access to controller actions according to a specific client id

Using CakePHP 2.2, I am building an application in which each client has it's own "realm" of data and none of the other data is visible to them. For example, a client has his set of users, courses, contractors and jobs. Groups are shared among clients, but they cannot perform actions on groups. All clients can do with groups is assign them to users. So, an administrator (using ACL) can only manage data from the same client id.
All my objects (except groups, of course) have the client_id key.
Now, I know one way to get this done and actually having it working well, but it seems a bit dirty and I'm wondering if there is a better way. Being early in the project and new to CakePHP, I'm eager to get it right.
This is how I'm doing it now :
1- A user logs in. His client_id is written to session according to the data from the user's table.
$user = $this->User->read(null, $this->Auth->user('id'));
$this->Session->write('User.client_id', $user['User']['client_id']);
2- In AppController, I have a protected function that compares that session id to a given parameter.
protected function clientCheck($client_id) {
if ($this->Session->read('User.client_id') == $client_id) {
return true;
} else {
$this->Session->setFlash(__('Invalid object or view.'));
$this->redirect(array('controller' => 'user', 'action' => 'home'));
}
}
3- Im my different index actions (each index, each relevant controller), I check the client_id using a paginate condition.
public function index() {
$this->User->recursive = 0;
$this->paginate = array(
'conditions' => array('User.client_id' => $this->Session->read('User.client_id'))
);
$this->set('users', $this->paginate());
}
4- In other actions, I check the client_id before checking the HTTP request type this way.
$user = $this->User->read(null, $id);
$this->clientCheck($user['User']['client_id']);
$this->set('user', $user);
The concept is good - it's not 'dirty', and it's pretty much exactly the same as how I've handled situations like that.
You've just got a couple of lines of redundant code. First:
$this->Auth->user('id')
That method can actually get any field for the logged in user, so you can do:
$this->Auth->user('client_id')
So your two lines:
$user = $this->User->read(null, $this->Auth->user('id'));
$this->Session->write('User.client_id', $user['User']['client_id']);
Aren't needed. You don't need to re-read the User, or write anything to the session - just grab the client_id directly from Auth any time you need it.
In fact, if you read http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user it even says you can get it from outside the context of a controller, using the static method like:
AuthComponent::user('client_id')
Though it doesn't seem you'll be needing that.
You could also apply the client_id condition to all finds for a Model by placing something in the beforeFind function in the Model.
For example, in your User model, you could do something like this:
function beforeFind( $queryData ) {
// Automatically filter all finds by client_id of logged in user
$queryData['conditions'][$this->alias . '.client_id'] = AuthComponent::user('client_id');
return $queryData;
}
Not sure if AuthComponent::user('client_id') works in the Model, but you get the idea. This will automatically apply this condition to every find in the model.
You could also use the beforeSave in the model to automatically set that client_id for you in new records.
My answer may be database engine specific as I use PostgreSQL. In my project I used different schema for every client in mysql terms that would be separate database for every client.
In public schema (common database) I store all data that needs to be shared between all clients (objects that do not have client_id in your case), for example, variable constants, profile settings and so on.
In company specific models I define
public $useDbConfig = 'company_data';
In Controller/AppController.php beforeFilter() method I have this code to set schema according to the logged in user.
if ($this->Session->check('User.Company.id')) {
App::uses('ConnectionManager', 'Model');
$dataSource = ConnectionManager::getDataSource('company_data');
$dataSource->config['schema'] =
'company_'.$this->Session->read('User.Company.id');
}
As you see I update dataSource on the fly according to used company. This does exclude any involvement of company_id in any query as only company relevant data is stored in that schema (database). Also this adds ability to scale the project.
Downside of this approach is that it creates pain in the ass to synchronize all database structures on structure change, but it can be done using exporting data, dropping all databases, recreating them with new layout and importing data back again. Just need to be sure to export data with full inserts including column names.

Categories