Eloquent save() not working with PHP & MySQL - php

I hope you're having a great week.
I've been meddling with PHP and Silex. MySQL is the db. I am trying to create a post route & controller. I am using Eloquent as an ORM tool here, but it is not working and worse there is no log or a trace about any error. This is quite strange. I know that MySQL assumes that the created_at and updated_at fields exist in the tables. Although they do exist, I cannot get it working. I am open for anything here. I'd appreciate any help in fixing this.
Below you can find the code snippets...
This is the Model class
<?php
namespace DemoApp\Models;
class Apple extends \Illuminate\Database\Eloquent\Model
{
}
And this is the post route in index.php
$app->post('/apple', function(Request $request) use($app) {
$_apple = $request->get('apple');
$apple = new Apple();
$apple->body = $_apple;
$apple->user_id = 1;
$apple->save();
return new Response('Apple created.', 200);
});
PS: created_at and updated_at fields are present in the model table.
Peace...

Related

One To Many Relationship in Eloquent with JSON field

I'm trying to create a connection between a JSON field in my database and a table which stores music by ID. So, I have a table called "playlists" which has a field called "songs". In this "songs" field I have a array[] of song ID's e.g. [1,2]. I tried the following code to make a relationship between these two tables:
class Playlist extends Model
{
protected $table = 'playlists';
public function songs()
{
return $this->hasMany('App\Music', 'id');
}
}
I used the foreign_key id because of the songs table which has a id field.
The code I used to retrieve the playlist from the controller is as follows:
$playlist = Playlist::find($id)->songs;
print_r($playlist);
Which outputs:
[1,2]
I most probably did something wrong, not understanding the relationships correctly. Could someone explain how this works? I looked up the documentation but did not get any wiser.
Laravel has no native support for JSON relationships.
I created a package for this: https://github.com/staudenmeir/eloquent-json-relations
If you rename the songs column to song_ids, you can define a many-to-many relationship like this:
class Playlist extends Model
{
use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
protected $casts = [
'song_ids' => 'json',
];
public function songs()
{
return $this->belongsToJson('App\Music', 'song_ids');
}
}
class Music extends Model
{
use \Staudenmeir\EloquentJsonRelations\HasJsonRelationships;
public function playlists()
{
return $this->hasManyJson('App\Playlist', 'song_ids');
}
}
Although this is a very old post but I will go ahead and drop my own opinion for my future self and fellow googlers.....
So, If I got this question correctly, you are trying to use a JSON field for a relationship query. This issue I have stumbled across a couple of times, at different occasions for different use-cases. With the most recent being for the purpose of saving a couple of Ids belonging to different tables, in a single JSON field on a given table (While I keep pondering on why the Laravel guy won't just add this functionality already! I Know Pivots, Data Normalization etc....But I'm pleading for the 1%). Until I came across this post on Laracast that worked like a charm.
Apologies for the long intro, let me get right into it....
On your Playlist model (in Laravel 8.0 and a few older versions I can't really keep track of) you can do something like so;
public function songs()
{
$related = $this->hasMany(Song::class);
$related->setQuery(
Song::whereIn('id', $this->song_ids)->getQuery()
);
return $related;
}
I have the really good solution for keeping data in column on json format. It help me on previous project online shop
https://scotch.io/tutorials/working-with-json-in-mysql

Advanced Laravel merged data/models - can it be done at model level?

We have a COMMON database and then tenant databases for each organization that uses our application. We have base values in the COMMON database for some tables e.g.
COMMON.widgets. Then in the tenant databases, IF a table called modified_widgets exists and has values, they are merged with the COMMON.widgets table.
Right now we are doing this in controllers along the lines of:
public function index(Request $request)
{
$widgets = Widget::where('active', '1')->orderBy('name')->get();
if(Schema::connection('tenant')->hasTable('modified_widgets')) {
$modified = ModifiedWidget::where('active', '1')->get();
$merged = $widgets->merge($modified);
$merged = array_values(array_sort($merged, function ($value) {
return $value['name'];
}));
return $merged;
}
return $countries;
}
As you can see, we have model for each table and this works OK. We get the expected results for GET requests like this from controllers, but we'd like to merge at the Laravel MODEL level if possible. That way id's are linked to the correct tables and such when populating forms with these values. The merge means the same id can exist in BOTH tables. We ALWAYS want to act on the merged data if any exists. So it seems like model level is the place for this, but we'll try any suggestions that help meet the need. Hope that all makes sense.
Can anyone help with this or does anyone have any ideas to try? We've played with overriding model constructors and such, but haven't quite been able to figure this out yet. Any thoughts are appreciated and TIA!
If you put this functionality in Widget model you will get 2x times of queries. You need to think about Widget as an instance, what I am trying to say is that current approach does 2 queries minimum and +1 if tenant has modified_widgets table. Now imagine you do this inside a model, each Widget instance will pull in, in a best case scenario its equivalent from different database, so for bunch of Widgets you will do 1 (->all())+n (n = number of ModifiedWidgets) queries - because each Widget instance will pull its own mirror if it exists, no eager load is possible.
You can improve your code with following:
$widgets = Widget::where('active', '1')->orderBy('name')->get();
if(Schema::connection('tenant')->hasTable('modified_widgets')) {
$modified = ModifiedWidget::where('active', '1')->whereIn('id', $widgets->pluck('id'))->get(); // remove whereIn if thats not the case
return $widgets->merge($modified)->unique()->sortBy('name');
}
return $widgets;
OK, here is what we came up with.
We now use a single model and the table names MUST be the same in both databases (setTable does not seem to work even though in exists in the Database/Eloquent/Model base source code - that may be why it's not documented). Anyway = just use a regular model and make sure the tables are identical (or at least the fields you are using are):
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Widget extends Model
{
}
Then we have a generic 'merge controller' where the model and optional sort are passed in the request (we hard coded the 'where' and key here, but they could be made dynamic too). NOTE THIS WILL NOT WORK WITH STATIC METHODS THAT CREATE NEW INSTANCES such as $model::all() so you need to use $model->get() in that case:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class MergeController extends Controller
{
public function index(Request $request)
{
//TODO: add some validations to ensure model is provided
$model = app("App\\Models\\{$request['model']}");
$sort = $request['sort'] ? $request['sort'] : 'id';
$src_collection = $model->where('active', '1')->orderBy('name')->get();
// we setup the tenants connection elsewhere, but use it here
if(Schema::connection('tenant')->hasTable($model->getTable())) {
$model->setConnection('tenant');
$tenant_collection = $model->get()->where('active', '1');
$src_collection = $src_collection->keyBy('id')->merge($tenant_collection->keyBy('id'))->sortBy('name');
}
return $src_collection;
}
}
If you dd($src_collection); before returning it it, you will see the connection is correct for each row (depending on data in the tables). If you update a row:
$test = $src_collection->find(2); // this is a row from the tenant db in our data
$test->name = 'Test';
$test->save();
$test2 = $src_collection->find(1); // this is a row from the tenant db in our data
$test2->name = 'Test2'; // this is a row from the COMMON db in our data
$test2->save();
dd($src_collection);
You will see the correct data is updated no matter which table the row(s) came from.
This results in each tenant being able to optionally override and/or add to base table data without effecting the base table data itself or other tenants while minimizing data duplication thus easing maintenance (obviously the table data and population is managed elsewhere just like any other table). If the tenant has no overrides then the base table data is returned. The merge and custom collection stuff have minimal documentation, so this took some time to figure out. Hope this helps someone else some day!

Can't get Laravel associate to work

I'm not quite sure if I understand the associate method in Laravel. I understand the idea, but I can't seem to get it to work.
With this (distilled) code:
class User
{
public function customer()
{
return $this->hasOne('Customer');
}
}
class Customer
{
public function user()
{
return $this->belongsTo('User');
}
}
$user = new User($data);
$customer = new Customer($customerData);
$user->customer()->associate($customer);
I get a Call to undefined method Illuminate\Database\Query\Builder::associate() when I try to run this.
From what I can read, I do it exactly as is stated in the docs.
What am I doing wrong?
I have to admit that when I first started using Laravel the relationships where the part that I had to consistently refer back to the docs for and even then in some cases I didn't quite get it right.
To help you along, associate() is used to update a belongsTo() relationship. Looking at your code, the returned class from $user->customer() is a hasOne relationship class and will not have the associate method on it.
If you were to do it the other way round.
$user = new User($data);
$customer = new Customer($customerData);
$customer->user()->associate($user);
$customer->save();
It would work as $customer->user() is a belongsTo relationship.
To do this the other way round you would first save the user model and then save the customer model to it like:
$user = new User($data);
$user->save();
$customer = new Customer($customerData);
$user->customer()->save($customer);
Edit: It may not be necessary to save the user model first but I've just always done that, not sure why.
As I understand it, ->associate() can onyl be called on a BelongsTo relationship. So, in your example, you could do $customer->user()->associate($user). However, in order to 'associate' a Has* relationship you use ->save(), so your code should be $user->customer()->save($customer)
just add ->save() to the end.
$user->customer()->associate($customer)->save();

Questions about Using laravel with several models / MySQL tables

I'm new with laravel + frameworks and i'm having a few issues.I read the laravel documentation and tried asking for support on their forums - no results/
In my current setup - I followed the laravel documentation & code
I have 1 Model : User
I have 1 table in the db : users
Everything works fine for the login / registration parts etc....
However now i need to create several new tables & maybe some more models :
I searched the web and there are no tutorials or anything else to guide me how to do it.
Any help would be greatly appreciated .
Tried :
In Models -
created : profile.php
class Profile extends Eloquent implements UserInterface, RemindableInterface {
protected $table = 'profile';
}
It doesn't seem to work , I'm wondering if i have to link the file or something in the laravel framework etc..
P.s : I used artisan and migrations to create the user table
I am now creating the tables directly in the database but i have no idea how to access them such as :
in the user table , i can use :
Auth::user()->username - to get the username
however in the new table (profile) -
I have absolutely no idea how to access it using laravel code.
Have you read over the documentation http://laravel.com/docs/eloquent?
Create a new file inside of ../app/models/
../app/models/Profile.php
** note the file matches the classname
inside the model:
class Profile extends Eloquent {
protected $table = 'profile';
}
Then in your controller or route closure access the model via
$profile = Profile::find(1);
or
$profile = App::make('Profile');
$profile->about = 'About the user';
$profile->save();

Cannot insert to my new table

I have created a migration for ratings, and the table also working when i am entering phpmyadmin.
The problem is, i cannot figure out, how to write to the table?
I am running the code from "story" controller
I am using this:
$z = new Rating();
$z->story_id = 10;
$z->save();
print_r($z);
My "ratings.php" model:
<?php
class Rating extends Eloquent {
protected $table = 'ratings';
}
?>
Is there some place where i should notify laravel that new Rating() means my table "ratings"?
It doesn't seem like i have done the migration correctly, but i am completely new still, so hope someone can figure it out for me.
well instead of using the save() function for laravel you can use the insert() function
Rating->insert_get_id(array('story_id' => '10'));
or
$insert_id = Rating->insert_get_id(array('story_id' => '10'));
for insertion into table.This is much easy to use and I have used this in my whole project and so far I haven't face any problems.
Also if you have not created the model for rating table then go to the models folder under application folder and create a file name rating.php and inside the file write this:
class Rating extends Eloquent
{
public static $timestamps = false;
}
Also please note that table which you created in the phpmyadmin should have name of the form "ratings".
I hope this can be of some help.
I don't really understand what you're doing. Are you trying to write into the table from php? Is Rating a sort of database connection class? You need to create a mysqli object to connect to the database, write a query, and get a result. For best security use a prepared statement. Mysqli Documentation Sorry if I'm off-base about your question, I'm just not positive about what it is.

Categories