Acces to data using relationships Laravel - php

i want to access to data in the function of the controller using relationships on Laravel.
I will explain first my code:
I have 3 tables, projects, client and client_project.
At this moment, client_project don't have any relationship, i just add it manually.
Now i want to use relationships on laravel, but it's a bit confusing (for me at least).
I think it's not too much important the code of projects and clients table, just have id like primary key, and some fields more.
My migration of client_project looks like here:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateClientProjectTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('client_project', function(Blueprint $table)
{
$table->increments('id');
$table->integer('client_id');
$table->integer('project_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('client_project');
}
}
Client_Project model looks like here:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Client_Project extends Model
{
protected $fillable = ['client_id','project_id'];
public $table = 'client_project';
public function clients()
{
return $this->hasMany('App\Models\Project');
}
public function projects()
{
return $this->hasOne('App\Models\Client');
}
}
One client can have more than one project, but one project is only created by one client. I think relationships are declared good.
(At first, i think with relationships i don't need to make the client_project table), but i think that's a wrong idea. I want to make it with this table too.
So, now, the problem it's when i try to call on the function controller, i think i can access to data using por example:
App\Models\Project::find(1), like doc of laravel says.
The function is this:
$client = new Client();
$client->name = $request->input("nameClient");
$client->slug = $request->input("slugClient");
$client->priority = $request->input("priorityClient");
$client->save();
$client_project = new Client_Project();
$client_project->client_id = App\Models\Client::max('id');
$client_project->project_id = App\Models\Projects::max('id');
$client_project->save();
The part of the client, is working. I just take the value of some inputs and i create a new one.
The problem is with $client_project. I want to make it dynamic. I create the client and the project, and my code get the last one(the bigger id), and the last one(the bigger id too) of projects.
How can i access them using relationships?
Maybe need edit migration of client_project and put some key in project_id or client_id?
If need more information, please ask it.
Any help will be appreciated!

Here is your ans. You are going good way you created pivot table for client and project so you can attached as many projects to any client. Here is relationship with model.
Client Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Client extends Model
{
public function projects() {
return $this->belongsToMany(Project::class,'client_project');
}
}
Project model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Projects extends Model
{
public function client() {
return $this->belongsToMany(Client::class,'client_project');
}
}
?>
For Save project id use following way in controller method
$client = new Client();
$client->name = $request->input("nameClient");
$client->slug = $request->input("slugClient");
$client->priority = $request->input("priorityClient");
$client->save();
$project = new Project();
//include fields as per your table
$project->save();
$client->projects()->attach($project->id);
.

Related

Laravel eloquent with multiple inner joins

I currently am doing a raw sql query however this is causing issues with relationships and model boot methods.
Is it possible to do the following SQL query but with laravel eloquent models by relationship? Note all db tables have FK's defined, and relationships either HasOne or HasMany relationships.
$timeBreakDown = DB::select(
"SELECT
Entries.`task_id`,
Entries.`opportunity_id`,
SUM(Entries.`total_duration`) as 'duration',
Class.`class` as 'class',
Subclass.`sub_class` as 'subclass'
from entries Entries
INNER JOIN `tasks` Task
ON task_id = Task.id
INNER JOIN `task_class` Class
ON Task.`class_id` = Class.`id`
INNER JOIN `task_subclasses` Subclass
ON Task.`subclass_id` = Subclass.`id`
WHERE Entries.`opportunity_id` = '".$opportunity->id."'
GROUP BY Entries.`task_id`"
);
Models are
Entries
Tasks
Class
Subclass
How would I have to structure my models relationships to handle the above sql query?
You can write a query in this way:
Please check table names according to your database
DB:: table('table name')->join('tasks','task_id','=','tasks.id')
->join('task_class', 'tasks.subclass_id','=','task_class.id')
->join('task_subclasses','tasks.subclass_id','=', 'task_subclasses.id')
->selectRaw('entries.task_id,
task_subclasses.opportunity_id,
SUM(entries.total_duration) as duration,
task_class.class as class,
task_subclasses.sub_class as subclass')
->where(['entries.opportunity_id'=>$opportunity->id])
->groupBy('enteries.task_id')->get();
Models\Entries.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Entries extends Model
{
public function Tasks(){
return $this->hasOne(Tasks::class);
}
public function Class(){
return $this->hasMany(Classes::class);
}
public function SubClasses(){
return $this->hasOne(SubClasses::class);
}
}
Models\Tasks.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Tasks extends Model
{
public function Entries(){
return $this->belongsTo(Entries::class, "id", "task_id");
}
}
Models\Classes.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Classes extends Model
{
public function Entries(){
return $this->belongsTo(Entries::class, "class_id", "id");
}
}
Models\Subclasses.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class SubClasses extends Model
{
public function Entries(){
return $this->belongsTo(Entries::class, "id", "subclass_id");
}
}
Query:
Entries::with([
"Tasks",
"Classes",
"SubClasses"
])
->where("opportunity_id", $opportunity->id)
->groupBy("task_id")
->get();
Yes, You can do it with Eloquent I'll share an example with you
I can't read your Mess Query sorry for this but I will suggest you to do this
Entries::with(['Tasks','Class','Subclass'])->get();
from this, you will get all objects from this array
Let just say
The class have a relation with another Model but not Entries table then
the Eloquent is something like this
Entries::with(['Tasks','Class.Subclass'])->get();
hope its helpful for you
Might be something like this:
$timeBreakDown = Entries::select('entries.task_id, entries.opportunity_id', DB:raw('SUM(Entries.total_duration) as duration), task_class.class, task_subclasses.sub_class as subclass)
join('tasks', [['tasks.id', 'entries.task_id']])
join('task_class', [['task_class.id', 'entries.class_id']])
join('task_subclasses', [['task_subclasses.id', 'entries.subclass_id']])
->where('entries.opportunity_id', $opportunity->id)
->groupBy('entries.task_id')
->get();
Try this query:
$timeBreakDown = Entries::join('tasks', 'tasks.id', '=', 'entries.task_id')
->join('class', 'class.id', '=', 'entries.class_id')
->join('subclass', 'subclass.id', '=', 'entries.subclass_id')
->select(
'entries.task_id',
'entries.opportunity_id',
\DB::raw('SUM(entries.total_duration) as duration'),
'class.class',
'subclass.sub_class as subclass')
->where('entries.opportunity_id', $opportunity->id)
->groupBy('entries.task_id')
->get();
And try dd($timeBreakDown->toSql()); to match with your Raw SQL query.
From the official documentation.
You can define relationships using the base database relationship type by adding the tasks method to the Entries model.
The tasks method should call the hasOne method and return its result.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Entries extends Model
{
/**
* Get the phone associated with the user.
*/
public function task()
{
return $this->hasOne(Tasks::class);
}
}
In turn, the Tasks model will have an entry method with which we can determine the inverse of the hasOne relationship using the belongsTo method:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Tasks extends Model
{
/**
* Get the user that owns the phone.
*/
public function entry()
{
return $this->belongsTo(Entries::class);
}
}
you need to just setup the relationships like this:
I am assuming that that a Class will have a subClass and a Class will also have Tasks and those Tasks have Entries.
Also do you not have a User model?
Class Model
class Class extends Model
{
protected $with = ['entries', 'subclass', 'task'];
public function entries()
{
return $this->hasManyThrough(\App\Models\Entries::class, \App\Models\Task::class);
}
public function subClass()
{
return $this->hasOne(\App\Models\subClass::class);
}
public function tasks()
{
return $this->hasMany(\App\Models\Task::class);
}
}
Entry Model
class Entry extends Model
{
protected $with = ['task'];
public function task()
{
return $this->belongsTo(Task::class);
}
}
SubClass Model
class SubClass extends Model
{
protected $with = ['class'];
public function class()
{
return $this->belongsTo(\App\Models\Class::class);
}
}
Task Model
class Task extends Model
{
protected $with = ['entries', 'class'];
public function entries()
{
return $this->hasMany(\App\Models\Class::class);
}
public function class()
{
return $this->hasMany(\App\Models\Task::class);
}
}
With all of that set up you should be good to do something like this fro wherever your at in the stack:
$entry = Entry::findOrFail('id');
$entry->task->class->subClass->name;
or
$class = Class::findOrFail($class->id);
$subclass_name = $class->subclass->name;
$entries = $class->tasks->entries;
If you would have posted your models that would have been easier for us. But here is what I got from your raw query above.
$timeBreakDown = Entries::where('opportunity_id',$opportunity->id)->load('Tasks','Class.SubClass')->get();
You should read about Laravel Eloquent and relationships. Just for brief intro the difference between load and with used by Waleed is:
Load is used for lazy loading of relationship data while with is used for eager loading.
Eager loading is all the data gets load as soon as the Eloquent
queries the data while lazy loading loads the data when it is required.

Laravel Eloquent Model using multiple tables combined into one (no separate models)

I'm working on an REST API with Slim and Eloquent.
I used Medoo DB before. It worked well, but i wanted to remove the static Schema and get more flexible.
I have a DB Table with product information. Problem is i have many more Tables with product information. These are not used for them selves, but only in combination with a product.
So it doesn't make sense to create Eloquent Relationship Classes and a Model for every Sub-Table because they will never be used on there own. It is in fact one table extended over multiple tables.
I know the best would be to change the DB structure and to create one big table, but i cannot do that right now.
So in Medoo i defined a schema Structure with all joinable Tables and a query selecting one product worked. Like i said i want to stay flexible and not define the schema inside the code, but at the moment i can only select data from the main table.
So here is only the Product Model:
<?php
namespace Product\Models;
use Interop\Container\ContainerInterface;
#use Medoo\Medoo;
use \Illuminate\Database\Query\Builder;
use \Illuminate\Database\Eloquent\Model as Model;
use \Illuminate\Database\Capsule\Manager;
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
class Object extends Model
{
protected $database;
public function __construct($database)
{
$this->setTable('product_objects');
$this->database = $database;
}
public function getObjectById($id) {
/*
$data = $this->database
->table('product_objects')
->get($columns)
->first()
;
*/
$data = $this->find($id); // this works (with one table)
// Throw error if no result found.
if (empty($data)) {
throw new \Exception('No object found', 400);
}
return $data;
}
}
// this was just a test
class Freetext extends Model
{
protected $database;
public function __construct($database)
{
$this->setTable('product_freetext');
$this->database = $database;
}
}
Is it possible to do something like:
$data = $this->find($id)->product_freetext->product_table3->product_table4 ...
I solved it so far by inserting a scope method that joins the other tables.
Maybe someone has a better way?
public function scopeObjects($query) {
return $query->join('product_freetext', 'product_freetext.oid', '=', 'product_objects.id');
}
and then
$data = $this->objects()->find($id);

Laravel 5.4 Relations are not loading inside Model boot method

I have a model named 'Poll'. Inside Poll model I defined a boot method like follows:
public static function boot()
{
parent::boot();
self::created(function($model){
// dd($model);
$speakers = $model->speakers()->get();
// dd($speakers);
// What I want to do here is: create poll options relation from speakers as follows
// $poll->poll_options()->create([
// 'option' => $speaker->name,
// ]);
}
}
I am adding the speakers relation and it is working perfect.
But inside this boot method, inside self::created if I tried to get the speakers relation, it is always empty (dd($speakers) line). Is it because of the boot method runs just after the model is saved into DB and the relations not at all saved?
I am getting newly created model in the line: dd($model) mentioned in the code.
UPDATE
I tried with events also.
My Poll Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Backpack\CRUD\CrudTrait;
use Cookie;
use App\Events\PollCreated;
class Poll extends Model
{
........
protected $events = [
'created' => PollCreated::class,
];
.......
public function speakers()
{
return $this->belongsToMany('App\Models\Speaker','poll_speaker','poll_id','speaker_id');
}
}
app/Events/PollCreated.php:
namespace App\Events;
use App\Models\Poll;
use Illuminate\Queue\SerializesModels;
class PollCreated
{
use SerializesModels;
public $poll;
/**
* Create a new event instance.
*
* #param Poll $poll
* #return void
*/
public function __construct(Poll $poll)
{
// $this->poll = $poll;
$event = $poll->event()->first();
// dd($event);
// dd($poll->speakers()->get());
// dd($poll->load('speakers'));
}
}
Here also I am not getting speakers, in the line: dd($poll->speakers()->get());
my Speaker model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Backpack\CRUD\CrudTrait;
class Speaker extends Model
{
use CrudTrait;
……..
public function polls()
{
return $this->belongsToMany('App\Models\Poll');
}
……..
}
The problem is with timing as models must always be created before they can be set in a many-to-many relationship. So there is no possible way that in a many-to-many relationship during the created event the relationship is already set as the created events are always raised before the relationships.
Anyone looking for a solution can probably experiment with the chelout/laravel-relationship-events package as this adds relationship events to models.
To be sure, I tested this out with a simple application of users and computers.
User.php
class User extends Model
{
use HasBelongsToManyEvents;
public static function boot() {
parent::boot();
self::created(function($model){
Log::info('user::created');
});
static::belongsToManyAttaching(function ($relation, $parent, $ids) {
$ids = implode(' & ', $ids);
Log::info("Attaching {$relation} {$ids} to user.");
});
static::belongsToManyAttached(function ($relation, $parent, $ids) {
$ids = implode(' & ', $ids);
Log::info("Computers {$ids} have been attached to user.");
});
}
public function computers() {
return $this->belongsToMany(Computer::class, 'user_computers');
}
}
Computer class is the same in reverse. And for the following code:
$user = User::create();
$user->computers()->attach([
Computer::create()->id,
Computer::create()->id
]);
This was the outcome:
user::created
computer::created
computer::created
Attaching computers 69 & 70 to user.
Computers 69 & 70 have been attached to user.

Laravel - Using controller function for two different eloquent models

I am currently developing an application for an indy movie production company. The way I have the workflow right now, the user begins by creating a new movie object by entering the movie title and synopsis. From there the user can then add more details such as price, run-time, full-screen/wide-screen, etc. The movie basic (title, synopsis) are in one database table, and the details are in another. I have set up a one-to-one relationship between the two eloquent models. I have also set up a MovieController that allows me to very easily do CRUD operations on the movie basic model, and when I am displaying the movie object to the user, I can display both the basics and details.
What I was wondering was there some way to use the already existent functions in the movie controller to do CRUD operations on the movie details without having to create new functions in the controller? Also is it possible to reuse the views I've created for each corresponding CRUD operation? In other words can I would like
something.dev/cms/create
In one instance to match to creating a new movie (title, synopsis) and in another instance to match to creating the movie detail (price, run-time, full-screen/widescreen) etc. Is this possible? I have provide the code for the two models below:
Movie_basic.php
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Movie_basic extends Model {
protected $fillable = ['movie_title', 'movie_synopsis'];
protected $guarded = ['id'];
public function details()
{
return $this->hasOne('App\Movie_detail', 'movie_id');
}
public function personnel()
{
return $this->hasMany('App\Movie_personnel', 'movie_id');
}
}
Model_detail.php
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Movie_detail extends Model {
protected $fillable = ['minutes', 'languages', 'viewer_discretion', 'screen_type', 'price'];
protected $guarded = ['id', 'movie_id'];
public function basics()
{
return $this->belongsTo('App\Movie_basic');
}
}
If I understand you, this might be an answer. (Did not test the code.)
Please note that, that code has been written to show you an example. You will probably want to edit it to make it work and act as you wanted. Maybe you want to use a repository or automate the model instance creating (I did not create new instances), and saving processes. You can use interfaces instead of your models etc...
Here is the service to store the logic.
<?php
use Movie_basic; use Movie_detail;
Class MovieService {
protected $movieBasic;
protected $movieDetail;
public function __construct(Movie_basic $movieBasic, Movie_detail $movieDetail) {
$this->movieBasic = $movieBasic;
$this->movieDetail = $movieDetail;
}
public function createMovie(array $attr) {
// TODO: Move your business logic here.
// E.g
$movie = $this->movieBasic->fill($attr);
$movie->save();
return $movie;
}
public function createMovieDetail(array $movieAttr, array $attributes) {
// TODO: Move your detail logic here.
// E.g.
$basic = $this->createMovie($movieAttr);
$detail = $this->movieDetail->fill($attributes);
$detail->basic()->associate($detail);
$detail->save();
return $detail;
}
}
And here, the controller examples:
<?php
use MovieService;
class MovieController {
public function __construct(MovieService $ms) {
$this->ms = $ms;
}
public function store() {
$this->ms->createMovie($attrToSave);
}
}
<?php
use MovieService;
class MovieDetailController {
public function __construct(MovieService $ms) {
$this->ms = $ms;
}
public function store() {
$this->ms->createMovieDetail($attrToSave);
}
}

Like or favorite a post with unique user using Laravel Eloquent

I was creating a like system for my website. in this I wanted one user can only like one time for a post. and a post can be liked by many user. Also many user can like many post.
So if I guess it right, It is a many to many reletionship.
in this context,
I create the following table
... users table:
id
name
....
posts table :
id
post
...post_likes table
id
user id
poost_id
Now I am having the following model for
user :
class User extends SentryUserModel {
public function post_likes()
{
return $this->has_many('Post_like', 'id');
}
}
post :
class Post extends Eloquent {
public function post_likes()
{
return $this->has_many('Post_like', 'id');
}
}
post_like :
class Post_like extends Eloquent {
public function posts()
{
return $this->belongs_to('Post', 'post_id');
}
public function users()
{
return $this->belongs_to('User', 'user_id');
}
}
now when I am going to insert into the database (for post_likes table) I am getting an error called
Illuminate \ Database \ Eloquent \ MassAssignmentException
user_id
Also I want to know is there any way to inset into database like
$user->like()->save($user); ?????
Thank you in advance. Happy coding . \m/
I'll start with a basic issue, firstly you might want to make sure all your tables are lower case (still as a snake case as well), it's not required but it's ultimately how it's expected to be with Laravel so it makes life easier to keep with that. Also a note to the wise, like Class names, database tables are typically in the singular so user instead of users
Secondly yes you can do an insert with $user->post_likes()->save($debate); as your post_likes method on the user class returns has_many.
Thirdly, your design of the Post_like class is a bit off, you could be better off make it like so:
class PostLike extends Eloquent { // note that PostLikes is a more standard naming for a class, they should ideally be camel case names but with all capitals for words
protected $table = 'post_like'; // specifies the table the model uses
public function post() // this should be singular, the naming of a belngs_to method is important as Laravel will do some of the work for you if let it
{
return $this->belongs_to('Post'); // by naming the method 'post' you no longer need to specify the id, Laravel will automatically know from the method name and just adding '_id' to it.
}
public function users()
{
return $this->belongs_to('User');
}
}
Fourthly, your other classes could be better as:
class Post extends Eloquent {
public function post_likes()
{
return $this->has_many('PostLike'); // doesn't require you to specify an id at all
}
}
I can't exactly tell you why you're getting that mass assign error, your post is a bit garbled and doesn't look like you've included the code that actually causes the exception? I have a feeling though is that you're trying to do an insert for multiple database rows at one time but haven't defined a fillable array for PostLike such as with here: http://four.laravel.com/docs/eloquent#mass-assignment
According to Laravel 5:
User Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
public function post_likes()
{
return $this->hasMany('App\PostLike');
}
}
Post Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model {
public function post_likes()
{
return $this->hasMany('App\PostLike');
}
}
PostLike Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class PostLike extends Model {
protected $table = 'post_like';
public function posts()
{
return $this->belongsTo('App\Post');
}
public function users()
{
return $this->belongsTo('App\User');
}
}
and if you want to save the post_like data then:
$inputs['post_id'] = 1;
$inputs['user_id'] = 4;
$post_like = PostLike::create($inputs);
Hope this helps!!

Categories