Eloquent saves multiple models to database by error - php

I have a controller that creates a new model then passes it to the view
public function fill_site_form($id, $step_id, $form_id){
$form = new FormEntry();
$form->site_id = $id;
$form->form_id = $form_id;
$form->step_id = $step_id;
$form->entry_json = Form::find($form_id)->form_json;
$form->save();
return view('sites.fill_site_form', ['form' => $form]);
}
I need it to only create one record in the db but it creates 2 records everytime I go to that route.
I have removed the ->save and then no records are inserted into the DB.
Any suggestions?
Edit:
Image of DB entries on the $form->save:
SCREENSHOT IMAGE LINK
The DB Schema:
Schema::create('form_entries', function (Blueprint $table) {
$table->increments('id');
$table->integer('site_id');
$table->integer('form_id');
$table->integer('step_id');
$table->text('entry_json', 600000);
$table->timestamps();
});
The code that receives the ajax from the sites.fill_site_form view
public function update_site_ajax($id, Request $request){
$entry = FormEntry::find($id);
$entry->entry_json = json_encode($request->form_json);
$entry->save();
return $request->all();
}
Front end AJAX code:
$('#submit_button').click((e)=>{
$.ajax({
type:'PATCH',
url:'/site/' + document.getElementById('form_id').value,
data: {'form_json' : renderer.userData},
success:function(data){
$.notify("Form successfully Updated!",
{
position:"top center",
className: 'success'
}
);
console.log('Response: ', data)
}
});
});

I couldn't get it working with Model::create or Model->save, So I resorted to Model::firstOrCreate which looks more stable, still would like to know why only on that model it creates two entries

Related

Laravel incrementing the db value by 2 times

This is function that is returning the view
// show individual post
public function showPost($id){
$targetPost = Post::findorFail($id);
$targetPost->increment('post_view_count');
$post = [
'post' => $targetPost,
'related_posts' => Post::all()->sortByDesc("id")->take(2)// load some related posts too
];
return view('post_single', $post);
}
What I am wanting here is to update the value by 1 when someone visits the page, the posts are in a list view to some other page, user are supposed to click that link.
Everything is working, but instead of incrementing the value by 1, it is incrementing by 2 even if I hit the reload button.
What I can assume is that the page is requested twice or loading via some kinda middleware first. That's why the request is being sent twice. How do I fix this?
Such a basic counter will not suit your needs. What you can do is create a migration for your Post Views:
Schema::create("post_views", function(Blueprint $table)
{
$table->unsignedInteger("id");
$table->unsignedInteger("id_post");
$table->string("session_id");
$table->string("user_id");
$table->string("ip");
$table->string("agent");
$table->timestamps();
});
Next create a model that will handle the views for you
class PostsViews extends \Eloquent {
protected $table = 'posts_views';
public static function createViewLog($post) {
$postsViews= new PostsViews();
$postsViews->id_post = $post->id;
$postsViews->titleslug = $post->titleslug;
$postsViews->url = \Request::url();
$postsViews->session_id = \Request::getSession()->getId();
$postsViews->user_id = \Auth::user()->id;
$postsViews->ip = \Request::getClientIp();
$postsViews->agent = \Request::header('User-Agent');
$postsViews->save();
}
Now use this in your showPost function():
public function showPost($id){
$targetPost = Post::findorFail($id);
PostsViews::createViewLog($targetPost);
$post = [
'post' => $targetPost,
'related_posts' => Post::all()->sortByDesc("id")->take(2)
];
return view('post_single', $post);
}
Now it will log all views but you can filter it out when you need it on User agent, IP address or session. You can also use that kind of filter when logging a view to just log 1 view per post per viewer.

function static::created does not save properly Laravel

So I have 2 tables: Item and Product. An Item hasMany Products and a Product belongsTo an Item.
Products migration:
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('hashed_id')->nullable()->unique();
$table->bigInteger('item_id')->unsigned();
$table->bigInteger('user_id')->unsigned();
$table->integer('state')->default(1);
$table->decimal('price');
$table->string('slug')->nullable()->unique();
$table->timestamps();
$table->foreign('item_id')->references('id')->on('items')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
For the hashed_id I use the following package: https://packagist.org/packages/hashids/hashids to create a hashed id to show in the url.
Product.php
public static function boot()
{
parent::boot();
static::created(function ($product) {
$productId = $product->id;
$hashids = new Hashids("", 10, 'abcdefghijklmnopqrstuvwxyz1234567890');
$hashedId = $hashids->encode($productId++);
$slug = Str::slug($product->item->slug . '-' . $hashedId);
$product->hashed_id = $hashedId;
$product->slug = $slug;
});
}
ProductsController.php
public function createSelfProduct(Request $request)
{
$product = auth()->user()->products()->create([
'item_id' => $request->item_id,
'user_id' => auth()->user()->id,
'price' => $request->price,
]);
// create the product and show seller info
return new ProductResource($product->load('user'));
}
What I'm trying to do is that when a user creates a new product, it should get the slug from the item model, put the $hashedId behind it and save that to the db. Now, when I do a post request via Postman, I get the desired result, as hashed_id and slug are saved. But when I check the database, both hashed_id and slug are NULL. Only the item_id, user_id and price are saved. What am I doing wrong and how can I fix this?
The created event means the Model has already been created. This is not before save, but after it has been saved. If you alter anything at this point you will need to save the record again.
Simply: You forgot to call save on your model instance to save the changes after you altered it.
Laravel has a convenient way of handling this with Observers
https://laravel.com/docs/5.8/eloquent#observers
php artisan make:observer ProductObserver
Then in Observers/ProductObserver.php
public function created(Product $product) {
$product = ''; // whatver you need to do here. $product is an instance of Product model
// Dont forget to save your model after modifying
$product->save();
}

Default value for a photo in laravel

Hi i'm trying to make a function that allows everyone to publish whatever they want but when the visitor is not a user his post photo's default will be a photo from my directory storage that holds the meaning of anonymous or something alike:
what is the SQL command line that allows me to do so?
My post migration table is:
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('username');
$table->string('body');
$table->boolean('valid')->default(0);
$table->string('photo',150)->nullable();
$table->timestamps();
});
My function store() is the following:
public function store(Request $request)
{
$post= new Post();
$post->title=$request->input('title');
$post->photo=$request->photo; //what do i change in this field?
$post->username=$request->input('username');
$post->body=$request->input('body');
$post->save();
return redirect ('/ed');
}
Any ideas would be appreciated, thank you
You can use this:
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// The user is logged in...
$postPhoto = $request->photo
} else{
//photo from directory storage
$postPhoto = public_path('/images/default.jpg');
}
// store photo in the database
$post->photo = $postPhoto;
#Wellwisher is right! But you can also set a default value to the photo field at posts table (and that is if you not planning to change the image name).
$table->string('photo', 150)->default('avatar.jpg');
and you will overwrite (change) it in case user uploads a new image as his/her profile image.

How to get ID from different controllers Yii2?

In the ActiveForm I have model button with Pjax render field after form from the modal button will created. Added a picture for an example. How can I get newly created id (not select added to the database, need to get the id that comes from this form).
I think I need to set get to button, than with ajax catch this and transfer to my Pjax rendered cell
I tried variations, but unsuccessfully, I cann't fully understand how to implement it. Can anyone help with the solution ?
//TwoController
public function actionCreate()
{
$model = new Formtwo();
if ($model->load(Yii::$app->request->post())) {
if ($model->save()) {
echo 1;
//maybe here I must to do query ?
} else {
echo 0;
}
} else {
return $this->renderAjax('create', [
'model' => $model,
]);
}
}
Index GridView
I hope I understood correct; you wish that when a user creates an instance of Form2, it is transferred then to create an instance of Form1, and the id of newly created record for Form2, is put in the Form1 _form.
If I did not understand correctly, please explain better :)
In TwoController create action, after creation, you would call the create action of OneContrller:
if ($model->save()) {
return \Yii::$app->runAction('/controller/action-name', ['form2_id'=>$model->id]);
}
On OneController actionCreate add parameter with default value:
public function actionCreate($form2_id=null) {
and make sure it is passed to the view (don't forget to make sure you pass it on create.php as well to the _form.
//TwoController
public function actionCreate()
{
$model = new Formtwo();
if ($model->load(Yii::$app->request->post())) {
if ($model->save()) {
echo $model->id;
//maybe here I must to do query ?
} else {
echo 0;
}
} else {
return $this->renderAjax('create', [
'model' => $model,
]);
}
}
You don't need query. Just use $model->id. It has value after save().
Update
It doesn't matter in which controller you are. You get the id of the model saved after save(). Then you can use id attribute. So, you can open modal form with ajax load. On form2 you register script to ajax post form. Something like this:
$("#form :submit").click(function (e) {
e.preventDefault();
$.ajax({
method: "POST",
url: $("#form").attr("action"),
data: $("#form").serialize(),
success: function (response) {
$("#modalid").modal("hide")
$.pjax.reload({
container: "#grid"
});
$('#Form2_id').val(response); //here you get the id
},
})
return false;
});

Laravel 5.2 multilanguage with dimsav/laravel-translatable

I am using dimsav for multilanguage and I have this problem after doing step by step from the guid. (dimsav)
I have a Model Category:
use Illuminate\Database\Eloquent\Model;
use Dimsav\Translatable\Translatable;
class Category extends Model {
use Translatable;
public $translatedAttributes = ['name'];
}
A CategoryTranslation:
use Illuminate\Database\Eloquent\Model;
class CategoryTranslation extends Model {
public $timestamps = false;
}
And in Controller when I try to save this with a specific language I get an error. This is my controller:
$language = App::getLocale();
$user = Auth::user();
$category = new Category();
$category->translate('en')->name = Input::get('name'); //line 35
$category->save())
And error:
at HandleExceptions->handleError('2', 'Creating default object from
empty value',
'C:\workspace\applications\wamp\www\lutz-paletten\app\Http\Controllers\CategoryController.php',
'35', array('language' => 'en', 'user' => object(User), 'category' =>
object(Category))) in CategoryController.php line 35
PS: this is my migration:
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->integer('categoryId');
$table->integer('user_id');
$table->timestamps();
});
Schema::create('category_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->string('name');
$table->string('locale')->index();
$table->unique(['category_id','locale']);
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
});
What am I missing ?
If I use this, it works:
$category->name = Input::get('name');
And it will be saved with what is set as AppLocale but how can I use it with translate() ?
I don't know if you solved this or not, but i think you should check with a couple of things:
1- delete the Parentheses when initiating the Category object so it will become:
$category = new Category;
2- Change the extra Parentheses after the save function so it will be:
$category->save();
3- make sure your input is named correctly.
and that's all i can see, hope you solved already :).
BTW you don't need that
$table->integer('categoryId'); in your migration is not nessary since $table->increments('id); is playing that role!
happy coding :)
If you create a new record of Category, this last one saves record with your current Locale (default : en).
You just need to change $category->translate('en') by $category->getNewTranslation('en') or $category->translateOrNew('en') and it works !
For your example:
Create a category with default locale (config/app.php ==> locale => 'en'):
// CategoryController
public function createCategory(Request $request)
{
// Save record in *categories* table
// And save the default language (config/app.php ==> locale) in *category_translations* table.
$category = new Category::create($request);
}
Create a translation in an existing category:
public function createCategoryTranslation(Request $request, $id)
{
$category = Category::find($id)
// Solution 1 : If you want to explain the fields to be saved.
$category->getNewTranslation('en')->name = $request->input('name');
// Solution 2 : Mass assignement if you have multiple fields to be saved.
$category->getNewTranslation('en')->fill($request);
$category->save()
}
Update a translation:
public function updateCategoryTranslation(Request $request, $id)
{
$category = Category::find($id)
// Solution 1 : If you want to explain the fields to be saved.
$category->translate('en')->name = $request->input('name');
// Solution 2 : Mass assignement if you have multiple fields to be saved.
$category->translate('en')->fill($request);
$category->save()
}
CreateOrUpdate translation:
public function createOrUpdateCategoryTranslation(Request $request, $id)
{
$category = Category::find($id)
// Solution 1 : If you want to explain the fields to be saved.
$category->translateOrNew('en')->name = $request->input('name');
// Solution 2 : Mass assignement if you have multiple fields to be saved.
$category->translateOrNew('en')->fill($request);
$category->save()
}

Categories