I was wondering how to calculate revenues using eloquent ORM.
The challenge:
Calculate the planned revenue for each clients. Each clients has many projects.
Question:
How can I make operations such as "budget-cost" outside SQL. Can i put this into my model or somewhere else to access these "special" attributes in my view?
This code is working, but not very elegant, I guess.
$planned_clients = DB::table('clients')
->join('projects', 'clients.id', '=', 'projects.client_id')
->select('projects.*', 'clients.title as client_title',
DB::raw('SUM(projects.planned_budget) as planned_budget'),
DB::raw('SUM(projects.planned_costs) as planned_costs'),
DB::raw('SUM(projects.planned_budget) - SUM(projects.planned_costs) as total_revenue')
)
->where('projects.commitment', '=', Project::PLANNED)
->whereNotIn('projects.status', [Project::CANCELED])
->groupBy('projects.client_id')
->get();
Here are the schemas
class CreateClientsTable extends Migration {
public function up()
{
Schema::create('clients', function(Blueprint $table) {
$table->increments('id');
$table->string('client_id')->unique();
$table->string('title')->unique();
$table->boolean('is_keyclient')->default(0);
$table->text('comment');
$table->timestamps();
});
}
}
class CreateProjectsTable extends Migration {
public function up()
{
Schema::create('projects', function(Blueprint $table) {
$table->increments('id');
$table->string('project_id')->unique();
$table->string('title');
$table->integer('client_id')->unsigned();
$table->enum('commitment', array('save', 'planned'));
$table->enum('status', array('waiting', 'running', 'done', 'canceled', 'cleared'));
$table->string('comment');
$table->integer('planned_budget');
$table->integer('planned_costs');
$table->integer('actual_budget');
$table->integer('actual_costs');
$table->timestamps();
});
Schema::table('projects', function(Blueprint $table) {
$table->foreign('client_id')->references('id')->on('clients');
});
}
Related
I am working on an app where the users can have trainings attached to them with a little description.
So, they can have a training in High School and the description they attach is "Rockford High School". However, I want them to be able to put several times the same type, so they could have 3 High School, or University, etc.
However, when I try to attach two times the same model with the same id, one gets overwritten. I thought that using an intermediate model would solve the issue, but it didn't.
Here are my migrations and any relevant code.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Training extends Model
{
protected $fillable = ['name_french', 'name_english'];
public function candidates() {
return $this->belongsToMany('\App\Candidate')->using('App\CandidateTraining')->withPivot('description');
}
}
<?php
namespace App;
use App\Traits\SanitizeIds;
use App\Salary;
use Illuminate\Database\Eloquent\Model;
class Candidate extends Model
{
use SanitizeIds;
protected $fillable = [
'first_name',
'last_name',
'email',
'phone_number',
'address',
'field_of_work',
'formations',
'work_experiences',
'interests'
];
public function trainings() {
return $this->belongsToMany('\App\Training')->using('App\CandidateTraining')->withPivot('description');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class CandidateTraining extends Pivot
{
//
}
Schema::create('trainings', function (Blueprint $table) {
$table->id();
$table->string('name_french');
$table->string('name_english');
$table->timestamps();
});
Schema::create('candidate_training', function (Blueprint $table) {
$table->id();
$table->string('candidate_id');
$table->string('training_id');
$table->string('description');
$table->timestamps();
});
Schema::create('candidates', function (Blueprint $table) {
$table->id();
$table->string('first_name');
$table->string('last_name');
$table->string('email');
$table->string('phone_number');
$table->string('address');
$table->string('field_of_work')->default('{}');
$table->string('formations')->default('{}');
$table->string('work_experiences')->default('{}');
$table->string('interests')->default('{}');
$table->string('cv')->default('');
$table->string('video_cv')->default('');
$table->timestamps();
});
I don't get how I could make this work and I haven't found any answer during my research. I also want the user to be able to edit them eventually, so delete one model with x id without deleting all the others with the same id but different description.
Call me an idiot but am thinking something like this would make sense for your situation:
Schema::create('trainings', function (Blueprint $table) {
$table->id();
$table->string('name_french');
$table->string('name_english');
// You should checkout 'spatie/laravel-translatable' package, that
// way you can use one column for 'name' and then translate it in realtime
// depending on your application locale.
$table->timestamps();
});
Schema::create('candidate_practice', function (Blueprint $table) {
$table->id();
$table->string('candidate_id');
$table->string('training_id');
$table->timestamps(); // Probably not needed
});
Schema::create('practices', function (Blueprint $table) {
$table->id();
$table->foreignId('candidate_id')
->constrained()
->onDelete('cascade');
$table->string('description');
$table->timestamps();
});
Schema::create('candidates', function (Blueprint $table) {
$table->id();
$table->string('first_name');
$table->string('last_name');
$table->string('email');
$table->string('phone_number');
$table->string('address');
$table->string('field_of_work')->default('{}');
$table->string('formations')->default('{}');
$table->string('work_experiences')->default('{}');
$table->string('interests')->default('{}');
$table->string('cv')->default('');
$table->string('video_cv')->default('');
$table->timestamps();
});
Now you can create multiple practices related to a user by a one-to-many relationship which is a lot easier to edit individually or delete without stepping on other resources and then relate practices to training.
With this, creating a CandidatePractice.php pivot class is no longer necessary.
I have a many to many relation
public function products()
{
return $this->belongsToMany(Product::class); // relation between books and categories
}
public function parts()
{
return $this->belongsToMany(Part::class); // relation between books and categories
}
my migrations :
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->string('link')->default('anohe.com');
$table->string('pname')->default('product');
$table->timestamps();
$table->string('description',3000)->nullable();
$table->string('smalldescription',500)->nullable();
});
}
public function up()
{
Schema::create('parts', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
public function up()
{
Schema::create('part_product', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('product_id');
$table->unsignedInteger('part_id');
$table->timestamps();
$table
->foreign('product_id')
->references('id')
->on('products')
->onDelete('cascade');
$table
->foreign('part_id')
->references('id')
->on('parts')
->onDelete('cascade');
});
}
How can I get products that have a special part_id?
If your relations are correct, that should work:
$specialPartIds = [1];
$products = Product::whereHas('parts', function ($query) use ($specialPartIds) {
$query->whereIn('id', $specialPartIds);
})->get();
dd($products->toArray());
I have 3 tables and I'm trying to make relations between order_products and order_products_status_names. I have transition/pivot table named order_product_statuses. The problem are my PK, becuase I have in table orders 3 Pk, and I don't know how to connect this 3 tables throught relationships.
My migrations are:
Table Order Products:
public function up()
{
Schema::create('order_products', function (Blueprint $table) {
$table->integer('order_id')->unsigned();
$table->integer('product_id')->unsigned();
$table->integer('ordinal')->unsigned();
$table->integer('size');
$table->primary(['order_id', 'product_id', 'ordinal']);
$table->foreign('order_id')->references('id')->on('orders');
$table->foreign('product_id')->references('id')->on('products');
});
}
Table Order Product Statuses - this is my transition/pivot table between order_products and order_product_status_names
public function up()
{
Schema::create('order_product_statuses', function (Blueprint $table) {
$table->integer('order_id')->unsigned();
$table->integer('product_id')->unsigned();
$table->integer('status_id')->unsigned();
$table->integer('ordinal')->unsigned();
$table->dateTime('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$table->foreign('order_id')->references('id')->on('orders');
$table->foreign('status_id')->references('id')->on('order_product_status_names');
$table->primary(['order_id', 'product_id', 'ordinal']);
});
}
And the last one is Order Product Status Names
public function up()
{
Schema::create('order_product_status_names', function (Blueprint $table) {
$table->integer('id')->unsigned();
$table->string('name');
$table->string('code');
$table->dateTime('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$table->primary('id');
});
}
I know that here is relationship blengsToMany in two ways, but I don't know or can I declarate this relation ( from order_products to order_product_status_names and inverse )?
Ok haven't spent a great amount of time on this, but this is kind of what I would do. Also as #Devon mentioned I would probably add ids to each table seeing as Eloquent isn't really designed for composite keys. As mentioned in one of my comments I usually create startup and update scripts, so the syntax might not be exactly right:
public function up() {
Schema::create('order_products', function (Blueprint $table) {
$table->bigIncrements('id')->unsigned();
$table->integer('order_id')->unsigned();
$table->integer('product_id')->unsigned();
$table->integer('order_product_statuses_id')->unsigned();
$table->integer('ordinal')->unsigned();
$table->integer('size');
$table->primary('id');
$table->foreign('order_id')->references('id')->on('orders');
$table->foreign('product_id')->references('id')->on('products');
$table->foreign('order_product_statuses_id')->references('id')->on('order_product_statuses');
});
}
public function up() {
Schema::create('order_product_statuses', function (Blueprint $table) {
$table->bigIncrements('id')->unsigned();
$table->integer('product_id')->unsigned();
$table->integer('status_id')->unsigned();
$table->integer('ordinal')->unsigned();
$table->dateTime('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$table->primary('id');
$table->foreign('status_id')->references('id')->on('order_product_status_names');
});
}
public function up() {
Schema::create('order_product_status_names', function (Blueprint $table) {
$table->bigIncrements('id')->unsigned();
$table->string('name');
$table->string('code');
$table->dateTime('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$table->primary('id');
});
}
I hope that helps you out a bit.
I'm trying to get the users that are on today's shift. I have a many to many relationship between the User and Shift model with a pivot table called user_shifts.
My User model:
/**
* Get the users shifts
*/
public function shift()
{
return $this->belongsToMany('App\Shift', 'user_shifts', 'user_id', 'shift_id');
}
My Shift model
/**
* The shift can have many users
*/
public function users()
{
return $this->belongsToMany('App\User', 'user_shifts', 'shift_id', 'user_id')->withPivot('start_time', 'end_time');;
}
In my controller I thought I could do something like:
$shift = Shift::all()->where('date', date('Y-m-d'));
$users = User::all()->where('shift_id', $shift);
return $users;
But that is returning null. Any help would be appreciated!
If it matters my db schema is:
Schema::create('shifts', function (Blueprint $table) {
$table->increments('id');
$table->date('date');
$table->boolean('weekend');
});
Schema::create('user_shifts', function (Blueprint $table) {
$table->increments('id');
$table->integer('shift_id');
$table->integer('user_id');
$table->time('start_time');
$table->time('end_time');
});
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('fname');
$table->string('lname');
$table->string('email')->unique();
$table->string('password', 60);
$table->rememberToken();
$table->timestamps();
});
I have a many-to-many relationship between my client and tag tables. A client can have many tags, and each tag can be related to multiple clients.
On the client show view, I'm trying to display the client info plus all tags associated to this client.
How do I change the query below to retrieve the client rows with all its related tags?
public function show($id)
{
$client = Client::findOrFail($id);
return view('clients.show')->with(['client' => $client]);
}
Client model
public function clienttag()
{
return $this->belongsToMany('App\Clienttag');
}
Clienttag model
public function client()
{
return $this->belongsToMany('App\Client');
}
Client_clientags table migration
public function up()
{
Schema::create('client_clienttag', function(Blueprint $table)
{
$table->integer('client_id')->unsigned();
$table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
$table->integer('clienttag_id')->unsigned();
$table->foreign('clienttag_id')->references('id')->on('clienttags')->onDelete('cascade');
$table->timestamps();
});
}
Clients table migration
public function up()
{
Schema::create('clients', function(Blueprint $table)
{
$table->increments('id');
$table->string('first_name');
$table->string('last_name');
$table->rememberToken();
$table->timestamps();
});
}
Clienttags table migration
public function up()
{
Schema::create('clienttags', function(Blueprint $table)
{
$table->increments('id');
$table->string('tag');
$table->text('description');
$table->rememberToken();
$table->timestamps();
});
}
You can use "Eager Loading" methods like the following
public function show($id)
{
$client = Client::with('clienttag')->findOrFail($id);
return view('clients.show')->with(['client' => $client]);
}
Check documentation at http://laravel.com/docs/5.1/eloquent-relationships#eager-loading
Then at your view you can print your tags
#foreach ($client->clienttag as $tag)
{!! $tag->tagname!!} (or whatever your field in clienttags table name is)
#endforeach