Having problems in the store method Laravel-Eloquent - mysql

Been at this for a very long time and I can't get it right. Would be really thankful for some help. Thanks in advance!
Im trying to build a little clone of reddit some learning purpose.
I think these models is correct for what I'm trying to do. Im able to save a Subreddit to DB with user_id. But my problem is that I can't post to the post table since it's telling me it cannot find the subreddits_id column. Im seems like the method im trying to call should be working but it doesnt.
protected $fillable = ['title', 'link','content', 'post_picture', 'user_id', 'subreddit_id'];
//Functions
public function user () {
return $this->belongsTo(User::class);
}
public function subreddit() {
return $this->belongsTo(Subreddit::class);
}
public function comments () {
return $this->hasMany(Comment::class);
}
Above is my Post model
protected $guarded = [];
//Functions
public function user () {
return $this->belongsTo(User::class);
}
public function posts () {
return $this->hasMany(Post::class);
}
public function comments () {
return $this->hasMany(Comment::class);
}
Above is my Subreddit Model
public function posts () {
return $this->hasMany(Post::class);
}
public function subreddit() {
return $this->hasMany(Subreddit::class);
}
public function commments () {
return $this->hasMany(Comment::class);
}
Above is my User model
I think these models is correct for what I'm trying to do. Im able to save a Subreddit to DB with user_id. But my problem is that I can't post to the post table since it's telling me it cannot find the subreddits_id column. Im seems like the method im trying to call should be working but it doesnt.
The Store method looks like this:
public function store(Request $request)
{ $data = request()->validate([
'title' => 'required',
'link' => 'required',
'content' => 'required',
]);
$post = auth()->user()->posts()->create($data);
return redirect('/home');
}
I'm getting this error General error: 1364 Field 'subreddit_id' doesn't have a default value (SQL: insert into posts (title, link, content, user_id, updated_at, created_at) values (awe, ew, we, 2, 2020-04-01 17:41:29, 2020-04-01 17:41:29))

your $data only takes the parameters you specify for validation, But you did not include subreddit_id, It should be like this:
public function store(Request $request)
{ $data = request()->validate([
'title' => 'required',
'link' => 'required',
'content' => 'required',
'subreddit_id' => 'required|exist:subreddits,id'
]);
$post = auth()->user()->posts()->create($data);
return redirect('/home');
}

Related

HasONE YII2 link with 2 attributes

``` public function getContaCorrente()
{
return $this->hasOne(\app\models\ContaCorrente::className(), ['id' => 'conta_corrente_id']);
}```
Is it possible to add two attributes in the same get? For example, I have this get above and I want to join it with the get below, as they both look for the same table but different variables.
public function getContaCorrenteAdesao()
{
return $this->hasOne(\app\models\ContaCorrente::className(), ['id' => 'conta_corrente_adesao']);
}
Since this is a query builder you can do something like that:
public function getContaCorrenteAdesao()
{
return $this->hasOne(\app\models\ContaCorrente::className(), ['id' => 'conta_corrente_adesao'])->orWhere(['id' => 'conta_corrente_id']);
}

Many to many relationships in Yii2

I am trying to create a many to many relationship between a profile and several fields within that profile including languages and specialities. I have looked at several implementations and understand that there are several extensions, but I am required to minimise usage of extensions.
I have created the proper migration...this is a skeleton and the user table is purely for logins and OAuth...so keys can be ignored. As you can see in my controller I don't really know the way forward at this point. My language model is for all intensive purposes static from this controller(It is controlled by an admin backend). What is working? If I make a couple modifications to the below code then the checkboxlist will display with the proper checked items that I manually added to the lookup table. Trying to modify the lookup table from code, I have been unable to do unless I populate the $languageModel with a findOne(knownPK), however that is not usable, because multiple checkboxes can be selected resulting in an array and the link command requires ActiveRecordInterface which is singular. Ideally I would like to simply use
$languageModel->load(Yii::$app->request->post(),$trainerModel->formName());
but that isn't working.
Additionally, is there a mechanism within the framework to remove lookups or is that done manually. Any help or insight would be helpful. Thank you in advance.
public function safeUp()
{
$this->createTable('student', [
'id' => $this->primaryKey(),
'user_id' => $this->integer()->notNull(),
]);
$this->createTable('language', [
'id' => $this->primaryKey(),
'language' => $this->string(63),
]);
$this->createTable('student_language',[
'id' => $this->primaryKey(),
'language_id' => $this->integer(),
'student_id' => $this->integer()
]);
$this->addForeignKey('fk-student-language-language', 'student_language', 'language_id', 'language', 'id', 'CASCADE', 'CASCADE');
$this->addForeignKey('fk-student-language-student', 'student_language', 'student_id', 'student', 'id', 'CASCADE', 'CASCADE');
$this->addForeignKey('fk-student-user-user_id', 'student', 'user_id', 'user', 'id', 'CASCADE', 'CASCADE');
}
My student Active Record
/**
* #return \yii\db\ActiveQuery
*/
public function getstudentLanguages()
{
return $this->hasMany(studentLanguage::className(), ['student_id' => 'id']);
}
public function getLanguages(){
return $this->hasMany(Language::className(),['id'=>'language_id'])->viaTable('student_language',['student_id'=>'id']);
}
My Language Model
/**
* #return \yii\db\ActiveQuery
*/
public function getstudentLanguages()
{
return $this->hasMany(studentLanguage::className(), ['language_id' => 'id']);
}
public function getLanguages(){
return $this->hasMany(student::className(),['id'=>'student_id'])->viaTable('student_language',['language_id'=>'id']);
}
My Controller
public function actionProfile()
{
if (Yii::$app->user->isGuest) {
throw new UnauthorizedHttpException('This page requires you to be logged in');
} else {
$user_id = Yii::$app->user->identity->getId();
$studentModel = $this->findstudentModelByUserId($user_id);
if (is_null($studentModel)) {
$studentModel = new student();
$studentModel->setAttribute('user_id', $user_id);
$studentModel->save();
}
$languageModel = ??????????????????
$studentModel->load(Yii::$app->request->post()) && $studentModel->save() && $studentModel->link('languages',$languageModel);
}
return $this->render('profile', ['model' => $studentModel]);
}
My View
<?= $form->field($model, 'languages')->checkboxList(\common\models\Language::find()->select(
['language', 'id'])->indexBy('id')->column(), ['prompt' => 'select Language']); ?>
This is my solution at this point, however I am interested to hear improvements.
Note: There is no error checking etc...just functional code.
I added this to the student activerecord class
public function linkMultiple( $name,Array $models){
studentLanguage::deleteAll(['student_id' =>$this->id]);
foreach($models as $model){
$this->link($name, $model);
}
return true;
}
Modified my Controller action to the following
public function actionProfile()
{
if (Yii::$app->user->isGuest) {
throw new UnauthorizedHttpException('This page requires you to be logged in');
} else {
$user_id = Yii::$app->user->identity->getId();
$studentModel = $this->findstudentModelByUserId($user_id);
if (is_null($studentModel)) {
$studentModel = new student();
$studentModel->setAttribute('user_id', $user_id);
$studentModel->save();
}
$languages = Yii::$app->request->post('student')['languages'];
$languageModels = Language::findAll($languages);
$studentModel->load(Yii::$app->request->post()) && $studentModel->save() && $studentModel->linkMultiple('languages',$languageModels);
}
return $this->render('profile', ['model' => $studentModel]);
}

cakephp 3 + can't update database record when using translate behavior and 'contain'

I am using CakePHP 3 and trying to do some pretty basic stuff.
I have two tables, articles and tags.
Articles belongs to tags, and I made table tags translatable by attaching Translate behavior.
class ArticlesTable extends Table {
public function initialize(array $config) {
$this->addAssociations([
'belongsTo' => ['Tags']
]);
}
}
class TagsTable extends Table {
public function initialize(array $config) {
$this->addAssociations([
'hasMany' => ['Articles'],
]);
$this->addBehavior('Translate', ['fields' => ['name']]);
}
}
In Article controller I have edit function:
class ArticlesController extends AppController {
public function edit($id = null) {
$article = $this->Articles->get($id);
if ($this->request->is(['post', 'put'])) {
$this->Articles->patchEntity($article, $this->request->data);
if ($this->Articles->save($article)) {
$this->Flash->success(__('Your article has been updated.'));
return $this->redirect(['action' => 'edit',$id]);
}
$this->Flash->error(__('Unable to update your article.'));
}
$this->request->data = $article;
$tags = $this->Articles->Tags->find('list');
$this->set('tags', $tags);
}
}
In AppController I am setting locale language and at this point everything works fine, in edit.ctp file tags names are in local language and updating is working as it should.
BUT, when I replaced following line in edit function in ArticlesController:
$article = $this->Articles->get($id);
with line:
$article = $this->Articles->get($id, ['contain' => ['Tags']]);
I can no longer update article's tag.
If I change body and tag in my edit form, only new body is saved to my database. No error occurred, but tag_id is simply not changing.
If I remove translate behavior from the tags table, tags are not shown in local language, but can be updated again.
I am completely stuck, have no idea in which direction to search, why I can not use translate behavior and 'contain' at the same time?
Any help is greatly appreciated.

Yii Gridview show image from related data

i have table feedback and user, i am trying to show user's image on feedback page.
i am using grid view, this is my gridview.
[ 'attribute' => 'iduser.photo',
'headerOptions' => ['width' => '20px'],
'format' => 'image',
'value'=> function($data) { return $data->imageurl; },
],
and the model
public function getImageurl()
{
return \Yii::$app->request->BaseUrl.'/../../'.$this->hasOne(User::className(), ['photo' => 'photo']);
}
i get right url but the photoname is wrong the result is "photo", i want getting the data form entity photo?
Inside your model you should have a way to get the User related to your feedback like this:
public function getUser() {
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
Then your getImageurl method should look something like this:
public function getImageurl()
{
return \Yii::$app->request->BaseUrl.'/../../'.$this->user->photo;
}
I would recommend checking out Aliases, you can use them instead of \Yii::$app->request->BaseUrl. For example, this is the implementation i use to get a file url to show to the user:
public function getFileUrl() {
return Yii::getAlias('#web/uploads/'.$this->fileName);
}

QueryException - Integrity constraint violation: 1062 Duplicate entry when I hit the route 'logout'

I get the above error when I try and logout by hitting the route /logout. The table that is referenced in the screenshot is mdbids. It stores all of my IDs (strings, 16 characters in length).
When a user is created their MDBID (id) is stored in the mdbids table.
routes.php
<?php
Route::get('login', ['as' => 'login', 'uses' => 'SessionsController#create']);
Route::get('logout', ['as' => 'logout', 'uses' => 'SessionsController#destroy']);
SessionsController.php
<?php
use MDB\Forms\LoginForm;
class SessionsController extends \BaseController {
protected $loginForm;
function __construct(LoginForm $loginForm)
{
$this->loginForm = $loginForm;
}
public function create()
{
if(Auth::check()) return Redirect::to("/users");
return View::make('sessions.create');
}
public function store()
{
$this->loginForm->validate($input = Input::only('email','password'));
if (Auth::attempt($input)) {
Notification::success('You signed in successfully!');
return Redirect::intended('/');
}
Notification::error('The form contains some errors');
return Redirect::to('login')->withInput()->withFlashMessage("The form contains some errors");
}
public function destroy()
{
Auth::logout();
return Redirect::home();
}
}
The following is taken from my User.php (model) file. It isn't the whole file as it is fairly big, but this is the only part where IDs are mentioned.
User.php (model)
<?php
public function save(array $options = array())
{
$this->mdbid = $this->mdbid ?: str_random(16);
$this->key = $this->key ?: str_random(11);
Mdbid::create([
'mdbid' => $this->mdbid,
'table_number' => 7,
'table_name' => 'users',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
parent::save($options);
}
I don't know where to start to look. Any help is greatly appreciated.
Your issue is that the logout is actually causing save() to run, and therefor you are causing Mdbid::create to run with an already added key (presumably when you logged in, or somewhere else in your User model?).
Solution #1:
You could add a logout() function to the User model that you have. Something similar to
function logout()
{
$this->mdbid = null;
return Auth::logout()
}
This will stop two of the same keys being added to the logout function.
Solution #2
If what you are trying to accomplish is adding a row upon a successful login, then you should not be using the User::save() function, rather, you should be listening for the auth.login event.
Inside app/start/global.php, add the following code:
Event::listen('auth.login', function($user)
{
$user->mdbid = $user->mdbid ?: str_random(16);
$user->key = $user->key ?: str_random(11);
Mdbid::create([
'mdbid' => $user->mdbid,
'table_number' => 7,
'table_name' => 'users',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
});
This will ensure only one row gets added to Mdbid per successful login, instead of adding a new row (with the same id) each time the User model is updated.
Solution #3 (a.k.a. what was really wanted)
Each table has mdbid as a primary key. Each primary key needs to be added to the Mdbid table each time a new row is inserted.
The way that this should be done is with an Observer. The first part is adding a new Observer class that will be used for all of the models we want to add the mdbid into:
class MdbidObserver
{
/**
* Observe new rows being added into the database
*/
public function creating($model)
{
// note that $model could be any model
$model->mdbid = $model->mdbid ?: str_random(16);
$model->key = $model->key ?: str_random(11);
Mdbid::create([
'mdbid' => $model->mdbid,
'table_number' => 7,
'table_name' => 'users',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]);
}
}
The second part is adding the Observer to all the models that we want the mdbid added to (inside app/start/global.php):
User::observe(new MdbidObserver);
Artist::observe(new MdbidObserver);
Album::observe(new MdbidObserver);
To stop any issues with mdbid not actually being random already being used, you might want to add a loop just before $model->mdbid. Something similar to:
$isUnique = false;
while (!$isUnique)
{
$unqiueId = str_random(16);
$row = Mdbid::where('mdbid', $uniqueId);
if (is_object($row))
$isUnique = true;
}
$model->mdbid = $uniqueId;