Laravel - multiple controllers in single view - php

I'm trying to code a simple event page. This page should display a particular event and it's features (including other info not relevant for the problem).
I've tried a couple different approaches with no luck, this is the approach I feel like I might be closet to success with, any suggestions?
I can provide other extracts of code if you think the problem lies elsewhere but I think my problem lies within these 7 files.
The current error I have is "Property [features] does not exist on this collection instance." and point to the EventController show() function.. if anyone could help I'd greatly appreciate it.
web.php
Route::get('cards/{id}', 'CardController#show');
Route::get('event/{id}', 'EventController#show');
event.blade.php
<h1 class="big-title">
</h1>
<section id="events">
#each('partials.event', $event, 'event')
</section>
(partials) event.blade.php
<header>
<h2 class="event-name fsb">
{{ $event->name }}
</h2>
</header>
<p class="event-description pdl1em">
{{ $event->description }}
</p>
<ul class="event-dates pdl1em">
<ul>
#each('partials.features', $event_features, 'feature')
</ul>
</ul>
Event.php
class Event extends Authenticatable
{
public function features() {
return $this->hasMany('App\Models\EventFeature');
}
}
EventFeature.php
class EventFeature extends Authenticatable
{
public function event() {
return $this->belongsTo('App\Models\Event');
}
}
EventController
class EventController extends Controller
{
public function show($id)
{
$event = DB::table('event')->where('id', $id)->get();
return view('pages.event', ['event' => $event, 'features' => $event->features]);
}
}
EventFeatureController
class EventFeatureController extends Controller
{
public function show($id)
{
$event_features = DB::table('event_features')->where('id', $id)->get();
return view('pages.event', ['event' => $event_features->eventClass, 'features' => $event_features]);
}
public function list($event_id)
{
if (!Auth::check()) return redirect('/login');
$event_features = DB::table('event_features')->where('event_id', $event_id)->orderBy('id')->get();
return view('pages.event', ['event_features' => $event_features]);
}
}

When you want to retrieve a single item, use find($id) or first() to retrieve an instance of the model. When you call get() you get a collection of an array with the instances inside it.
When using DB::table('events') you dont get as a result an instance of the model, you get a generic object instance => you can't use Model class defined methods like relations and such. use the model directly instead Event::where(...
Change your method to
class EventController extends Controller
{
public function show($id)
{
$event = Event::findOrFail($id);
return view('pages.event', ['event' => $event, 'features' => $event->features]);
}
}

Related

Cant get Property from the model realtion Laravel

I got an issue when i use fooreach loop with 3 model realtion in 1 view
This is my Thread model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Thread extends Model
{
protected $primaryKey = "id_threads";
public function user(){
return $this->belongsTo('App\User','id_users');
}
protected $fillable = [
'id_users', 'threads',
];
public function comment(){
return $this->hasMany('App\Comment','id_threads');
}
}
This is my Comment model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $primaryKey = 'id_comments';
public function thread(){
return $this->belongsTo('App\Thread','id_threads');
}
public function users(){
return $this->belongsTo('App\User');
}
protected $fillable = [
'id_threads', 'id_users', 'comments','status'
];
}
This is my index controller
public function index()
{
$user = Auth::user();
$comment = Comment::all();
//Threads
$threads = Thread::orderBy('created_at','desc')
->get();
$hitung = $threads->where('id_users', '=',$user->id);
return view('/home',compact('threads','hitung','comment'));
}
And this is piece of my view
#foreach ($threads as $thread)
<div class="media-body">
<h5 class="mb-0">{{$thread->user->name}}</h5>
<div class="card-date mb-2">
{{date('F d, Y', strtotime($thread->created_at))}} at {{date('g : ia', strtotime($thread->created_at))}}
</div>
<input type="hidden" name="$id_threads" value="{{$thread->id_threads}}">
{{$thread->threads}}
<div class="card-delete mt-5">
#if (Auth::user()->id==$thread->id_users)
Delete
#else
#endif
</div>
<hr>
<div class="media comment mt-3">
<a class="mr-3" href="#">
{{$thread->comment->comments}}
The Error comes when i want to show comment
{{$thread->comment->comments}}
And an error like this appears
Property [comments] does not exist on this collection instance. (View: D:\Jendro\Project Laravel\projectCO\resources\views\home.blade.php)
But when i just call the object only, like this
{{$thread->comment}}
Thats no error appears, in my view a data set appears from the Comment model
[{"id_comments":6,"id_threads":54,"id_users":2,"comments":"asdqweasd","created_at":"2020-06-29 08:58:53","updated_at":"2020-06-29 08:58:53","status":"comment"}]
It was same when i use to call user object, but threse no problem with user object when i call property of user's object
I was stuck in this issue, does anyone have solution for this issue ?
You will not be able to access this way, as this is a hassle. There is not one record, but an array of records. You need to twist $ thread->comments and get comments from it.
But if $ thread->comment should always be a single entry, then use hasOne in Thread class instead of hasMany

how to show data from two related tables, with Laravel

I have two tables one called "Events" and another one "Dependences", a dependency can have several events, that is the relation between them, what I try to do is show the data of an event, but also show the data of the dependency to which is related.
This is my controller where I bring the event:
class WelcomeController extends Controller
{
public function evento($slug){
$event = Event::where('slug', $slug)->first();
return view('evento', compact('event'));
}
This is the event model:
class Event extends Model
{
protected $table = 'events';
protected $fillable = [
'admin_id', 'dependence_id', 'place_id', 'name', 'slug', 'excerpt', 'body', 'status', 'file'
];
public function dependences(){
return $this->belongsTo('App\Dependence', 'dependence_id');
}
dependence model:
class Dependence extends Model
{
protected $table = "dependences";
protected $fillable = [
'name', 'slug'
];
public function events(){
return $this->hasMany('App\Event');
}
so I try to show it in the view:
#foreach($event->dependences as $dependence)
<a href="#">
{{$dependence->name}}
</a>
#endforeach
but I get this error: Trying to get property 'name' of non-object
these are the tables in the database:
enter image description here
the routes are fine, but I do not know what the problem is, I hope for your help, thank you very much.
There is only one dependency for every event. So you no need to use foreach.
$events->dependency->name
And you should change the relationship name from dependences to dependency.
class Event extends Model
{
public function dependency()
{
return $this->belongsTo('App\Dependence', 'dependence_id');
}
}
In view:
#foreach($events as $event)
{{ $event->dependency->name }}
#endforeach
You should access directly, as:
$event->dependence->name;
Since, belongsTo relationship brings one item.
Also add a check to see if the object is null, as in:
#if($event->dependece)
$event->dependence->name;
#endif
You could also use an #else in case you want to manage the null case somehow

calling function from controller in view laravel

this is a simple thing actually but since im new in laravel it trouble me, i have this function
class HomeController extends Controller {
public $layout = 'layouts.master';
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('landing-page')
->with('title','Landing Page')
->with('users',User::member()->get());
}
<!-- HOW TO CALL getDate Function in my view -->
public function getDate(){
$mytime = Carbon::now()->format('f');
$response = array
(
'content' =>$mytime,
'status' =>'success',
);
return Response::json($response)->view('landing-page');
}
}
how to call it in my laravel view? i search all over the internet but i not quite understand since programming is new for me i already tried something like this in my view using routes {{url('date')}}, {{$mytime}}, but none working, well i can call a function if there's certain event happen like clicking button or else but if no certain event it's quite confusing me
<p>Month :{{url('date')}}</p>
<p>Month :{{$mytime()}}</P>
above are some ways i tried to call the function
UPDATE WHAT I'VE TRIED BASED on #tptcat answer and work
create helpers.phplocated under files `app\helpers.php
<?php
use Carbon\Carbon;
if (! function_exists('myGetDate')) {
function myGetDate()
{
$mytime = Carbon::now()->format('F');
return $mytime
}
}
composer.json
"autoload": {
"files":[
"App/helpers.php"
],
calling function in my view
{{myGetDate()}}
This isn't a hard and fast rule, but part of using a framework is to somewhat buy into its conventions and use them to your advantages.
Generally speaking, your Controllers are for working with HTTP (GET, POST, PUT, etc.). They're not designed to be indiscriminate ways to call methods from your Views.
I would recommend doing something like this instead:
// app/Utilities.php
<?php
class Utilities
{
public static function getDate()
{
// your code
}
}
then in your view:
{{ Utilities::getDate() }}
or:
// app/helpers.php
<?php
if (! function_exists('myGetDate')) {
function myGetDate()
{
// your code
}
}
then in your view:
{{ myGetDate() }}
and then in composer.json autoload whichever file you create:
"autoload": {
"files": [
"app/Utilities.php"
]
}
or...
"autoload": {
"files": [
"app/helpers.php"
]
}
and then run composer dump-autoload.
Another way to approach this could be using Blade Service Injection (introduced in Laravel 5.1). This technically can be done with your controller:
// In your blade template
#inject('service', 'App\Http\Controllers\HomeController')
{{ $service->getDate() }}
But I'd still recommend not having a method in your controller in charge of returning this data if it's going to be called as a method from a Blade template. Using some type of service class would be more appropriate:
// app/Utilities.php
<?php
namespace App;
class Utilities
{
public function getDate()
{
// your code
}
}
// In your blade template
#inject('service', 'App\Utilities')
{{ $service->getDate() }}
and in this case you wouldn't need to add it to the files autoload array in composer.json.
For what it's worth, not knowing anything else about your project, I would choose one of the first two options, and more likely the helpers.php option.
Try this:
class HomeController extends Controller {
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$title = 'Landing Page';
$users = \User::member() - > get();
$mytime = \Carbon::now()->format('f');
return view('layouts.master.landing-page', [
'title' => $title,
'users' => $users,
'mytime' => $mytime
]
);
}
}
And to display it within the landing-page view you would access them with:
{{ $title }}
{{ $users }}
{{ $mytime }}

Laravel 5.2 'Master Layout' Variable passing

So here is what I'm trying to achieve. I have a default blade template default.blade.php which is extended by all of my child views.
Within my default.blade.php i have a foreach loop which expresses some 'global' options to the user, and example of which is below.
#foreach ($projects as $p)
<li><a href='$p->project_uid'>{{ $p->project_name }}</a></li>
#endforeach
So to achieve this I'm having to pass the $projects variable via the view('viewname', $data) or via View::share('projects', $projects); in my Controller __construct()
Is there a better way for me to do this on a global sense so that the above calls don't need to be made?
One option i am aware of is calling a Model function from within my view, but this defies the concept of MVC so is not ideal.
Any guidance on the subject would be appreciated, Thanks.
Edit 1
So i tried the ViewComposer solution but ran into a couple of problems.
Below is my Composer & the Service Provider Register.
Config/app.php
App\Providers\ComposerServiceProvider::class,
ComposerServiceProvider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider {
/**
* Register bindings in the container.
*
* #return void
*/
public function boot() {
// Using class based composers...
view ()->composer ( 'default', 'App\Http\ViewComposers\MasterComposer' );
}
/**
* Register the service provider.
*
* #return void
*/
public function register() {
//
}
}
MasterComposer
<?php
namespace App\Http\ViewComposers;
use Illuminate\View\View;
use App\Repositories\UserRepository;
use Sentinel;
use ProjectUsers;
class MasterComposer
{
protected $users;
public function __construct(ProjectUsers $users)
{
$uid = Sentinel::getUser()->id;
$this->users = ProjectUsers::where("user_id", '=', $uid)->get();
}
public function compose(View $view)
{
$view->with('projects', $this->users);
}
}
Am i missing something obvious as it doesn't seem like the Composer is being loaded at all.
Edit 2
Fixed it myself. Realised that within the ComposerServiceProvider i need to specify a full path to my view like so.
view ()->composer ( 'admin/layouts/default', 'App\Http\ViewComposers\MasterComposer' );
Now it Works :D
Yes, you do this with View Composer.
View composers are callbacks or class methods that are called when a
view is rendered. If you have data that you want to be bound to a view
each time that view is rendered, a view composer can help you organize
that logic into a single location.
Bind that data to defualt.blade.php view, like:
public function compose(View $view)
{
$data = .... // Get data here.
$view->with('projects', $data);
}

How can I compact this code for sending info to the view from the Laravel Controller?

Here's my edit function in the controller
public function edit($id)
{
$game = Game::find($id);
// build list of team names and ids
$allTeams = Team::all();
$team = [];
foreach ($allTeams as $t)
$team[$t->id] = $t->name();
// build a list of competitions
$allCompetitions = Competition::all();
$competition = [];
foreach ($allCompetitions as $c)
$competition[$c->id] = $c->fullname();
return View::make('games.edit', compact('game', 'team', 'competition'));
}
I am sending data in order to display in a select list. I know about Eloquent ORM method Lists, but the problem is as far as I know it can only take property names as an argument, and not methods (like name() and fullname()).
How can I optimize this, can I still use Eloquent?
I would look into attributes and appends. You can do what you would like by adjusting your models.
Competition
<?php namespace App;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
class Competition extends Model
{
protected $appends = ['fullname'];
...
public function getFullnameAttribute()
{
return $this->name.' '.$this->venue;
}
}
Team
<?php namespace App;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
protected $appends = ['name'];
...
public function getNameAttribute()
{
return $this->city.' '.$this->teamName;
}
}
Controller
public function edit($id)
{
$game = Game::find($id);
$team = Team::get()->lists('id','name');
$competition = Competition::get()->lists('id','fullname');
return View::make('games.edit', compact('game', 'team', 'competition'));
}
The only thing I can think of (aside from using the map functionality of Eloquent collections) is to overwrite the toArray method in your model to add some custom attributes.
Eg.
public function toArray()
{
return array_merge(parent::toArray(), [
'fullname' => $this->fullname(),
]);
}
This will allow you to use something like:
$competition = $allCompetitions->fetch('fullname');
Although:
In saying all this I think the more elegant solution is to just provide the whole competition objects to the view and let the loop where you render them (or whatever) call the method itself.
You can call model method in view file if they are not related with other models. So if name() & fullname() returns result related to this model then you can use this model methods in view
#foreach (($allTeams as $t)
{{ $t->name() }}
#endforeach
ofcourse you have to pass the $allteams collection from controller to view

Categories