I am having offers and services table.
Service(s) is a child of an offer. So far I have established functionality for soft deleting an offer. How would I also soft delete appended services? Here is my code:
Migration Offers
Schema::create('offers', function(Blueprint $table)
{
$table->increments('id')->unsigned();
...
$table->timestamps();
$table->softDeletes();
});
Migration Services
Schema::create('services', function(Blueprint $table)
{
$table->increments('id');
$table->integer('offer_id')->unsigned();
...
$table->timestamps();
$table->softDeletes();
});
Schema::table('services', function($table)
{
$table->foreign('offer_id')
->references('id')
->on('offers');
});
Model Offer
use SoftDeletes;
protected $dates = ['deleted_at'];
public function services() {
return $this->hasMany('App\Service');
}
Model Service
public function offer() {
return $this->belongsTo('App\Offer');
}
Delete method
public function destroy($id)
{
$offer = Offer::find($id);
$offer->delete();
}
Thank you for all the help.
I have put this code in Offer model:
protected static function boot() {
parent::boot();
static::deleting(function($offer) {
$offer->services()->delete();
});
}
And added missing
use SoftDeletes;
protected $dates = ['deleted_at'];
in the Service model.
You should use Eloquent events for this.
Offers::deleted(function($offer) {
$offer->services()->delete();
});
Offers::restored(function($offer) {
$offer->services()->withTrashed()->restore();
});
If you want to get cascading softDeletes in your Eloquent Models I highly recommend using this library iatstuti/laravel-cascade-soft-deletes
Composer
// get it with composer.
$ composer require iatstuti/laravel-cascade-soft-deletes="1.0.*"
Quick example
The one provided in the getting started sample.
<?php
namespace App;
use App\Comment;
use Iatstuti\Database\Support\CascadeSoftDeletes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use SoftDeletes, CascadeSoftDeletes;
protected $cascadeDeletes = ['comments'];
protected $dates = ['deleted_at'];
public function comments()
{
return $this->hasMany(Comment::class);
}
}
You can do like this.
self::deleting(function($offer) {
$offer->services()->delete();
});
self::restoring(function ($offer) {
$offer->services()->restore();
});
You should first delete/restore the children records (services) before deleting/restoring the parent (offer). Failing to do this, will trigger referential integrity MySql error.
Related
Below are all of the models, migrations and controller.
Donation Model
class Donation extends Model
{
protected $guarded =[];
public function users(){
return $this->hasMany(User::class);
}
public function items(){
return $this->belongsTo(DonationItems::class);
}
}
Donation Items Model:
class DonationItems extends Model
{
protected $guarded=[];
public function donation(){
return $this->hasMany(Donaition::class);
}
}
Donation Items Migration:
public function up()
{
Schema::create('donation_items', function (Blueprint $table) {
$table->id();
$table->string('category');
$table->timestamps();
});
}
Donation Migration:
public function up()
{
Schema::create('donations', function (Blueprint $table) {
$table->id();
$table->string('item');
$table->unsignedInteger('user_id');
$table->unsignedInteger('donation_item_id');
$table->timestamps();
});
}
In my controller I want to access the items as follows:
$don = Donation::all();
$don->items;
But I'm unable to achieve this.
Its not working because laravel follows one rule for relationships:
Remember, Eloquent will automatically determine the proper foreign key column on the Comment model. By convention, Eloquent will take the "snake case" name of the owning model and suffix it with _id. So, for this example, Eloquent will assume the foreign key on the Comment model is post_id.
So you can try by supplying local and foreign id
So it would look something like this
Donation Model
class Donation extends Model
{
protected $guarded =[];
public function users(){
return $this->hasMany(User::class);
}
public function items(){
return $this->belongsTo(DonationItems::class, 'donation_item_id', 'id');
}
}
Donation Items Model:
class DonationItems extends Model
{
protected $guarded=[];
public function donation(){
return $this->hasMany(DonationItems::class, 'id', 'donation_item_id');
}
}
I am writing from my head you might need to swap local and foreign ID's
The following code in tinker returns a null value while it should return the project to which the first task is linked.
App\Task::first()->projects;
Already tried renaming the method names, column names in migrations, tried exiting tinker and logging back in
Project Migration
public function up()
{
Schema::create('projects', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('title');
$table->string('description');
$table->timestamps();
});
}
Task Migration
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('project_id');
$table->string('description');
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
Project.php
use App\Task;
class Project extends Model
{
protected $fillable = ['title','description'];
public function tasks(){
return $this->hasMany(Task::class);
}
}
Task.php
use App\Project;
class Task extends Model
{
protected $fillable = [
'completed'
];
public function projects(){
return $this->belongsTo(Project::class);
}
}
If anyone could just review this piece of code and let me know where I have made any conventional\idiotic mistakes (since Im new to route model binding) it would be of great help!
A task belongs to a project, so rename projects to project as it is singular. If you keep projects then provide the column name as second parameter:
public function projects(){
return $this->belongsTo(Project::class, 'project_id');
}
// I suggest this
public function project(){
return $this->belongsTo(Project::class);
}
Your column types are different, for the id of the project you use Big Integer and for the reference you use Integer, so this:
$table->unsignedInteger('project_id');
should be this:
$table->unsignedBigInteger('project_id');
// also good to make the relationship on the Database level:
$table->foreign('project_id')->references('id')->on('projects')->onDelete('cascade');
In my Model class;
Currently I have defined like;
return $this->belongsTo(related: Site::class,
foreignKey:'SiteId', ownerKey:'SiteId');; ----->This works.
But I want to define a combination as Foreign key,
eg: CompanyCode+SiteId
My Current and Target model has both columns(ie:CompanyCode+SiteId). That combination will return a single entry.I want to retrieve that in my current model.
How can I do that?
My Site Model is like;
class Site extends Model
{
protected $table = 'vwSitesPortal';
protected $primaryKey = 'SiteId';
...
My Current model is like;
class Alarm extends Model
{
protected $table = 'vwAlarm';
protected $primaryKey = 'AlarmId';
...
public function Site()
{
return $this->belongsTo(**related**: Site::class,
**foreignKey**:'SiteId', **ownerKey:**'SiteId'
}
Schema::create('favorites', function (Blueprint $table) {
$table->integer('lecture_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamps();
$table->primary(['lecture_id', 'user_id']);
$table->foreign('lecture_id')
->references('id')->on('lectures')
->onDelete('cascade');
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
see this example
I create a project based on the book Getting Started with Laravel 4.
So, I create two files in app/models/ - Cat.php and Breed.php with this content:
Cat.php
<?php
class Cat extends Eloquent {
protected $fillable = array('name','date_of_birth','breed_id');
public function breed() {
return $this->belongsTo('Breed');
}
}
and Breed.php
<?php
class Breed extends Eloquent {
public $timestamps = false;
public function cats()
{
return $this->hasMany('Cat');
}
}
and after, I use command php artisan migration:make create_cats_and_breeds_table
Ok, and should arise file in app/database/migrations. It is.
But, its contents it's not same as in the book...
In book:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddCatsAndBreedsTable extends Migration {
public function up()
{
Schema::create('cats', function($table)
{
$table->increments('id');
$table->string('name');
$table->date('date_of_birth');
$table->integer('breed_id')->nullable();
$table->timestamps();
})
Schema::create('breeds', function($table)
{
$table->increments('id');
$table->string('name');
})
}
public function down()
{
Schema::drop('cats');
Schema::drop('breeds');
}
}
My code:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddCatsAndBreedsTable extends Migration {
public function up()
{
//
}
public function down()
{
//
}
}
What's happen?
https://github.com/laracasts/Laravel-4-Generators
Provides some additional artisan commands which you can used to specific your fields in order to generate the migration files.
php artisan generate:migration create_posts_table --fields="title:string, body:text"
migration:make command does not know anything about your models. It just creates a stub that you need to fill with column definitions for your tables.
I have two models User.php and Blog.php and the content,
Model User.php
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
protected $softDelete = true;
protected $table = 'users';
protected $hidden = array('password');
//-----
public function blogs()
{
return $this->has_many('Blog');
}
//----
Model Blog.php
<?php
class Blog extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function author()
{
return $this->belongs_to('User', 'author_id');
}
}
The Controller, BlogsController.php
<?php
class BlogsController extends BaseController {
public function index()
{
$posts = Blog::with('author')->get();
return Response::json(array(
'status' => 'success',
'message' => 'Posts successfully loaded!',
'posts' => $posts->toArray()),
200
);
}
//-----
The blogs schema,
Schema::create('blogs', function(Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('body');
$table->integer('author_id');
$table->timestamps();
$table->softDeletes();
});
And the users schema,
Schema::create('users', function(Blueprint $table) {
$table->integer('id', true);
$table->string('name');
$table->string('username')->unique();
$table->string('email')->unique();
$table->string('password');
$table->timestamps();
$table->softDeletes();
});
When I call Blog::with('author')->get(); from BlogsController, I am getting this error:-
"type":"BadMethodCallException","message":"Call to undefined method Illuminate\\Database\\Query\\Builder::belongs_to()"
And when I change Blog::with('author')->get(); to Blog::with('author')->all();, the error become:-
"type":"BadMethodCallException","message":"Call to undefined method Illuminate\\Database\\Query\\Builder::all()"
I am using latest update for Laravel 4. What is the wrong with my code?
Your going to love and hate this answer, change belongs_to to belongsTo. Same goes for has_many to hasMany and has_one to hasOne.
Laravel 4 moved to using camel case for methods. Your method not being found on the eloquent model, it falls back to calling it on the query builder, laravel does this to allow short cutting to methods like select() and where().
The second error you were getting, when using all(), is because all() is a static method defined on eloquent and does not work with eager loading. get() is effectively the same thing as all().