Laravel accessing one to one relationship from the views - laravel

The code below one runs and the other doesn't. The code runs inside a foreach loop.
Does anyone know why the first one doesn't run?
{{ Status::find($workorder->statuses_id)->name }} //this doesn't
{{ Status::find(1)->name }} //this works

Assuming you have your relationship defined like this...
class Workorder extends Eloquent {
public function status() {
return $this->hasOne('Status');
}
}
You would need to do:
{{ Status::find($workorder->status->id)->name }}
This works for me no issues.
Alternatively, if you want to use the syntax you originally provided you could define a method on the Workorder class like this:
public function getStatusesIdAttribute() {
return $this->hasOne('Status')->first()->id;
}
...but that is a little awkward and likely not the best approach.

Related

Switching from Limit() to First() in Laravel Model

I'm stuck on an issue where I'm trying to clean up code presented to me, and I feel like I must've just been at this too long and can't see this issue.
At the moment I have the following code in one of my models:
public function attachments(){
return $this->hasMany(volunteerAttachment::class, 'volunteerID','id');
}
public function photoID() {
$photoID= $this->attachments()->where('category','Drivers License')->orderBy('endDate','desc')->limit(1);
return $photoID;
}
What I would like to do is what I believed was relatively simple in replacing the limit(1) of the function photoIdentification with a simple first().
But when I try that and simply put {{$volunteer->photoID->id}} in my blade, it simply returns the error App\volunteer::photoID must return a relationship instance.
I do however know that there is a relationship because if I continue to use the limit(1) and put:
#foreach($volunteer->photoID as $id)
{{$id->id}}
#endforeach
It returns the relation and document correctly.
$volunteer is the variable for that particular model App\volunteer, and the following is how it is defined in the controller:
public function show(Volunteer $volunteer){
return view('volunteer.show', compact('volunteer'));
}
The function photoID() will still return a full volunteerAttachment object. If you want to get the id using the first() function you will have to select the id property on the object like so:
{{ $volunteer->photoID()->id }}
You could also create an accessor on the model that directly returns this property:
public function getPhotoidAttribute($value)
{
return $this->attachments()->where('category','Drivers License')->orderBy('endDate','desc')->first()->id;
}
Now in blade you can just use:
{{ $volunteer->photoid }}
When you call a function of a model as a variable Laravel assumes you try to return a related model. Try with an accessor instead:
public function getPhotoidAttribute($value) {
$photoID= $this->attachments()->where('category','Drivers License')->orderBy('endDate','desc')->first();
return $photoID->id;
}
and call it like this:
{{ $volunteer->photoid }}

Laravel 5.5 - Deep Relations calling by -->

I now spent hours googling and experimenting on trying to get an relation with two intermediate tables working.
My database looks like this:
(apt_id is apartment_id in real, was shorter to write)
I have every relation one away setup correctly with belongsTo and and hasMany:
EXAMPLE FROM House.php
public function user()
{
return $this->belongsTo('App\User');
}
public function apartments()
{
return $this->hasMany('App\Apartment');
}
Isn't there a way to access these relations like:
$house->apartments->tenants->entries
in Blade:
#foreach ( $house->apartments->tenants->entries as $entry )
, since I want to display all house entries on house.show (Blade View)
The only way it's working is by using a bunch of foreach inside each others... :/ and they define the order...
Using my wanted relation calling produces:
Property [tenants] does not exist on this collection instance.
displayed on the page.
Greetings,
Pat
I don't think you can achieve what you want using the code you posted, because when calling, for example, $house->apartments it returns a Collection object. So, it is not dealing with database anymore, that's why you would need to use a bunch of #foreachs.
I don't know if this is the best way to solve this, or if it will help you in your actual problem, but you could think this problem backwards and try something like this:
$entries = \App\Entry::whereHas('tenants', function($q) use ($house) {
$q->whereHas('apartments', function($q1) use ($house) {
$q1->where('apartments.house_id', $house->id);
});
})->get();
And in the view:
#foreach ($entries as $entry)
{{ $entry->tenant->apartment->house->name }}
#endforeach

Controller method not called in laravel 4

I'm trying to learn laravel 4. I created a form(using view) and returned it via a controller(testController) using index method. I had created this controller using artisan command.
i created another method (dologin) in the controller which would process the form. In the form url parameter i gave the address of dologin method.
This is the route:
Route::resource('test', 'testController');
This is the controller
<?php
class testController extends \BaseController {
public function index()
{
return View::make('test.index');
}
public function dologin(){
echo "working";
}
and this is the index view file
{{ Form::open(array('url'=>'test/loginform')) }}
{{ Form::text('username', null, array('placeholder'=>'Username')) }}<br/>
{{ Form::password('password', array('placeholder'=>'Password')) }}<br/>
{{ Form::submit('Login') }}
{{ Form::close() }}
After submitting form, it should echo "working" in the browser. But after submitting the form, page is blank. The url changes though from
/laravel/public/index.php/test/
to
/laravel/public/index.php/test/loginform
umefarooq's answer is correct, however hopefully this answer should give you a bit more insight into getting a head-start in your Laravel development as well as a consistent best-practice programming style.
Firstly, class names should really start with a capital letter. Try to keep methods / function names starting with a lower case letter, and class names starting with a capital.
Secondly, you don't need the \ in front of BaseController. You only need the backslash if you are name-spacing your controller. e.g. if your controller is in the folder Admin\TestController.php, and you put your TestController in the Admin namespace by typing <?php namespace Admin at the beginning of the file. This is when you should use \BaseController because you are telling your TestController to extend BaseController from the Global Namespace. Alternatively, before you declare your class, you can type use BaseController; and you don't need to put a \ in every time.
Specifically related to your question:
When you use resource routes in your routes file, you are telling Laravel that the controller can have any or all of the following methods: index, show, create, store, edit, update and destroy.
As such, Route::resource('test', 'TestController'); will point to TestController.php inside your controllers folder.
Your TestController should be structured as follows, most restful controllers will use the below as some kind of boilerplate:
<?php
class TestController extends BaseController
{
public function __construct()
{
}
// Typically used for listing all or filtered subset of items
public function index()
{
$tests = Test::all();
return View::make('test.index', compact('tests'));
}
// Typically shows a specific item detail
public function show($id)
{
$test = Test::find($id);
return View::make('test.show', compact('test'));
}
// Typically used to show the form which creates a new resource.
public function create()
{
return View::make('test.create');
}
// Handles the post request from the create form
public function store()
{
$test = new Test;
$test->attribute1 = Input::get('attribute1');
$test->attribute2 = Input::get('attribute2');
$test->attribute3 = Input::get('attribute3');
$test->attribute4 = Input::get('attribute4');
if ($test->save())
{
return Redirect::route('test.show', $test->id);
}
}
// Shows the edit form
public function edit($id)
{
$test = Test::find($id);
return View::make('test.edit', compact('test'));
}
// Handles storing the submitted PUT request from the edit form.
public function update($id)
{
$test = Test::find($id);
$test->attribute1 = Input::get('attribute1');
$test->attribute2 = Input::get('attribute2');
$test->attribute3 = Input::get('attribute3');
$test->attribute4 = Input::get('attribute4');
if ($test->save())
{
return Redirect::route('test.show', [$id]);
}
}
// Used to delete a resource.
public function destroy($id)
{
$test = Test::find($id);
$test->delete();
return Redirect::route('test.index');
}
}
Also, the beauty of using Resource Controllers is that you can take advantage of named routes.
in the terminal window, type in php artisan routes.
You should see 7 named routes.
test.index
test.destroy
test.show
test.edit
test.destroy
test.create
test.update
So within your form, instead of doing
{{ Form::open(array('url'=>'test/loginform')) }} you can point the url to a named route instead:
{{ Form::open(array('route' => array('test.store')) }}
That way if you ever change the url, or need to move around your site structure, this will be easy, because the forms post url will auto bind to the named route within the routes file. You wont need to update every single one of your views to ensure that the url's are pointing to the correct location.
Finally, as a starting point, I would recommend using JefreyWay/Laravel-4-Generators package. https://github.com/JeffreyWay/Laravel-4-Generators . Use them to create your resources, controllers, views etc. and see how the generators scaffold your models, views and, controllers for you.
Here is another resource to help you get started:
https://laracasts.com/lessons/understanding-rest
Route::resource('test', 'testController');
will work for RESTful method of controller, like index, edit, destroy, create and now you are using custom method of controller for this you need to create another route
Route::post("test/loginform",'testController#dologin');
hope this will work for you. read route documentation http://laravel.com/docs/routing
In addition to what umefarooq said, which is 100% accurate. You need to look into flash messages as well.
public function dologin(){
//do login verification stuff
If login validated
Return redirect::to(logged/page)->with('message', 'You're logged in');
If login failed
Return redirect::to('test')->with('message', 'You login credentials fail');
}
For further research:
http://laravel.com/docs/responses

How do I access a global model instance in laravel 4?

In Laravel 4, how do I create an instance of a model and make it globally available? Even in views. I'm looking to do something similar to the way you get the User instance using Auth::User->name (the syntax I mean, not storing in a session) but in this case it would be ModelName::DefaultEntity->attribute.
A little more detail...
I am writing an application that will house multiple websites - a bit like a CMS. So I have a Website model. Each Website model will have a URL attribute so that when a user visits the URL the application can retrieve the Website model from the database and brand the website appropriately e.g. Title, logo, theme, etc...
I would like the current Website model to be available everywhere without having to create a new instance of Website in every controller/method. So in my layouts and views I could just say something like:
{{ Website::Website()->name }}
or
{{ CurrentWebsite::name }}
I have achieved the first one by making a static method in the Website model:
public static function current()
{
return Website::find(1); // just to test it for now
}
But with that, it will have to do a database query every time I say:
{{ Website::current()->name }}
Plus it doesn't feel right.
Can anyone help?
Kind regards,
Robin
You probably are looking for 'a shared container bind'. See the docs here.
<?php
App::singleton('foo', function()
{
return Website::whereCode('whoop')->first();
});
App::make('foo'); // every where you need it
Create normal class. Like CurrentWebsite or Website or whatever.
class Website {
public function a() {
//your code
}
}
Create facade (WebsiteFacade.php)
use Illuminate\Support\Facades\Facade;
class WebsiteFacade extends Facade {
protected static function getFacadeAccessor() { return 'website'; }
}
Create Service Provider
use Illuminate\Support\ServiceProvider;
class WebsiteServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('website', function()
{
return new Website();
});
}
}
4.Go to your config/app.php and add folowing:
'providers' => array(
'WebsiteServiceProvider'
)
and
'aliases' => array(
'WebsiteFacade'
)
5.Refrech auto loader. And Now you can access Website class anywhere like this:
Website::a();
What you already have is good, but if you just want prevent that query from executing every time, you can cache it:
public static function current()
{
return Website::remember(10)->find(1); // just to test it for now
}
Adding a listener to your routes.php:
DB::listen(function($sql, $bindings, $time) { var_dump($sql); var_dump($bindings); });
And executing it:
{{ Website::current()->name }}
Will show the query in the first execution but not in the second, because it's cached.

doctrine2 - use custom query getter

I'm using Symfony2 and Doctrine2. How would I go about using a different query for a get method? (poorly worded, let me explain)
i.e. I have an application entity, this has a one to many relation with Version
so in my application entity I have:
/**
* Get versions
*
* #return Doctrine\Common\Collections\Collection
*/
public function getVersions()
{
return $this->versions;
}
This is all good, however, how can I implement a method, such as
getCurrentVersion, where I perform a simple query, such as:
SELECT v.* FROM version WHERE application_id = 1 AND current = 1
and so in a twig template, I can do:
{% for application in applications %}
Name : {{ application.name }}
Current Version: {{ application.getCurrentVersion }}
{% endfor %}
Any help is much appreciated.
p.s. if i'm going about this wrong, please enlighten me.
Thanks.
EDIT: http://www.doctrine-project.org/docs/orm/2.1/en/reference/limitations-and-known-issues.html#join-columns-with-non-primary-keys Seriously?!
EDIT, I really don't want to do this, it is unnecessary and resourcefully wasteful:
public function getCurrentVersion
{
foreach($this->versions as $version)
{
if($version->current)
{
return $version;
}
}
}
Take a look into https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/working-with-associations.html#filtering-collections
I believe that's what you've been looking for.
First, you shouldn't touch the database from your entity. It's considered bad practice to inject an entity manager into a managed entity, and it has no way of knowing about the data layer otherwise.
To do what you're asking, you can use a custom entity repository with a getCurrentVersion method that takes an id or instance of the entity and runs the query on it:
// class Foo\Bundle\Repository\BarRepository
public function getCurrentVersion(MyClass $class)
{
$dql = 'SELECT v FROM Namespace\Of\Version\Class v WHERE v.application_id=:id AND current=1';
$query = $this->_em->createQuery($dql);
$query->setParameter('id', $class->getId());
$version = $query->execute();
return $version;
}
Note that if you're only expecting one version, you can use $query->getSingleResult(); instead of $query->execute();
However, it sounds like you're trying to do versioning/history on some of your classes, in which case, you should check out the Gedmo DoctrineExtensions and associated Symfony2 bundle; specifically, have a look at the Loggable behavioral extension, which handles versioning of your entities transparently.

Resources