Get related item many to many - php

I have model post and tags. And relationship many-to-many.
Post:
public function getTags()
{
return $this->hasMany(Tag::className(), ['id' => 'tag_id'])
->viaTable('post_tag', ['post_id' => 'id']);
}
Tags:
public function getPosts()
{
return $this->hasMany(Post::className(), ['id' => 'post_id'])
->viaTable('post_tag', ['post_id' => 'id']);
}
And table post-tags:
But when I try tags for post:
$tags = $post->tags;
I get an empty variable;
-------------------------
| Post-tag table: |
-------------------------
| id | post_id | tag_id |
-------------------------
| 8 | 2 | 1 |
-------------------------

Make sure you have the relevant tags saved in the post_tag table against the post you are calling the relation.
Also you have to correct the relation inside the Tags Model, you need to specify the 'tag_id'=>'id' rather than 'post_id'=>'id' when calling viaTable().
public function getPosts()
{
return $this->hasMany(Post::className(), ['id' => 'post_id'])
->viaTable('post_tag',['tag_id'=>'id']);
}

Posts:
public function getTags() {
return $this->hasMany ( Tag::className (), [
'post_id' => 'post_id'
] )
}
Tags:
no need actually;
public function getPosts() {
return $this->hasMany ( Post::className (), [
'post_id' => 'post_id'
] )
}
$tags = $post->tags; will give u an object now!

Related

Laravel - Model::create() works, but is missing attributes

So, I have the following Models:
class Recursive extends Model {
public function __construct() {
parent::__construct();
}
// ...
}
class Place extends Recursive {
protected $table = 'places';
protected $fillable = ['name', 'parent_id'];
// ...
}
The following code is used to create a new Place:
$place = Place::create([
'name' = 'Second',
'parent_id' => 1
]);
This results in the following record in the database:
| Actual | Expected |
---------------------------------------------------------
| id | name | parent_id | id | name | parent_id |
| 1 | 'Top' | NULL | 1 | 'Top' | NULL |
| 2 | NULL | NULL | 2 | 'Second' | 1 |
As you can see, the only value being set is the Auto-incrementing id column. The 2 columns I'm trying to create are in the fillable array, and the model is created, but it's not associated correctly.
Has anyone come across this issue before? I know I can use another method, such as
$place = new Place();
$place->name = 'Second';
$place->parent_id = 1;
$place->save();
But this isn't the only spot I'm using this code, and I'd prefer to not lose functionality like this.
Edit: Enabling the query log shows the following for the create() call:
array (
'query' => 'insert into `places` () values ()',
'bindings' =>
array (
),
'time' => 1.26,
),
Further edit: Enable MySQL log has the same output as above. Following Miken32's suggestion of reverting the extends to Model works as expected:
array (
'query' => 'insert into `places` (`name`, `parent_id`) values (?, ?)',
'bindings' =>
array (
0 => 'Second',
1 => '1'
),
'time' => 1.21,
),
Checking the Illuminate\Database\Eloquent\Model class, the constructor looks like this:
public function __construct(array $attributes = [])
{
$this->bootIfNotBooted();
$this->initializeTraits();
$this->syncOriginal();
$this->fill($attributes);
}
However, you overrode this in your Recursive class:
public function __construct()
{
parent::__construct();
}
The attributes were not being passed to the constructor, so it was not able to successfully build the query. You could remove the constructor since it's not doing anything, or use this instead:
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
}

Having problems getting values from foreach

trying to get id from each person
$person = $request->input('person');
//values for person: Murdock,Wayne
$values = explode(',' , $person);
if(count($values) > 1) {
//count($values) = 2
foreach($values as $val) {
$get_id = Tag::where('name', $val)->get();
foreach($get_id as $get) {
echo "id=".$get->id;
$result= FileTags::with('file')->where('tag_id', $get->id)->get();
}
}
}
when i do echo $get->id just getting id=1, when is supossed to be id=1 and id=2
Murdock -- id:1
Wayne -- id:2
|table filetags|
| id | tag_id | file_id |
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 2 | 4 |
| 4 | 3 | 1 |
$result = FileTags::with('file')->where('tag_id', $id->id)->get();
I should get files with id 2,3 and 4
Model TAG
public function fileTag() {
return $this->hasMany('App\FileTags');
}
Model Archive
protected $table = 'files';
public function fileTag() {
return $this->hasMany('App\FileTags');
}
Model FileTags
public function tag() {
return $this->belongsTo('App\Tag' , 'tag_id');
}
public function file() {
return $this->belongsTo('App\Archive', 'file_id');
}
Thanks for the help.
EDIT:
|table tag|
| id | name |
| 1 | Murdock |
| 2 | Wayne |
Result from echo $obt_id;
[{"id":1,"name":"Murdock","description":"Description","type":"0","status":"1","created_at":"2016-07-20 18:01:14","updated_at":"2016-07-20 18:01:14"}][]
from var_dump($obt_id)
array (size=1)
0 =>
object(App\Tag)[267]
protected 'table' => string 'tags' (length=4)
protected 'fillable' =>
array (size=4)
...
protected 'connection' => null
protected 'primaryKey' => string 'id' (length=2)
protected 'keyType' => string 'int' (length=3)
protected 'perPage' => int 15
public 'incrementing' => boolean true
public 'timestamps' => boolean true
protected 'attributes' =>
array (size=7)
...
...
...
C:\wamp64\www\Petro\app\Http\Controllers\CatalogedController.php:53:
object(Illuminate\Database\Eloquent\Collection)[272]
protected 'items' =>
array (size=0)
You could create a Variable, $result; initialize it as an Empty Arrayand then simply push all the Results of evaluating the code: FileTags::with('file')->where('tag_id', $get->id)->get() into that the $result Array. And, in the end, Check if the $result Array is not empty. If it's not, you may simply implode it using comma (Assuming it is a String) and echo your Results...
<?php
$person = $request->input('person');
//values for person: Murdock,Wayne
$values = explode(',' , $person);
$result = array(); // <== INITIALIZE TO AN EMPTY ARRAY...
if(count($values) > 1) { //<== $values NOT values...
//count(values) = 2
foreach($values as trim($val)) { //<== TRY TRIMMING OFF WHITE SPACES.
$get_id = Tag::where('name', $val)->get();
foreach($get_id as $get) {
echo "id=".$get->id;
// PUSH THE DATA INTO THE ARRAY...
$result[] = FileTags::with('file')->where('tag_id', $get->id)->get();
}
}
}
// CHECK IF $result IS NOT EMPTY
if(!empty($result)){
// CONVERT THE ARRAY TO A STRING (ASSUMING ITS CONTENT ARE NOT OBJECTS OR ARRAYS)
$result = implode(", ", $result);
// ECHO OUR YOUR RESULT...
echo $result;
}

Laravel: Eager loading with local scope

I have a Coupon model in a Many to Many relation with a Product model (with pivot table and so on...). I created some local scope to get only available coupons, and to get only coupons of determined category:
public function scopeAvailable($query)
{
return $query->where('available', '>', 0);
}
public function scopeOfCategory($query, $category)
{
return $query->join('categories', 'categories.id', '=', 'coupons.category_id')
->where('categories.slug', $category);
}
I want to eager load all available coupons of some category with their respective products. So I'm doing:
$coupons = Coupon::with('products')->available()->ofCategory($category)->paginate(20);
If I call $coupons->first(), I can see the information about the coupon. But if I call $coupons->first()->products I get an empty array.
If I comment the ->ofCategory($category) part, it works as expected.
Here is my Models:
class Coupon extends Model
{
public function products()
{
return $this->belongsToMany('App\Product');
}
...
}
class Product extends Model
{
public function coupons()
{
return $this->belongsToMany('App\Coupon');
}
...
}
I'm using Laravel 5.2. What am I doing wrong?
Edit:
It looks like a problem with my Category. If I try to get coupons on "other" category, I got my coupon as expected. If I try to get coupons on "electronics" category, I got a coupon with no products. I'm pretty sure I have coupons with products both on "electronics" and "other" categories.
If I dump Category::where('slug', '=', 'electronics')->first():
...
protected 'attributes' =>
array (size=3)
'id' => int 1
'name' => string 'Electronics' (length=11)
'slug' => string 'electronics' (length=11)
...
If I dump Category::where('slug', '=', 'other')->first():
...
protected 'attributes' =>
array (size=3)
'id' => int 2
'name' => string 'Other' (length=5)
'slug' => string 'other' (length=5)
...
Edit 2:
I created another coupons with "other" category, so I have two coupons with this category. When I print the coupons, it shows the first coupon twice.
Table coupons:
| id | name | available | category_id |
|----|------------|-----------|-------------|
| 1 | Coupon #1 | 1 | 1 |
| 2 | Coupon #2 | 1 | 1 |
| 3 | Coupon #3 | 1 | 1 |
Table products:
| id | name |
|----|-------------|
| 1 | Product #1 |
| 2 | Product #2 |
| 3 | Product #3 |
Table coupon_product:
| id |product_id| coupon_id |
|----|----------|-----------|
| 1 | 1 | 1 |
| 2 | 2 | 1 |
Table categories:
| id | slug |
|----|-------------|
| 1 | category-1 |
| 2 | category-2 |
| 3 | category-3 |
Product.php:
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function coupons()
{
return $this->belongsToMany('App\Coupon');
}
}
Coupon.php:
class Coupon extends Model
{
public function products()
{
return $this->belongsToMany('App\Product');
}
public function scopeAvailable($query)
{
return $query->where('available', '>', 0);
}
public function scopeOfCategory($query, $category)
{
return $query->join('categories', 'categories.id', '=', 'coupons.category_id')
->where('categories.slug', $category);
}
}
And finally when I run:
$coupons = App\Coupon::with('products')->available()->ofCategory('funny')->first();
dd($coupons->products);
I get this:
Which is correct. Can you post more detailed info about your current state of the project?

Yii2: Kartik DepDrop widget without child value show up

I'm new in Yii2. I am using the DepDrop widget provide by Kartik. Now, I can pick data from column1, however, the related data in column2 doesn't show up. I can't even click on it.
Here is partial of the content of mysql table.
ID | name | sub_ID | category
1 | up | 11 | T-shirt
1 | up | 12 | jet
2 | shoe | 21 | nike
2 | shoe | 22 | adidda
Here is my _form.php code
<?= $form->field($model, 'category')->dropDownlist(
ArrayHelper::map(itemcategory::find()->all(), 'ID', 'name'), ['id' => 'cat_id', 'prompt' => 'Select…']
);?>
<?= $form->field($model, 'subcategory')->widget(
DepDrop::classname(), [
'options' => ['id' => 'subcategory', 'placeholder' => 'Select…'],
'pluginOptions' => [
'depends' => ['cat_id'],
'url'=>\yii\helpers\Url::to(['/positemcategory/Subcat'])
]
]
)?>
Here is my model ItemCategory.php code
public function getSubCatList($cat_id)
{
$data = self::find()->where(['ID' => $cat_id])->select(['sub_ID AS id', 'subcategory AS name'])->asArray()->all();
return $data;
}
And here is the controller Itemcategory.php code
public function actionSubcat()
{
$out = [];
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if ($parents != null) {
$cat_id = $parents[0];
// $out = \app\models\ItemCategory::getSubCategoryList($cat_id);
$out = self::getSubCatList($cat_id);
echo Json::encode(['output'=>$out, 'selected'=>'']);
return;
}
}
echo Json::encode(['output'=>'', 'selected'=>'']);
}
I want to let user pick the item by its name, and save only the ID in another table in mysql instead of the full name.
Use ArrayHelper of Yii2.
$out = self::getSubCatList($cat_id);
echo Json::encode(['output'=>ArrayHelper::map($out,'id','name'),'selected'=>'']);
As a result you will get array with id as key and name as value.

Doesn't choose records

author id | name
1 Mike
2 Dive
3 Stiv
book id | title
1 ABC
2 War
book_author id_book | id_author
1 1
1 2
2 3
app/models/Book.php
public function getAuthors()
{
return $this->hasMany(Authors::className(), ['id' => 'id_author'])->viaTable('book_author',['id_book' => 'id']);
}
In view:
foreach (Books::findAll([1, 2]) as $book)
{
echo sprintf('%s | %s',
$book->title,implode(', ',
$book->getAuthors()));
}
Always returned implode(): Invalid arguments passed in $book->getAuthors()));
getAuthors() - doesn't choose author, why?
Need:
ABC | Mike, Dive
War | Stiv
$book->getAuthors() get object arrays. You should get simple array. Try this code:
foreach (Books::findAll([1, 2]) as $book)
{
$authors = ArrayHelper::toArray($book->getAuthors()->all(), [
'app\models\Authors' => [
'name', 'id'
]
]);
echo sprintf('%s | %s',
$book->title,implode(', ',
ArrayHelper::map($authors, 'id', 'name')));
}

Categories