Yii2 viaTable many-to-many. Tables has no relation. Eagre loading - php

There is 2 tables many-to-manty and another Intermediary able
$this->createTable('tweet',[
'id' => Schema::TYPE_PK,
'text' => Schema::TYPE_STRING.' NOT NULL',
'date_written' => Schema::TYPE_STRING.' NOT NULL',
'date_imported' => Schema::TYPE_STRING.' NOT NULL',
],"ENGINE=InnoDB DEFAULT CHARSET=utf8");
$this->createTable('hashtag',[
'text' => $this->string(),
'PRIMARY KEY(text)'
],"ENGINE=InnoDB DEFAULT CHARSET=utf8");
$this->createTable('tweet_hashtag', [
'tweet_id' => $this->integer(),
'hashtag_text' => $this->string(),
'PRIMARY KEY(tweet_id, hashtag_text)'
],"ENGINE=InnoDB DEFAULT CHARSET=utf8");
$this->createIndex('idx-tweet_hashtag-tweet_id', 'tweet_hashtag', 'tweet_id');
$this->createIndex('idx-tweet_hashtag-hashtag_text', 'tweet_hashtag', 'hashtag_text');
$this->addForeignKey('fk-tweet_hashtag-tweet_id', 'tweet_hashtag', 'tweet_id', 'tweet', 'id', 'CASCADE');
$this->addForeignKey('fk-tweet_hashtag-hashtag_text', 'tweet_hashtag', 'hashtag_text', 'hashtag', 'text', 'CASCADE');
Table Tweet
public function getTweetHashtags()
{
return $this->hasMany(TweetHashtag::className(), ['tweet_id' => 'id']);
}
public function getHashtagTexts()
{
return $this->hasMany(Hashtag::className(), ['text' => 'hashtag_text'])->viaTable('tweet_hashtag', ['tweet_id' => 'id']);
}
Table tweet_hashtag
public function getHashtagText()
{
return $this->hasOne(Hashtag::className(), ['text' => 'hashtag_text']);
}
public function getTweet()
{
return $this->hasOne(Tweet::className(), ['id' => 'tweet_id']);
}
Table hashtag
public function getTweetHashtags()
{
return $this->hasMany(TweetHashtag::className(), ['hashtag_text' => 'text']);
}
public function getTweets()
{
return $this->hasMany(Tweet::className(), ['id' => 'tweet_id'])->viaTable('tweet_hashtag', ['hashtag_text' => 'text']);
}
When i try
Tweet::find()->with('hashtag')->where(['id' => $tweetID])->all()
there is Exception
Exception 'yii\base\InvalidParamException' with message 'app\models\Tweet has no relation named "hashtag".'
How I can correctly made eagre loading. To get 'text' from hashtag table, by id in Tweet table.

You should use the name or relation
Tweet::find()->with('tweetHashtags')->where(['id' => $tweetID])->all()

Related

Laravel Seeder throws SQLSTATE[42000]: Syntax error or access violation

I am having the following db tables
// Table 1: Foos
id, foo_name, foo_type, created_at, updated_at
// Table 2: Bars
id, bar_name, bar_type, parent_id, foo_id [ForeignKey], created_at, updated_at
// Table 3: Quxes
id, qux_name, bar_id [ForeignKey], created_at, updated_at
And I am having the following seeders setup
class FooSeeder extends Seeder
{
public function run()
{
\App\Models\Qux::truncate();
\App\Models\Bar::truncate();
\App\Models\Foo::truncate();
\App\Models\Foo::create([
'foo_name' => 'Foo',
'foo_type' => 'Foo type',
]);
}
}
class BarSeeder extends Seeder
{
public function run()
{
\App\Models\Qux::truncate();
\App\Models\Bar::truncate();
\App\Models\Bar::create([
'bar_name' => 'Bar',
'bar_type' => 'Bar type',
'foo_id' => 1,
'parent_id' => 1,
]);
\App\Models\Bar::create([
'bar_name' => 'Bar Bar',
'bar_type' => 'Bar Bar type',
'foo_id' => 1,
'parent_id' => 0,
]);
}
}
class QuxSeeder extends Seeder
{
public function run()
{
\App\Models\Qux::truncate();
\App\Models\Bar::truncate();
\App\Models\Qux::create([
'qux_name' => 'Qux',
'bar_id' => 1,
]);
\App\Models\Qux::create([
'qux_name' => 'Qux Qux',
'bar_id' => 1,
]);
}
}
When I try to run php artisan db:seed I get the following error
SQLSTATE[42000]: Syntax error or access violation: 1701 Cannot truncate a table referenced in a foreign key constraint (`mylaravelschema`.`quxes`, CONSTRAINT `qux_bar_id_foreign` FOREIGN KEY (`bar_id`) REFERENCES `mylaravelschema`.`bars` (`id`)) (SQL: truncate table `bars`)
I have been trying to play with the order of truncating the tables on these three seeders and still haven't manage to sort this, any help appreciated.
use it like this
class FooSeeder extends Seeder
{
public function run()
{
\App\Models\Foo::truncate();
\App\Models\Bar::truncate();
\App\Models\Qux::truncate();
\App\Models\Foo::create([
'foo_name' => 'Foo',
'foo_type' => 'Foo type',
]);
}
}
class BarSeeder extends Seeder
{
public function run()
{
\App\Models\Bar::create([
'bar_name' => 'Bar',
'bar_type' => 'Bar type',
'foo_id' => 1,
'parent_id' => 1,
]);
\App\Models\Bar::create([
'bar_name' => 'Bar Bar',
'bar_type' => 'Bar Bar type',
'foo_id' => 1,
'parent_id' => 0,
]);
}
}
class QuxSeeder extends Seeder
{
public function run()
{
\App\Models\Qux::create([
'qux_name' => 'Qux',
'bar_id' => 1,
]);
\App\Models\Qux::create([
'qux_name' => 'Qux Qux',
'bar_id' => 1,
]);
}
}
please use this hierarchy level because you've the foreign keys and when you're going to truncate it cannot find the reference one
Hope it helps

Undefined array key "id" in CodeIgniter 4

Undefined array key "id" in CodeIgniter 4
enter image description here
public function update($id)
{
$slug = url_title($this->request->getVar('nama_rak'), '-', true);
$this->rakModel->save([
'id' => $id,
'nama_rak' => $this->request->getVar('nama_rak'),
'slug' => $slug,
'detail_rak' => $this->request->getVar('detail_rak'),
'created_at' => $this->request->getVar('created_at'),
'updated_at' => $this->request->getVar('updated_at')
]);
return redirect()->to('/master/master_rak')->with('pesan', 'Data Berhasil diubah!');
}
this is the construct
class Master extends BaseController
{
protected $rakModel;
public function __construct()
{
$this->rakModel = new RakModel();
}
// Pengadaan Buku
public function master_rak()
{
$data = [
'pages' => 'Master Data',
'title' => 'Data Rak',
'rak' => $this->rakModel->getRak()
];
echo view("master/master_rak", $data);
}

Laravel resource return empty array

I have resource where i get product data trough third table but having hard time make relationships work on models so it return empty array.
Logic
Product has many barcodes
Barcodes can have (belongsTo) damage
In damage we get product trough barcode table (we store barcode_id)
I also included fillable part of each column so you can see columns in database.
Code
Product model
class Product extends Model
{
protected $fillable = [
'name', 'slug', 'stock', 'cover', 'description', 'sku', 'price', 'discount',
];
public function barcodes()
{
return $this->hasMany(Barcode::class);
}
}
Barcode model
class Barcode extends Model
{
protected $fillable = [
'product_id', 'sku', 'serial_number', 'price', 'discount',
];
public function product()
{
return $this->belongsTo(Product::class);
}
public function damages()
{
return $this->hasMany(DamageProduct::class);
}
}
DamageProduct model
class DamageProduct extends Model
{
protected $fillable = [
'outlet_id', 'user_id', 'barcode_id', 'description',
];
public function barcode()
{
return $this->belongsTo(Barcode::class);
}
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
}
DamageProductsResource resource
class DamageProductsResource extends JsonResource
{
public function toArray($request)
{
$arrayData = [
'id' => $this->id,
'outlet' => new OutletsResource($this->whenLoaded('outlet')),
'user' => new usersResource($this->whenLoaded('user')),
'barcode' => new BarcodeResource($this->whenLoaded('barcode')),
'description' => $this->description,
];
return $arrayData;
}
}
Result
Any idea?
Update
In case you need to see how BarcodeResource resource looks like here it is:
public function toArray($request)
{
$arrayNull = [
'id' => $this->id,
'product' => new ProductsResource($this->whenLoaded('product')),
'sku' => $this->sku,
'serial_number' => $this->serial_number ? (Int) $this->serial_number : null,
'price' => (Int) $this->price,
'discount' => $this->discount ? (Int) $this->discount : null,
];
}
I would say you simply forgot the return statement in your BarcodeResource
public function toArray($request)
{
$arrayNull = [
'id' => $this->id,
'product' => new ProductsResource($this->whenLoaded('product')),
'sku' => $this->sku,
'serial_number' => $this->serial_number ? (Int) $this->serial_number : null,
'price' => (Int) $this->price,
'discount' => $this->discount ? (Int) $this->discount : null,
];
return $arrayNull; // this is missing
}

Eager Load Pivot in nested BelongsToMany with Api Resource

I need your help!
I'm having problems returning pivot table information when using ApiResources.
If I have a model like this:
Post.php
public function likes()
{
return $this->belongsToMany(Like::class)
->withPivot(['points']) // I want this in my PostResource::collection !
}
When defining its Resources:
LikeResource.php
public function toArray($request)
{
return [
'like_field' => $this->like_field
];
}
PostResource.php
public function toArray($request)
{
return [
'title' => $this->title,
'likes' => LikeResource::collection($this->whenLoaded('likes'))
];
}
Then in PostController.php
return PostResource::collection(Post::with('likes')->get())
It will return something like this:
Controller Response
[
{
'title' => 'Post 1'
'likes' => [
{
'like_field' => 'Test'
},
{
'like_field' => 'Test 2'
}
]
},
{
'title' => 'Post 2',
...
}
]
The problem is, using that LikeResource::collection() it does not appends pivot information. How could I add 'points' of the pivot table when defining that PostResource??
Thats all,
Thx!
Solution
Well, simply reading a bit in Laravel Docs, to return pivot information you just has to use the method $this->whenPivotLoaded()
So, the PostResource becomes:
public function toArray($request)
{
return [
'title' => $this->title,
'likes' => LikeResource::collection($this->whenLoaded('likes')),
'like_post' => $this->whenPivotLoaded('like_post', function() {
return $this->pivot->like_field;
})
];
}

Yii2 Call to a member function someFunction() on Integer and a non-object

I wanna show usernames in timeline index. It show error
Call to a member function getStatusesLabel() on integer
if use this code :
'status' =>$model->data['status']->getStatusesLabel(),
and
'author' => $model->data['author']->getAuthor(),
and another error
Trying to get property of non-object
if use this code :
'author' => ArrayHelper::map($model->data['author']->getAuthor, 'id','username'),
My Model
namespace common\models;
.....
class Article extends ActiveRecord
{
.....
public function getAuthor()
{
return $this->hasOne(User::className(), ['id' => 'author_id']);
}
public function getUpdater()
{
return $this->hasOne(User::className(), ['id' => 'updater_id']);
}
public function getCategory()
{
return $this->hasOne(ArticleCategory::className(), ['id' => 'category_id']);
}
public function getArticleAttachments()
{
return $this->hasMany(ArticleAttachment::className(), ['article_id' => 'id']);
}
public static function statuses()
{
return [
self::STATUS_PUBLISHED => Yii::t('common', 'Published'),
self::STATUS_DRAFT => Yii::t('common', 'Draft'),
];
}
public function afterCreate()
{
$this->refresh();
// use common\commands\AddToTimelineCommand;
Yii::$app->commandBus->handle(new AddToTimelineCommand([
'category' => 'articles',
'event' => '_item',
'data' => [
'title' => $this->title,
'published_at' => $this->published_at,
'created_at' => $this->created_at,
'slug' => $this->slug,
'author' => $this->author_id,
'category' => $this->category,
'status' => $this->status,
]
]));
}
public function afterUpdate()
{
$this->refresh();
// use common\commands\AddToTimelineCommand;
Yii::$app->commandBus->handle(new AddToTimelineCommand([
'category' => 'articles',
'event' => '_itemU',
'data' => [
'title' => $this->title,
'published_at' => $this->published_at,
'updated_at' => $this->updated_at,
'slug' => $this->slug,
'author' => $this->author_id,
'category' => $this->category,
'status' => $this->status,
]
]));
}
}
my controller article:
public function actionCreate()
{
$model = new Article();
$transaction = Yii::$app->db->beginTransaction();
try{
if ($model->load(Yii::$app->request->post()) && $model->save()) {
$model->afterCreate();
$transaction->commit();
return $this->redirect(['index']);
} else {
return $this->render('create', [
'model' => $model,
'categories' => ArticleCategory::find()->active()->all(),
]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
controller timeline
public function actionIndex()
{
$searchModel = new TimelineEventSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$dataProvider->sort = [
'defaultOrder'=>['created_at'=>SORT_DESC]
];
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
command timeline :
class AddToTimelineCommand extends Object implements SelfHandlingCommand
{
public $category;
public $event;
public $data;
public function handle($command)
{
$model = new TimelineEvent();
$model->application = Yii::$app->id;
$model->category = $command->category;
$model->event = $command->event;
$model->data = json_encode($command->data, JSON_UNESCAPED_UNICODE);
return $model->save(false);
}
}
index timeline:
<ul class="timeline">
<?php foreach($dataProvider->getModels() as $model): ?>
<?php if(!isset($date) || $date != Yii::$app->formatter->asDate($model->created_at)): ?>
<!-- timeline time label -->
<li class="time-label">
<span class="bg-blue">
<?php echo Yii::$app->formatter->asDate($model->created_at) ?>
</span>
</li>
<?php $date = Yii::$app->formatter->asDate($model->created_at) ?>
<?php endif; ?>
<li>
<?php
try {
$viewFile = sprintf('%s/%s', $model->category, $model->event);
echo $this->render($viewFile, ['model' => $model]);
} catch (\yii\base\InvalidParamException $e) {
echo $this->render('_item', ['model' => $model]);
}
?>
</li>
view _item for index:
<div class="timeline-body">
<?php echo Yii::t('backend', 'Updated post <b>({title})</b>, published date : {published_at} ', [
'title' => Html::a($model->data['title'],
Url::to(Yii::$app->urlManager->hostInfo.'/article'.'/') .$model->data['slug'],
['target' => '_blank']),
//'author' => ArrayHelper::map($model->data['author']->getAuthor, 'id','username'),
//'author' => $model->data['author']->getAuthor(),
'author' => $model->data['author'],
'category' => $model->data['category'],
//'status' =>$model->data['status']->getStatusesLabel(),
'published_at' => Yii::$app->formatter->asDatetime($model->data['published_at']),
'updated_at' => Yii::$app->formatter->asDatetime($model->data['updated_at'])
])//.Html::a($model->data['title'], ["/article/$model->data['title']"]) ?>
</div>
what is wrong with the above code?
i was use in GridView / detailview, there is no errors
how do I fix it?
In a simple view (not based on gridview or detailView widget) that you render using eg:
return $this->render('your_view', [
'model' => $model,
]);
you can use directly the model and the attribute (or the depending function) eg:
'author' => $model->author
If you instead use a
return $this->render('your_view', [
'dataProvider' => $dataProvider,
]);
you can refer to the model instance
'author' => $dataProvider->models[i]['author']
where i is the index for the specific instance

Categories