how to fetch products in laravel using regexp - php

I am facing problem. I want to find the products that belongs to current product (category_ids). I am in product detail page. Here is my structure of table:-
Now see currently i open the 2 product in browser and having category_ids(4,2) now i want to fetch all the products having the category_id 4 or 2 in my case i want to fetch the 3rd product but its is not working.. see 3rd product having category_id (1,2,6) so i want to fetch that record ... So if open 3rd product in browser i want o fetch the 2 product.. hope you guys undertstand here is my code:-
$recomendedProducts = Product::with('product_image')
->whereRaw("category_ids REGEXP '".$productDetail['category_ids']. "'")
->where('id','!=',$productDetail['id'])
->inRandomorder()
->take(5)
->get();
This above query shows me empty result. Please help me how to resolve. I am using laravel 5.2

Well, if that is what you want, according to your comment, you can do it like this.
First, you need to create a proper relationship between your productucs and your categories.
On your product model:
public function category()
{
return $this->belongsToMany('App\Category');
}
On your category model:
public function product()
{
return $this->belongsToMany('App\Product');
}
Next, you need to creat a proper pivot table to connect those two models. So create a migration for that.
php artisan make:migration create_category_product_table
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCategoryProductTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('category_product', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('category_id');
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->unsignedInteger('product_id');
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('category_product');
}
}
Now you can make a little function and access it and send it to your views via controller:
public function getRelatedProducts($product){
$related_category_ids = $product->category()->pluck('categories.id');
return $relatedProducts = Product::whereHas('category', function ($q) use($related_category_ids) {
$q->whereIn('category_id', $related_category_ids);
})
->where('id', '<>', $product->id)
->take(4)
->inRandomOrder()
->get();
}

Related

Retrieve data from many to many relationship in Laravel

I know the question has been responded many times, but for some reason I couldn't make it work for my tables, no matter what, and I don't understand why.
I've been trying this for like 4 hours and I couldn't get it done right.
So here are my functions from two models:
ConducatorDoctorat
public function materii()
{
return $this->belongsToMany('App\DomeniuDoctorat', 'profesor_domeniu', 'domeniu_id', 'profesor_id');
}
DomeniuDoctorat
public function materii()
{
return $this->belongsToMany('App\ConducatorDoctorat', 'profesor_domeniu', 'profesor_id', 'domeniu_id');
}
and profesor_domeniu schema:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ProfesorDomeniu extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('profesor_domeniu', function (Blueprint $table) {
$table->unsignedBigInteger('profesor_id');
$table->unsignedBigInteger('domeniu_id');
$table->foreign('profesor_id')
->references('id')->on('conducatori_doctorat')
->onDelete('cascade');
$table->foreign('domeniu_id')
->references('id')->on('domenii_doctorat')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('profesor_domeniu');
}
}
In my controller, I tried so many ways to do it, for example, like this:
public function edit($id)
{
$materii = ConducatorDoctorat::findOrFail($id)->materii()->pluck('domeniu_id');
return view('admin.conducatori_doctorat.edit')->with([
'materii' => $materii
]);
}
but it still doesn't work.
With the given $id, I want to retrieve all the data from profesor_domeniu where profesor_id == $id.
That's all, but I can't get it.
How can this be done and why doesn't my approach work?
//edit for clarity:
conducator_doctorat is where the professors are stored and domenii_doctorat is where their fields are stored.
In profesor_domeniu, I store what each professor teaches, by linking an id from conducatori_doctorat to an id of a field from domenii_doctorat.
//edit2:
materii() means the fields they teach.
//edit3:
My many-to-many relationship with some data added into the pivot table profesor_domeniu.
eager load your relationship on your model :
public function edit($id)
{
$conducatorDoctorat = ConducatorDoctorat::with('materii')->findOrFail($id);
$materii = $conducatorDoctorat->materii;
return view('admin.conducatori_doctorat.edit')->with([
'materii' => $materii
]);
}
you can also request only your materii related to your conducatorDoctorat :
public function edit($id)
{
$materii = DomeniuDoctorat::whereHas('materii', function($query) use ($id){
$query->where('id', $id);
})->get();
return view('admin.conducatori_doctorat.edit')->with([
'materii' => $materii
]);
}

morphToMany real many to many relation

All polymorh examples I found are one to many if I get it correct. (Tag to Post / Video e.g)
In my Case the parent class is multiple and the child class also. Therefore i set up the pivot table
Tables
Person
id
Venture
id
Capital
id
Estate
id
PIVOT TABLE
Revenues
emitter_id //ID of the revenue emitting class (Venture, Capital, Estate)
emitter_type // Class of the Emitter (App\Models\Venture App\Models\Estate)
receiver_id // Id of Receiver (Venture or Person)
receiver_type // type of Receiver (App\Models\Venture or App\Models\Person)
revenue
In the Estate Model i try this
public function revenuePersons()
{
// searched type, own type/id ,tabel own ID to search id
return $this->morphToMany(Person::class, 'emitter' ,'revenues' ,'emitter_id','receiver_id')
->withPivot('revenue');
}
One the Person Model
public function estaterevenues(){
// searched type, own type/id ,tabel own ID to search id
return $this->morphToMany(Estate::class, 'receiver' ,'revenues' ,'receiver_id','emitter_id')
->withPivot('revenue');
}
The Code works but in some cases i get additional relations back. So it seams the searched _type is not correctly considered.
So i started to implement a own database query function that gives me the Revenue Entry back. It works correctly.
Revenue Model
public function getRevenue($ownside, $emitter_id = Null, $emitter_type,$receiver_id=Null, $receiver_type ){
$revenue = DB::table('revenues')
->where('emitter_id', $emitter_id)
.....()->get()}
But I am not able to do something like
$persons->getRevenues
because a Relationship is expected as return value
So if anyone has an idea how to do that correctly I would be very happy. Or some other best practices for this many to many approach.
The second Question is how to get all revenue receiver at once.
Instead of
$estate->revenuepersons
$estate->revenueventures
Have something like
$estate->revenues //that list both, Ventures and Persons
And here a Class Diagram
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
/**
* Get all of the tags for the post.
*/
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
/**
* Get all of the posts that are assigned this tag.
*/
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
/**
* Get all of the videos that are assigned this tag.
*/
public function videos()
{
return $this->morphedByMany(Video::class, 'taggable');
}
}
$post = Post::find(1);
dd($post->tags);
$video = Video::find(1);
dd($video->tags);
$tag = Tag::find(1);
dd($tag->posts);
$tag = Tag::find(1);
dd($tag->videos);
posts table migration:
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
videos table migration:
Schema::create('videos', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
tags table migration:
Schema::create('tags', function (Blueprint $table) {
$table->increments('id');
$table->string("name");
$table->timestamps();
});
taggables table migration:
Schema::create('taggables', function (Blueprint $table) {
$table->integer("tag_id");
$table->integer("taggable_id");
$table->string("taggable_type");
});

BadMethodCallException: Method does not exist

I am trying to create a many to many relationship between this profile and an availability table but within my test i keep getting call to a undefined method on availability in the test.
This is the controller function
/**
* Creates association between availability and podcast profile
*
* #param array $availabilities
*/
private function associateAvailability(array $availabilities)
{
$this->podcastProfile->availability()->sync(
array_map(function ($availability) {
$availabilityModel = Availability::where('availability', '=', $availability)->first();
return $availabilityModel->id;
}, $availabilities)
);
}
This is the method in the podcast profile model
/**
* Defines many-to-many relationship between podcasts and availabilities
*/
public function availability(): BelongsToMany
{
return $this->belongsToMany(
'App\Models\Availability',
'podcast_availability',
'podcast_profile_id',
'availability_id'
);
}
This is the test for the method
/**
* #test
*/
public function it_should_create_availability_relationship()
{
$this->handlePostRequestToController();
$this->assertTrue($this->user->podcastProfile->availability()->exists());
$this->checkAvailability($this->requestData['availability']);
}
this is the check availability method inserted into the test
/**
* Check database
*
* #param $availabilities
*/
private function checkAvailability($availabilities): void
{
foreach ($availabilities as $availability) {
$availabilityModel = Availability::where('availability', '=', $availability)
->first();
$this->assertDatabaseHas('podcast_availability', [
'podcast_profile_id' => $this->user->podcastProfile->id,
'availability_id' => $availabilityModel->id
]);
}
}
this is the error
1) Tests\Feature\PodcastProfileControllerTest::it_should_create_availability_relationship
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::availability does not exist.
If your trying to make a Many to Many relationship base on Laravel Many to Many Relationship.
Here's how you do it. You need to have to 2 models and 3 migrations.
FIRST
Your model should look like this:
Profile Model
protected $guarded = [];
public function availabilities() {
return $this->belongsToMany(Availability::class);
}
Note: I use availabilities because it is in a many to many relationship so its a better naming convention.
Availability Model
protected $guarded = [];
public function profiles() {
return $this->belongsToMany(Profile::class);
}
SECOND
Your migration should be like this:
Profile Migration
Schema::create('profiles', function (Blueprint $table) {
$table->bigIncrements('id');
...
$table->timestamps();
});
Availability Migration
Schema::create('availabilities', function (Blueprint $table) {
$table->bigIncrements('id');
...
$table->timestamps();
});
Availability And Profiles Migration
Schema::create('availability_profile', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('availability_id');
$table->unsignedBigInteger('profile_id');
$table->timestamps();
});
Note: I use the availability_profile naming convention in alphabetical order
INFO
You can generate this migration using artisan command like this php artisan make:migration create_availability_profile_table --create=availability_profile
LAST
In you controller you can assign the profile to availability
Controller
Assuming you have record on your database.
public function generateAvailability() {
$profile = Profile::firstOrFail(1);
$role = Role::firstOrFail(1);
$profile->availabilities()->attach($role->id);
dd(profile->availabilities);
}
Note: I use dd(dump and die) to check the record
You can also see this reference and this

Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::type()

I'm trying to make a api that will return the type of a word (noun, pronoun, verb, etc.) after creating that word in the database. But for some reason I am getting a "Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::type()" error when the type method is clearly defined in my vocabulary model. I am not using a many to many relationship but a one to many (that's why I am using hasMany() and belongsTo). Type has many Vocabulary but Vocabulary has only one Type and many VocabularyContents and VocabularyContent has only one vocabulary it is related to. So clearly no many to many relationship. So clearly my question is not a duplicate of Call to undefined method (laravel 5.2)
. Here are parts of the code for the application.
The first model is the type model it allows me to get the "contents" of a type (model not listed here) and the vocabularies that belongs to a specific type.
model-code-listing 1: VocType.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class VocType extends Model
{
public function contents()
{
return $this->hasMany('App\VocTypeContent');
}
public function vocabularies()
{
return $this->hasMany('App\VocVocabulary');
}
}
this second model allows me to create a word in the vocabulary table access its "contents", type and category. This is where the issue lies.
model-code-listing 2: VocVocabulary.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class VocVocabulary extends Model
{
protected $fillable = ['voc_category_id','type_id', 'name', 'context', 'picture'];
public $timestamps = false;
public function contents()
{
return $this->hasMany('App\VocVocabularyContent');
}
public function type()
{
return $this->belongsTo('App\VocType');
}
public function category()
{
return $this->belongsTo('App\VocCategory');
}
}
The third model allows me to create the content of a vocabulary and access it parent vocabulary.
model-code-listing 3: VocVocabularyContent.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class VocVocabularyContent extends Model
{
protected $fillable = ['voc_vocabulary_id','lang_id', 'content', 'context', 'romanization', 'pronunciation', 'audio'];
public $timestamps = false;
public function vocabulary()
{
return $this->belongsTo('App\VocVocabulary');
}
}
below are the three migrations used for the models listed above.
migration-code-listing 1: create_voc_types_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateVocTypesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('voc_types', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('abbreviation');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('voc_types');
}
}
migration-code-listing 2: create_voc_vocabularies_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateVocVocabulariesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('voc_vocabularies', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('cat_id');
$table->unsignedInteger('type_id');
$table->foreign('cat_id')->references('id')->on('voc_categories')->onDelete('cascade');
$table->foreign('type_id')->references('id')->on('voc_types')->onDelete('cascade');
$table->string('name');
$table->string('context');
$table->string('picture');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('voc_vocabularies');
}
}
migration-code-listing 3: create_voc_vocabulary_contents_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateVocVocabularyContentsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('voc_vocabulary_contents', function (Blueprint $table) {
$table->primary(['voc_id', 'lang_id']);
$table->unsignedInteger('voc_id');
$table->unsignedInteger('lang_id');
$table->foreign('voc_id')->references('id')->on('voc_vocabularies')->onDelete('cascade');
$table->foreign('lang_id')->references('id')->on('languages')->onDelete('cascade');
$table->string('content');
$table->string('context');
$table->string('romanization');
$table->string('pronunciation');
$table->string('audio');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('voc_vocabulary_contents');
}
}
This is the controller where I am calling the type() method of vocabulary. basically I have an html form that sends a post request to this controller's method (postVocabularyAPI) if no id is provided in the request a vocabulary will be created (if the language is english). Then whether or not an id is provided with the request the method will create a vocabulary "content" for the given id (if no id is provided the given id will be the id of the previously created vocabulary). Then the postVocabularyAPI method will return a json response containing the id of the type of the vocabulary.
controller-code-listing 1: Vocabulearn.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Language;
use App\VocTheme;
use App\VocCategory;
use App\VocCategoryContent;
use App\VocVocabulary;
use App\VocVocabularyContent;
use App\VocType;
class Vocabulearn extends Controller
{
//other methods above
public function postVocabularyAPI(Request $request, $language, $theme, $category){
$vocabulary_id = $request->vocabulary_id;
if($vocabulary_id === NULL){
if($language == "english"){
$vocabulary = VocVocabulary::create([
'voc_category_id' => VocCategory::where("slug", $category)->get()->first()->id,
'type_id' => VocType::where("abbreviation", $request->type)->get()->first()->id,
'name' => ucfirst(addslashes($request->translation)),
'context' => $request->context,
'picture' => ''
]);
$vocabulary_id = $vocabulary->id;
} else {
echo '{"success":false, "message":"Create first the English Vocabulary"}';
}
}
$vocabularyContent = VocVocabularyContent::where('lang_id', '=', Language::where("slug", $language)->get()->first()->id)
->where('voc_vocabulary_id', '=', $vocabulary_id)
->first();
if($vocabularyContent !== NULL){
$vocabularies = DB::table('voc_vocabulary_contents')
->where('lang_id', '=', Language::where("slug", $language)->get()->first()->id)
->where('voc_vocabulary_id', '=', $vocabulary_id)
->delete();
}
$vocabularyContent = VocVocabularyContent::create([
'voc_vocabulary_id' => $vocabulary_id,
'lang_id' => Language::where("slug", $language)->get()->first()->id,
'content' => ucfirst(addslashes($translation)),
'context' => addslashes($context),
'romanization' => strtolower(addslashes($romanization)),
'pronunciation' => $pronunciation,
'audio' => $request->audio
]);
echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->type()->id)).'"}';
}
}
doing this gives me a
"Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::type()"
even when I change
echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->type()->id)).'"}';
by
echo '{"success":true, "type":"'.stripslashes(html_entity_decode($vocabularyContent->vocabulary()->get()->first()->type()->id)).'"}';
I get an error stating
"Call to a member function type() on null"
which isn't right because the database was properly populated so I shouldn't be getting a null vocabulary.
There is a quick solution for that.
First add a foreign key in VocVocabulary model type function
public function type()
{
return $this->belongsTo('App\VocType', 'type_id');
}
And then remove paranthesis
echo $vocabularyContent->type->id;
But it is not the standard way to do that. You need to setup your relations in standard ways to help Laravel to understand your relations.
First you need to change the function name as camelCase of the model name. For example as your type model name is VocType so your type function should be changed as
public function type()
To
public function vocType()
{
return $this->belongsTo('App\VocType'); //you don't need a foreign key here
}
In this case you are telling laravel that the function vocType is targeting VocType model. Furthermore you need to change the foreign key in the table of VocVocabulary from type_id to voc_type_id. In this way Laravel clearly understands your relationship otherwise you need to put extra efforts to teach laravel about your relationships.

Im unable to delete the records present int he Pivot Table

I have five tables:
Post
category
Tags
category_post
post_tag
The problem that I am getting is that if I delete the post then it should also delete all the relations of that post in all the tables where it is related. But the system is performing the total opposite it is only deleting the post in the post table.
I found a solution which was
$table->engine='InnoDB'
but my problem still remains the same
This is my Migration for the Category_post Pivot Table
public function up()
{
Schema::create('post_tag', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('post_id')->index()->unsigned();
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->integer('tag_id')->index()->unsigned();
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
$table->timestamps();
});
}
This is what I am doing in the controller
public function destroy(Post $post)
{
$post=Post::find($post->id);
$post->delete();
return redirect('admin/post')->with('message','Deleted Sucessfully');
}
I also Tried this
public function destroy(Post $post)
{
$post=Post::find($post->id);
$post->categories()->delete();
$post->tags()->delete();
$post->delete();
return redirect('admin/post')->with('message','Deleted Sucessfully');
}
But got the same results
When using pivot tables for ManyToMany relationships in Laravel, you should detach the associated tags and categories with the Post model instead of deleting them as per the docs
Besides, your controller code is deleting the tags and categories models and not the association which would corrupt any other posts that are attached to those tags and categories.
Here's an example of the correct way to do it
In your tags migrations
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->bigIncrements('id');
// Any other columns goes here
$table->timestamps();
});
Schema::create('post_tag', function (Blueprint $table) {
$table->bigInteger('post_id');
$table->bigInteger('tag_id');
// ensures a specific post can be associated a specific tag only once
$table->primary(['post_id', 'tag_id']);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('post_tag');
Schema::dropIfExists('tags');
}
Do the same thing for categories migration
Specify the ManyToMany relationship in your Eloquent model like so
class Post extends Model
{
public function tags()
{
return $this->belongsToMany('App\Tag');
}
public function categories()
{
return $this->belongsToMany('App\Category');
}
}
Now when associating tags/categories with a post use the attach method
$post = Post::create([]); // this is only sample code, fill your data as usual
$tag = Tag::create([]);
$category = Category::create([]);
// You can either attach by the model itself or ID
$post->tags()->attach($tag);
$post->categories()->attach($category);
And finally when destroying the Post model, just deassociate the relationship with the tags and categories instead of deleting them using the detach method like so
public function destroy(Post $post)
{
$post->categories()->detach();
$post->tags()->detach();
$post->delete();
return redirect('admin/post')->with('message','Deleted Sucessfully');
}

Categories