create a post with pre-defined categories - laravel

I have a table for posts and a table for categories. But its not possible to create new categories they should already exist in the database and is not possible to change them. DO you know how to structure this logic properly on laravel?
Also when a post is created it should have a maximum of 3 categories and a published date. Do you know how to do that validation in laravel, of dates and the maximum of 3 categories when a post is created? I have this validation for now:
$this->validate($request, [
‘post_name’ => 'required|max:255',
‘post_categories’ => 'required',
‘post_date' => 'required',
]);
Relevant code for this context:
// Category Model:
class Category extends Model
{
public function posts(){
return $this->belongsToMany('App\Post’);
}
}
// Post model
class Post extends Model
{
public function categories(){
return $this->belongsToMany('App\Category');
}
}
Migration Post:
class CreatePost extends Migration
{
public function up()
{
Schema::create(‘posts’, function (Blueprint $table) {
$table->increments('id');
$table->string(‘name’);
…
$table->timestamps();
});
}
Migration Category:
<?php
class CreateCategoriesTable extends Migration
{
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
}
// post controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
}
public function create()
{
return view(‘app.createPost’);
}
public function store(Request $request)
{
dd($request->all());
$this->validate($request, [
‘post_name’ => 'required|max:255',
‘post_categories’ => 'required',
‘post_date' => 'required',
]);
}

Use between rule
'post_categories' => 'required|array|between:1,3'
And for the first question, use firstOrCreate
foreach($request->post_categories as $categoryName){
$category= App\Category::firstOrCreate(['name' => $categoryName]);
$post->categories->attach($category->id);
}

Related

Laravel 8 many to many relationshiop update/delete API (pivot table)

Hello I need a help with laravel 8 many to many relationship pivot table, when I updating or deleting data in API.
These are my files info.
Firstly I created two tables:
Companies (migration file)
public function up()
{
Schema::create('companies', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
});
}
Contacts (migration file)
public function up()
{
Schema::create('contacts', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
});
}
After this created pivot table company_contact (migration file)
public function up()
{
Schema::create('company_contact', function (Blueprint $table) {
$table->foreignId('company_id')->constrained();
$table->foreignId('contact_id')->constrained();
});
}
Models looks like this:
Company model
class Company extends Model{
use HasFactory;
protected $fillable = [
'name',
'email'
];
public function contacts()
{
return $this->belongsToMany(Contact::class);
}
}
Contact model
class Company extends Model{
use HasFactory;
protected $fillable = [
'name',
'email'
];
public function contacts()
{
return $this->belongsToMany(Contact::class);
}
}
My routes file
Route::apiResource('companies', CompanyController::class);
My company controller
class CompanyController extends Controller{
public function index()
{
return CompanyResource::collection(Company::all());
}
public function store(CompanyStoreRequest $request)
{
$company = Company::create($request->validated());
$company->contacts()->attach($request->input('contact_id'));
return new CompanyResource($company);
}
public function show(Company $company)
{
//
}
public function update(CompanyStoreRequest $request,Company $company)
{
$contacts = Company::where('id', $company->id)->contacts()->get();
$company->contacts()->sync($request->input(['contact_id']));
$company->update($request->validated());
return new CompanyResource($company);
}
public function destroy(Company $company)
{
}
}
Company store request
public function rules()
{
return [
'name' => ['required'],
'email' => ['required', 'email'],
'contact_id' =>['required']
];
}
company resource
public function toArray($request)
{
//return parent::toArray($request);
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'contact_count' => $this->contacts()->count()
];
}
Maybe somebody can help my to write correct store() and destroy() methods in to company controller. For example when I updating company data also I want to add more contacts and to save these contacts id's in the pivot table.
With destroy method, when I delete certain company, also I want automatically delete these id’s in pivot table (relation company with contacts).
Thanks for any help.
First, you can pass the data of the contacts in an array together with the company's, using an array for several contacts and to record with the relationship use a foreach with the attach method, search on it. About the deletion you can use the softDelete, search on it too, it makes the cascade deletion of the items.

In Laravel many-to-many relationship, is there a way to update data in a pivot table?

I built two models User and Institution.
How do I update the pivot data between them, after adding additional Pivot columns?
<?php
class User extends Authenticatable
{
public function institutions()
{
$pivots = ['id', 'program_choice', 'session'];
return $this->belongsToMany('App\Institution')
->withPivot($pivots);
}
}
class Institution extends Authenticatable
{
public function users()
{
$pivots = ['id', 'program_choice', 'session'];
return $this->belongsToMany('App\User', 'institution_user')
->withPivot($pivots);;
}
}
Here are the migrations
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->integer('user_id')->unsigned();
$table->rememberToken();
$table->timestamps();
});
}
class CreateInstitutionsTable extends Migration
{
public function up()
{
Schema::create('institutions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->unique();
$table->string('city')->nullable();
$table->string('state')->nullable();
$table->string('country')->nullable();
$table->string('address')->nullable();
$table->string('user_id')->nullable();
$table->string('postal_code')->nullable();
$table->timestamps();
});
}
}
This is the what the pivot table looks like
I am able to attach the information to the pivot table
public function storeInstitution(Request $request)
{
$user_id = auth()->user()->id;
$user = User::find($user_id);
$institution_id = $request->input('institution_id');
$user_program_choice = $request->input('program_choice');
$user_session = $request->input('session');
$user_inst = array(
'program_choice' => $user_program_choice,
'session' => $user_session,
'user_id' => $user_id,
'institution_id' => $institution_id
);
$user->institutions()->attach($institution_id, $user_inst);
return 'success';
}
But unable to update the attached pivot E.g I can't change the program_choice, particle physics to something like digital art
Here's my current code
public function updateInstitutions(Request $request, $pivot_id)#TODO id is pivot_id
{
$user_id = auth()->user()->id;
$user = User::find($user_id);
$institution_id = $request->input('institution_id');
$pivot_attributes = array(
'user_id' => $user_id,
'institution_id' => $institution_id,
'session' => $request->input('session'),
'program_choice' => $request->input('program_choice'),
);
$user->institutions()->updateExistingPivots($institution_id, $pivot_attributes, false);
return 'success';
}
How do I update my pivot data, using the pivot id?
Check the documentation regarding this aspect.
Updating A Record On A Pivot Table
If you need to update an existing row in your pivot table, you may use
updateExistingPivot method. This method accepts the pivot record
foreign key and an array of attributes to update:
$user = App\Models\User::find(1);
$user->roles()->updateExistingPivot($roleId, $attributes);

Get category and Sub_subcategories list using query builder

How to get a list of Category and subcategories like this:
1 mobile
apple
samsung
nokia
2:Laptops
Mac
HP
Dell
Sony
3:Tvs
Samsung
using query builder in controller and foreach loop in view
My Controller
$sub_catagories = DB::table('books_categories')
->join('sub_catagories','sub_catagories.catId','=','books_categories.catId')->get();
return view('index',compact('sub_catagories'));
My category table
public function up()
{
Schema::create('books_categories', function (Blueprint $table) {
$table->increments('catId');
$table->string('catName', 50)->nullable(false);
$table->timestamps();
});
}
My sub_catagory table
public function up()
{
Schema::create('sub_catagories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('catId');
$table->timestamps();
});
}
I've written some example of whole cycle. There is convention in laravel to use unique auto increment 'id's, and have foreign keys like RELATION_id. So if you want to change the table and column names anyway, you can do that with following to this example:
Category Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
protected $table = 'categories';
protected $fillable = [
'id',
'name',
];
public function subcategories(){
return $this->hasMany(Subcategory::class, 'category_id', 'id');
}
}
Subcategory Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Subcategory extends Model
{
protected $table = 'subcategories';
protected $fillable = [
'id',
'category_id',
'name',
];
public function category(){
return $this->belongsTo(Category::class, 'category_id');
}
}
categories table Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCategoriesTable extends Migration
{
public function up()
{
Schema::create('categories', function (Blueprint $table) {
// PRIMARY
$table->bigIncrements('id');
// ADDITIONAL
$table->string('name');
// TIME
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('categories');
}
}
subcategories table Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSubcategoriesTable extends Migration
{
public function up()
{
Schema::create('subcategories', function (Blueprint $table) {
// PRIMARY
$table->bigIncrements('id');
// FOREIGN
$table->unsignedBigInteger('category_id')->nullable();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade')->onUpdate('cascade');
// ADDITIONAL
$table->string('name');
// TIME
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('subcategories');
}
}
usage in controller
// 1
public function categories()
{
$categories = Category::all()->get();
return view('categories', [
'categories' => $categories,
]);
}
// 2
public function catsWithSubcats()
{
$cats_with_subcats = Category::with('subcategories')->get();
return view('cats_with_subcats', [
'categories' => $cats_with_subcats,
]);
}
// 3
public function subcatsWithCats()
{
$subcats_with_cats = Subcategory::with('category')->get();
return view('subcats_with_cats', [
'subcategories' => $subcats_with_cats,
]);
}
If you want to show all categories with their subcategories in the blade, you don't need to use 2nd or 3rd method, just use 1st method. Create "categories.blade.php" inside of "resources/views/..." and write there something like this:
#foreach($categories as $category)
#foreach($category->subcategories as $subcategory)
<p>{{ $subcategory->name }}</p>
#endforeach
#endforeach

Eloquent - How to match data between tables of a single ID

Having multiple tables with data that relates to each other, i'm trying to display that data in a view using Laravel.
I must be confused with how Laravel runs its queries and I need help to sort how to do, what in PHP&SQL would be a left join.
My Asset Model:
public function category(){
return $this->hasOne(Category::class);
}
My Category Model:
public function asset()
{
return $this->belongsTo(Asset::class);
}
My Country Model:
public function country()
{
return $this->belongsTo(Asset::class);
}
And my AssetsController:
public function asset($id)
{
$asset = Asset::find($id);
return view('admin.assets.asset')->with('assets', $asset);
}
And the Router:
Route::get('/admin/assets/asset/{id}', [
'uses' => 'AssetsController#asset',
'as' => 'assets.asset'
//Show the Asset
]);
And the View:
<p><strong>Price:</strong>{{$assets->price}} €</p>
<p><strong>Description:</strong>{{$assets->description}}</p>
<p><strong>Country:</strong>{{$assets->country}}</p>
<p><strong>Category:</strong>{{$assets->name}}</p>
So in the 'asset.blade.php' I get the id from a previous index.blade.php that has a list of all the assets. I want to get via the ID, an asset page that displays the category name and the country name, instead of the ID that belongs to the Asset table.
So it should echo something like $assets->country->country_name and $assets->category->name
dd($asset);
EDIT: Additional information about migrations
categories_table migration
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('url');
$table->timestamps();
});
}
assets_table migration:
public function up()
{
Schema::create('assets', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->double('price',15,2);
$table->mediumText('description');
$table->integer('country');
$table->integer('category');
$table->integer('subcategory');
$table->integer('subsubcategory');
$table->integer('broker');
$table->string('featured');
$table->string('slug');
$table->timestamps();
});
}
Got it working.
class Category
{
public function asset()
{
return $this->hasMany(Asset::class);
}
}
class Asset
{
public function category()
{
return $this->belongsTo(Category::class);
}
}
use App\Asset;
use App\Category;
use App\Country;
use App\Subcategory;
use Illuminate\Http\Request;
class AssetController extends Controller
{
public function asset($id)
{
$asset = Asset::find($id);
return view('admin.assets.asset')
->with('asset', $asset)
->with('category', Category::all())
->with('subcategory', Subcategory::all())
->with('country', Country::all());
}
}
The other models have the same relationship towards the Asset model and vice-versa.
The View:
<p><strong>Category:</strong>{{$asset->category->name}}</p>
<p><strong>Sub-Category:</strong>{{$asset->subcategory->name}}</p>
It now shows the name matching the id of the corresponding tables.

Not being relationships in laravel 5 db:seed

I have three model Developer model:
migration:
$table->increments('id');
$table->string('email')->unique();
$table->unsignedInteger('programming_language_id');
$table->unsignedInteger('language_id');
$table->timestamps();
and function
class Developer extends Model
{
public function programming_languages() {
return $this->hasMany('App\ProgrammingLanguage');
}
public function languages() {
return $this->hasMany('App\Language');
}
}
ProgrammingLanguage model:migration:
$table->increments('id');
$table->string('name')->unique();
$table->timestamps();
and function:
protected $table = 'programming_languages';
public function developers() {
return $this->belongsToMany('App\Developer');
}
Language model: migration:
$table->increments('id');
$table->string('code', 30)->unique();
$table->timestamps();
and function:
public function developers() {
return $this->belongsToMany('App\Developer');
}
I want to make db seeder and being relationships between those. How can i do that?
I am trying: creating a factory DeveloperFactory
$factory->define(App\Developer::class, function (Faker $faker) {
return [
'email' => $faker->unique()->safeEmail,
'programming_language_id' => function () {
return factory(App\ProgrammingLanguage::class)->create()->id;
},
'language_id' => function () {
return factory(App\Language::class)->create()->id;
}
];
});
seed OK, But it doesnot make any relationships. just seed the data.How can i do that by db:seed?
Seed your languages and programming languages tables first, then query for records in the developer seeder.
return [
'email' => $faker->unique()->safeEmail,
'programming_language_id' => App\ProgrammingLanguage::inRandomOrder()->first()->getKey(),
'language_id' => App\Language::inRandomOrder()->first()->getKey()
];

Resources