Restructuring database and multiple views for model - laravel

I have a system where a user can input data into various forms and generate a custom document. When I set everything up, because each form has unique data, I create a Model/Controller for each type of document e.g. BriefDocument, InvoiceDocument etc.
I soon discovered that this became very messy, way too many Models and Controllers. It also took quite a long time to create a new document type. As such, I have rearranged my database.
I now have a Document model and a DocumentData model. A Document can have many Document Data. I envision something like this
Document
+----+---------------+-----------------+
| id | name | description |
+----+---------------+-----------------+
| 1 | BriefDocument | Something |
+----+---------------+-----------------+
DocumentData
+----+--------------+-----------------+--------------+
| id | key | value | documentId |
+----+--------------+-----------------+--------------+
| 1 | whatData | inputted data | 1 |
+----+--------------+-----------------+--------------+
| 2 | whoData | inputted data | 1 |
+----+--------------+-----------------+--------------+
| 3 | whyData | inputted data | 1 |
+----+--------------+-----------------+--------------+
| 4 | howData | inputted data | 1 |
+----+--------------+-----------------+--------------+
Doing this should allow me to create any type of Document using just these two models. My first problem is this, I have set up the routes as follows
Route::model('projects.document', 'Document');
Route::resource('projects.document', 'DocumentController', ['except' => ['index', 'show']]);
On a page I have a dropdown where the user can select the type of document they create. The dropdown has things like this
<li>{!! link_to_route('projects.document.create', 'Brief Document', array($project->id, 'Brief Document')) !!}</li>
So this will call the create function within my DocumentController
public function create(Project $project, $name)
{
$briefDocument = Document::where('projectId', '=', $project->id)
->where('name', '=', $name)
->first();
}
What I am trying to do in this function is first determine whether the same Document has already been created for this Project, because a Project can only have many documents, but no repeat documents.
If I do this however, I get
Missing argument 2 for App\Http\Controllers\DocumentController::create()
But am I not passing it arguement 2 within the link_to_route? From what I can see, this is passing my Project instance, as well as the string Briefing Document.
Why would I be getting this error?
Thanks
UPDATE
If I explicitly set the route it works e.g.
Route::model('projects.document', 'Document');
Route::get('projects/{projects}/document/{name}', array('as' => 'projects.document.create', 'uses' => 'DocumentController#create'));

You're getting this error, because you do not pass $name variable to the create() action.
Maybe the problem is in create() itself. This method is a part of RESTful controller and looks like it was designed to accept only Request object, so try this:
<li>{!! link_to_route('projects.document.create', 'Brief Document', ['project_id' => $project->id, 'name' => Brief Document')) !!}</li>
And create() action:
public function create(Request $request)
{
$id = $request->get('project_id');
$name = $request->get('name');
$briefDocument = Document::where('projectId', '=', $project->id)
->where('name', '=', $name)
->first();
}

Related

How should I use HasManyThrough connecting 3 tables via 2 pivot tables in Laravel?

I am having trouble wrapping my head around the HasManyThrough relationship in Laravel 5.8 which I think is what I need to use, but I am not sure how to implement. I've tried following along a Laracasts video where Jeffrey describes it and read the docs, but I can't seem to grasp the concept and feeling rather stupid right now.
How should I define the relationships in my models and write the correct Eloquent query in my ProductsController to display posts in a product view that shares the same tag id?
For example I have a post tagged with "mbti" and I have a product tagged also with "mbti". How would I go about displaying those related posts in the relevant product view? I've managed to display the tags in the view so far, but I want the posts associated with that tag to display as well. I appreciate any guidance on how I should approach this.
I have 3 tables and 2 pivot tables (some column names removed for brevity):
| products |
+----------+
|id |
------------
| posts |
+----------+
|id |
------------
| tags |
+----------+
|id |
------------
| post_tag |
+----------+
|post_id |
|tag_id |
------------
| product_tag |
+-------------+
|product_id |
|tag_id |
---------------
My models:
Post.php
public function tags() {
return $this->belongsToMany('App\Tag')->withPivot('tag_id');
}
Tag.php
public function posts()
{
return $this->belongsToMany('App\Post')->withPivot('post_tag');
}
public function products()
{
return $this->belongsToMany('App\Product')->withPivot('product_tag');
}
Product.php
public function tags()
{
return $this->belongsToMany('App\Tag')->withPivot('product_id');
}
I ended up adding a tag_id column to my products table and referencing the tag id there. A product in my application can only be assigned one tag, so the need for a pivot table was kind of redundant and added unnecessary complexity.
In my Tag.php model, I defined the relationship as:
public function products()
{
return $this->hasManyThrough('App\Post', 'App\Product');
}
and in my ProductsController.php I select the tags as such in mthe show method:
$tag = Tag::where('id', '=', $product->tag_id)->first();
if($tag) {
$tags = Tag::whereName($tag->name)->first();
}

How to eager loading with laravel on a different naming convention

I have two tables. 'weeks' and 'dates'
The weeks table holds an 'startDate' and an 'endDate' Both columns a foreignKeys to the dates columns. The dates table holds an primary key id and the date.
weeks
| IDweeks | startDate | endDate |
| 1 | 2 | 6 |
dates
| IDdates | date |
| 1 | 12-03-2018 |
| 2 | 13-03-2018 |
.....
When I query the weeks, I always get the keys for startDate and endDate. I would like to get the values from the dates tables instead.
I´ve already tried to eager load the values like this:
weeks Modal
class weeks extends Model
{
//....
public function startDate()
{
return $this->belongsTo('App\date', 'startDate', 'date');
}
public function endDate()
{
return $this->belongsTo('App\date', 'endDate', 'date');
}
//....
dates Modal
class date extends Model
{
protected $primaryKey = 'IDdates';
calling the 'with()' method
public function showWeeks() {
$weeks = weeks::with('startDate')->get();
return view('weeks')->with('weeks', $weeks);
}
using in the view
#foreach ($weeks as $week )
{{ $week->startDate->date }} // produces an error like: Trying to get property 'date' of non-object
{{ $week->startDate }} // works but returns only the keys instead of the value of dates table.
#endforeach
How can I load the results of the dates table when calling the weeks?
EDIT: edited a typo in the title

How can I notify a specific group in Laravel

I have a problem, I want to notify specific users, like a group of users or admins for example. But I don't know how I can only notify admin or users in my code with Laravel.
Here is my AdsController.php in which I notify only admin:
$ads = new Ad;
$current_user=Auth::user();
$ads->object = $request->input('object');
$ads->description = $request->input('description');
$ads->save();
$users = User::where('id', '<>', $current_user->id)->where('admin', 1)->get();
foreach ($users as $user) {
$user->notify(new NewAd($current_user, $ads));
}
please someone help me
you can add 1 table calls "role", and on table users add 1 field calls role_id. and then you can make condition in your controller,
for example :
Role table
id | name
1 | Admin
2 | User
User table
id | name | role_id
1 | Jon | 1
2 | Doe |2
Data table
id | name |user_id
1 |Data1 | 1
2 |Data2 | 2
Controller
public function index() {
if(Auth::user()->role_id == 1 ){
$datas = Data::all();
return view('projects.index',['datas' => $datas]);
} else {
$datas = DB::table('datas')->where('user_id', Auth::user()->id )->get();
return view('projects.index',['datas' => $datas]);
}
Hope can help you

Laravel 5 - Eloquent relationship

I have three tables as below:
------------------------------
| users | projects | clients |
|--------|-----------|-------- |
| id | id | id |
| name | client_id | name |
| | user_id | |
| | name | |
------------------------------
So basically the relationship is like:
User hasMany Project
Project belongsTo Client
My question is:
How can I get all clients of a user using eloquent?
Seems like I cannot user hasManyThrough method as there are no project_id in clients table.
So what I wish to achieve is :
foreach($users as $user)
foreach($user->clients as $client) //HOW TO SET UP THIS RELATION?
foreach($client->projects($user)->get() as $project)
$users = User::with('projects')->get();
// organize cleints' project and add for each user
foreach ($users as $user) {
// order projects by client_id
$projects = Collect($user->projects->toArray());
$clients = $projects->groupBy('client_id');
// keep projects data in 'projects' index
$temp = array();
foreach($clients as $client => $projects){
$temp[$client] = array('projects' => $projects);
}
// add clinets data for each user
$user['clients'] = $temp;
}
// output
foreach($users as $user)
foreach($user->clients as $client)
foreach($client['projects'] as $project)
echo 'user-'.$project['user_id'].', clinet-'.$project['client_id'].', project-'.$project['name'].'<br>';
Above code generated this output for me:

Joining pivot table to access data

I am trying to access data from a database query which I think will need a join. I have users that can be apart of many groups. I am using a belongsToMany
relationship. My Models are like so
class User extends Model
{
protected $table = 'users';
protected $guarded = [];
public function group()
{
return $this->belongsToMany('App\Group', 'users_user_groups')->withPivot('user_id', 'group_id');
}
}
class Group extends Model
{
protected $table = 'user_groups';
protected $guarded = [];
use SoftDeletes;
public function user()
{
return $this->belongsToMany('App\User', 'users_user_groups')->withPivot('user_id', 'group_id');
}
}
When I run everything I need too, I might get data like the following.
users
+----+---------------+
| id | name |
+----+---------------+
| 1 | John Doe |
+----+---------------+
user_groups
+----+---------------+-----------------+
| id | name | description |
+----+---------------+-----------------+
| 1 | Group AA | Something |
+----+---------------+-----------------+
| 2 | Group BB | Something |
+----+---------------+-----------------+
users_user_groups
+----+---------------+-----------------+
| id | user_id | group_id |
+----+---------------+-----------------+
| 1 | 1 | 1 |
+----+---------------+-----------------+
| 2 | 1 | 2 |
+----+---------------+-----------------+
So I know user with the id 1 belongs to the user_groups with ids of 1 and 2. What I am trying to do is grab all the users within my database who
belong to a user_group with the name admin. So I am trying something like this
DB::table('users')->select('userName')
->join('user_groups', 'users_user_groups')
->where('name', '=', 'admin')->get();
This I know is all wrong, how can I get all users within a group when using belongsToMany and a pivot table?
Thanks
Eloquent uses relations, not the query builder.
You can achieve what you're aiming for by doing something like this:
$group = Group::where('name', 'admin')->first();
$users = $group->users; // Where users is the name of your relationship (At the moment you have user)
Under the hood that will do two SQL statements and map them together in eloquent objects, rather than a join. The statements will look something like this:
select * from user_groups where name = ? and deleted_at is not null limit 1
select * from users where id in (?, ?)
When you have an instance Group you execute the relationship by calling it as if it was a property. So after that $users will contain a collection of User instances, so you can just loop through them:
foreach ($users as $user) {
// Do something with $user
}

Resources