Where provide "morphMap" setting for standalone eloquent usage without laravel - laravel

I am using eloquent as standalone module with slim framework (https://www.slimframework.com/docs/cookbook/database-eloquent.html)
My question is - where i can provide polymorphic relations "morphMap" setting?

you should define the morphMap in each function that define in morph or morphToMany:
example::
here is the comments function model:
class comment extends Model
{
public function commentable(){
Relation::morphMap([
'posts' => 'App\post',
'videos' => 'App\video',
]);
return $this->morphTo();
}
}
here is the post function model:
class post extends Model
{
public function comments(){
Relation::morphMap([
'posts' => 'App\post',
]);
return $this->morphMany('App\comment','commentable');
}
}
dont forget to add this namespace:
use Illuminate\Database\Eloquent\Relations\Relation;

To avoid to use morphMap in each model's relation you can override boot method setting there your morphMap:
class Post extends Model
{
protected static function boot(){`
parent::boot();
Relation::morphMap([
'posts' => 'App\post',
]);
}
public function comments(){
return $this->morphMany('App\Comment', commentable);
}
}

Today i searched for the same problem.
Slim4 & Eloquent.
I have to following code in my container boot file and it works.
container.php
// eloquent
$capsule = new \Illuminate\Database\Capsule\Manager;
$capsule->addConnection($dbSettings);
$capsule->setAsGlobal();
$capsule->bootEloquent();
$container->set('db', function ($container) use ($capsule) {
Illuminate\Database\Eloquent\Relations\Relation::morphMap([
App\Models\Order::class
]);
return $capsule;
});
now my database contains order instead of App\Models\Order
Don`t know if this is the correct way.
But this way I only have to write it in one place.

Related

How to insert into two table using laravel 8? This is my code

This is my code
I have a table inventory_transactions(id, part_name, part_number) and transaction_logs(id, description, inventory_transaction_id(FOREIGN KEY)). I want to insert the value of id to inventory_transaction_id.
What should I do?
namespace App\Http\Controllers;
use App\Models\Inventory_transaction;
use App\Models\Transaction_log;
use Illuminate\Http\Request;
public function store(Request $request){
$inventory_transaction = $request->validate($this->validation());
$value = Inventory_transaction::create($inventory_transaction);
return $this->respondWithMessage('Transaction added');
}
private function validation()
{
return [
'part_name' => ['required'],
'part_number' => ['required'],
];
}
Assuming that you have relationships defined as
class Inventory_transaction extends Model
{
public function transaction_logs()
{
return $this->hasMany(Transaction_log::class);
}
}
you can use the relation to insert related record
public function store(Request $request)
{
$validated = $request->validate($this->validation());
$transaction = Inventory_transaction::create($validated);
$transaction->transaction_logs()->create(['description' => 'Transaction Added.']);
return $this->respondWithMessage('Transaction added');
}
Having said that you should seriously spend some time going through Laravel docs, it will enable you to understand the basics very well - Laravel has one of the best documentation with lots of code examples for easy understanding of basic
Laravel relations: https://laravel.com/docs/8.x/eloquent-relationships#introduction

Laravel Polymorphic Relationships with order by

Laravel version 7.2.5.
I am using Polymorphic Relationships to store the access logs (login, logout) for multi-role application.
The data storing part is working completely fine. Now, I need to show the list of records in desc format with pagination. But, It's loading the data in the asc format
SomeModel.php
class SomeModel extends Model
{
/**
* Polymorphic Relationships
*/
public function loginLog()
{
return $this->morphMany(LoginLog::class, 'employable');
}
public function show($token)
{
return self::where([
'token' => $token,
])->with([
'loginLog:employable_id,ip,created_at,updated_at'
])->first() ?? null;
}
}
I did find the solution. But, somehow it doesn't feel the appropriate way to solve this issue.
Here is the link Laravel order results by column on polymorphic table
Try this
class SomeModel extends Model
{
/**
* Polymorphic Relationships
*/
public function loginLog()
{
return $this
->morphMany(LoginLog::class, 'employable')
->latest();
}
}
I found another way to solve this issue...
class SomeModel extends Model
{
/**
* Polymorphic Relationships
*/
public function loginLog()
{
return $this->morphMany(LoginLog::class, 'employable');
}
public function show($token, $pagination = 0)
{
return self::where([
'token' => $token,
])->with([
'loginLog' => function ($query) use ($pagination) {
return $query->select([
'employable_id',
'ip',
'created_at',
'updated_at',
])
->skip($pagination)
->take(\Common::paginationLimit())
->orderBy('id', 'DESC');
}
])
->orderBy('id', 'DESC')
->first('id') ?? null;
}
}
Since I do not need the base table's parameters, therefore, I am fetching only id from it.
Also, with this way I am able to use the pagination too (I am using loadmore pagination).

Eloquent Injected Multiple Model Relationships

So I learned in JeffreyWay's screencasts that I can use Eloquent to get the associated id from a model injected to another model.
I'm following his series about Laravel 5.4.
Here, I have a one-to-many relationships of user to posts.
App/Post
public function user()
{
return $this->belongsTo(User::class);
}
In my User Model, I have a publish method where the Post Model is injected. The publish method is used to create a post entry into the database.
App/User
public function posts()
{
return $this->hasMany(Post::class);
}
public function publish(Post $post)
{
$this->posts()->save($post);
}
I then have a store method in my PostsController that calls the publish method inside my User Model.
PostsController
class PostsController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
}
public function store()
{
auth()->user()->publish(
new Post(request(['title', 'body']))
);
}
}
When the publish method is called, the injected Post class automatically sets the user_id to the save method.
My question is, how do I make a relationship like this in a situation where for every posts, there are comments. These comments are associated to the Post and the User that created the comment.
In short, I should have both user_id and post_id when I call the addComment method.
User Model:
public function posts(){
return $this->hasMany(Post::class);
}
public function comments(){
return $this->hasMany(Comments::class);
}
Posts Model
public function user(){
return $this->belongsTo(User::class);
}
public function comments(){
return $this->hasMany(Comments::class);
}
Comments Model
public function post(){
return $this->belongsTo(Post::class);
}
public function user(){
return $this->belongsTo(User::class);
}
Example Problems:
1) Get user comments:
Solution: auth()->user()->comments()->get(); <- collection of user
comments .
2) Get user from the given comment:
Solution: Comment::find($someCommentId)->user()->first()->name; <-
User name from a specific comment.
3) Get all comments for a specific post .
Solution: Post::first()->comments()->get(); or eager load
Post::with('comments')->first(); <- A collection that contains post
information within it u can find a collection of comments for that
post.
4) Load user when loading a comment:
Solution: Comment::with('user')->first(); <- single collection
containing a collection with user info and comment info.
5) Load a specific user post and comments for that post at the same time:
Solution: User::with('posts.comments')->first(); <- Contains a
collection with user info and collection of all user posts with each
post containing comments.
In your question you wrote:
In short, I should have both user_id and post_id when I call the addComment method.
Which is absolutely correct and no problem. You don't have to set these properties through a method like $user->posts()->save($post) - this is just a convenience method that does the job for you (see save($model) and related setForeignAttributesForCreate($model) in the framework code; these methods just set the foreign key property for you).
In fact, the following three ways to create a new post are interchangeable:
// what you did
$user->posts->save(
new Post([
'title' => 'Hello',
'body' => 'World!',
])
);
// equivalent
Post::create([
'user_id' => \Auth::user()->id, // or \Auth::id()
'title' => 'Hello',
'body' => 'World!',
]);
// also equivalent
$post = new Post([
'user_id' => \Auth::user()->id, // or \Auth::id()
'title' => 'Hello',
'body' => 'World!',
]);
$post->save();
When storing a new comment, you will most likely have a controller like this, because a comment always belongs to a post and you therefore will need a reference of the post:
class CommentsController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
}
public function store(Post $post)
{
$comment = new Comment(request(['body']));
$comment->user_id = \Auth::user()->id;
$comment->post_id = $post->id;
$comment->save();
}
}
You could also abbreviate it and write:
Comment::create(
array_merge(request(['body']), ['user_id' => \Auth::id(), 'post_id' => $post->id])
);

Adding records to a relations repository with Laravel

I’m using laravel 5.5 and andersao/l5-repository. I want to add an answer record with the question repository.
My Question Controller
protected $repository;
public function __construct(QuestionRepository $repository)
{
$this->repository = $repository;
}
public function add_answer(AnswerAddRequest $request)
{
$this->validator->with($request->all())->passesOrFail(ValidatorInterface::RULE_CREATE);
$question = $this->repository->answer->create([
'content' => 'Answer text question',
'user_id' => Auth::user()->id
]);
return question;
}
My Question Model
public function answer()
{
return $this->belongsTo(Answer::class, 'question_id');
}
I tried '$this->repository->answer()'
always error : Undefined property
I think I have to use the with() method, but I don’t want to take all the content. I only need to add content with the relation of the model.
You should add this part of code
public function answer()
{
return $this->belongsTo(Answer::class, 'question_id');
}
into your Question mode, not into your repository.
The Laravel Eloquent class extends the Model class, which has methods like belongsTo that you're using.
--- EDIT ---
If you want to use repository, you could integrate it with Eloquent:
$this->reposotiry->find($request->input('question_id'))->answer()->create([
'content' => 'Answer text question',
'user_id' => Auth::user()->id
]);

PhpUnit - mocking laravel model with relations

I'm trying to mock (it's example only) $user->posts()->get().
example service:
use App\Models\User;
class SomeClass{
public function getActivePost(User $user): Collection
{
return $user->posts()->get();
}
}
and my Model:
and Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use \App\Models\Post;
class User extends Model
{
public function posts() : HasMany
{
return $this->hasMany(Post::class);
}
}
this doesn't work:
$this->user = Mockery::mock(User::class);
$this->user
->shouldReceive('wallets->get')
->andReturn('test output');
error:
TypeError: Return value of Mockery_2_App_Models_User::posts() must be an instance of Illuminate\Database\Eloquent\Relations\HasMany, instance of Mockery_4__demeter_posts returned
without return type hint (on post() method) everything is ok. Must I modify andReturn()? idk how
This error can be solved by using the alias prefix with a valid class name. Like the following:
$m = m::mock('alias:App\Models\User');
More information can be found at the official documentation http://docs.mockery.io/en/latest/reference/creating_test_doubles.html#aliasing
Alternatively you can use like this.
use App\Models\User;
class SomeClass{
public function getActivePost(User $user): Collection
{
$user->load('posts');
return $user->posts;
}
}
First you need to mock post, then add it to Collection (don't forget to use it in the top). Then when you call posts attribute its takes mocked $posts. In this case it will not throw error about return type.
use Illuminate\Database\Eloquent\Collection;
$post = $this->mock(Post::class)->makePartial();
$posts = new Collection([$post]);
$this->user = Mockery::mock(User::class);
$this->user
->shouldReceive('getAttribute')
->with('posts');
->andReturn($posts);
Also i wouldn't use mocks here. There is absolutely no need for it. So the unit test i write would be:
Create a user.
Create some posts authored by the user.
Perform assertions on user & posts.
So the code will then be something like this in my test:
$user = factory(User::class)->create();
$posts = factory(Post::class, 5)->create(['user_id' => $user->id]);
$this->assertNotEmpty($user->id);
$this->assertNotEmpty($posts);
$this->assertEquals(5, $posts->fresh()->count());
$this->assertEquals($user->id, $post->fresh()->first()->user_id);
if you want to test the relationship you can:
/** #test */
function user_has_many_posts()
{
$user = factory(User::class)->create();
$post= factory(Post::class)->create(['user_id' => $user->id]);
//Check if database has the post..
$this->assertDatabaseHas('posts', [
'id' => $post->id,
'user_id' => $user->id,
]);
//Check if relationship returns collection..
$this->assertInstanceOf('\Illuminate\Database\Eloquent\Collection', $user->posts);
}

Resources