Trouble retrieving Laravel relation as object - php

Baffled by what should be a fairly straightforward issue.
I have two objects related to each other:
class Country extends Eloquent {
public function hotspot()
{
return $this->hasOne('Hotspot');
}
}
and
class Hotspot extends Eloquent {
public function country()
{
return $this->belongsTo('Country');
}
}
I want to retrieve my hotspots and the countries they belong to, so:
$hotspot_list = Hotspot::with('country')->get();
As a test, I just want to loop through the list and output the country codes:
foreach ($hotspot_list as $hotspot_item) {
$hotspot = $hotspot_item->country;
echo $hotspot->country_code;
}
Throws an error: "Trying to get property of non-object"
So obviously I also can't do echo $hotspot_item->country->country_code;
If I access $hotspot as an array, it works: echo $hotspot['country_code'];
Because of this, I can't access $hotspot as an object. Since $hotspot is actually a Country object, I'm wanting to check another relation I have with Country but I can't since it's giving me an array instead of the object.
So even though I shouldn't have to do it this way, I tried this:
$country_id = $hotspot['id'];
$country = Country::find($country_id);
echo $country->name;
Still no go, it's still returning as an array, so I can do echo $country['name'];
Suggestions?

Ensure all your hotspots have countries, or you can validate them as you loop...
foreach ($hotspot_list as $hotspot_item) {
$hotspot = $hotspot_item->country;
if(isset($hotspot->country_code)) {
echo $hotspot->country_code;
}
}
Or even better if you have Laravel 4.1, only get the countries that have hotspots with...
$hotspot_list = Hotspot::has('country')->get();

Related

Laravel get property of non object

When I try to determine if an object is empty it's telling me:
Trying to get property of non-object
I'm doing it like this:
$lastTicket = Auth::user()->ticket->last()->ticketid;
if($lastTicket->isEmpty())
{
$lastTicket = 0;
}
Obviously Auth::user()->ticket->last(); isn't a record yet. How should I do this? I'm working with Laravel.
You need to check that collection not empty before get the property:
if(Auth::user()->ticket->last()->isEmpty())
{
$lastTicket = 0;
}
else
{
$lastTicket = Auth::user()->ticket->last()->lastId;
}
In short way:
$lastTicket = !Auth::user()->ticket->last()->isEmpty() ? $lastTicket = Auth::user()->ticket->last()->lastId : 0;
First of all have a look here if can be a solution at your problem. And anyway if you're trying to load a relation you should look at the official documentation:
Dynamic Properties
Eloquent allows you to access your relations via dynamic properties. Eloquent will automatically load the relationship for you, and is even smart enough to know whether to call the get (for one-to-many relationships) or first (for one-to-one relationships) method. It will then be accessible via a dynamic property by the same name as the relation. For example, with the following model $phone:
class Phone extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
$phone = Phone::find(1);
Instead of echoing the user's email like this:
echo $phone->user()->first()->email;
It may be shortened to simply:
echo $phone->user->email;
The right answer was:
$lastTicket = !Auth::user()->ticket->last() ? Auth::user()->ticket->last()->ticketid+1 : 0;
because if it's empty it will return 0 as default.

Getting data from database to model

So far I've used many objects in my applications but often if I had to for example display for example users' profiles on page I simply got 20 users from database as array using some method in my object and assigned it to view.
Now I want to create application more with models that represent real data. So for each user I should probably have User object with properties .
Here I put sample code to get users from database and to display them in PHP:
<?php
$db = new mysqli('localhost', 'root', '', 'mytest');
class User
{
private $id;
private $name;
public function __construct($data)
{
foreach ($data as $k => $v) {
if (property_exists($this, $k)) {
$this->$k = $v;
}
}
}
public function show()
{
return $this->id . ' ' . $this->name ;
}
}
$result = $db->query("SELECT * FROM `user` LIMIT 20");
$users = array();
while ($data = $result->fetch_object()) {
$data->x = 10; // just to test if property isn't created
$users[] = new User($data);
}
// displaying it on page
foreach ($users as $user) {
echo $user->show() . "<br />";
}
Questions:
Is it the way I should use data from database into model? I mean if should I create object for each record even if the only role of this object would be returning some data to view (for example even not modified by any functions as in this example). Of course I know that often data should be prepared to display or made some calculations or additional data should be retrieved from database before those data could be used to display.
Is there any way to assign object properties from database simpler than using constructor with loop?
First of all, i'd move the DB operations in a separate class, not inline with the User class. You could create an abstract Model class, which the User class would extend and add DB logic to it.
You'd have a select() method to query the database, which would return an array of objects of the class that extended the Model class (the User class in this case).
To answer your questions:
I think it's ok. Most ORMs work this way.
An alternative would be to assign the user row data from the DB to a $data attribute in your User class and use the magic methods __get and __set to access them.

Working with empty Doctrine 2 Association Objects

When creating an association using Doctrine 2 and the Zend Framework, if the associated object is empty e.g. for entity->associated_entity->item if associated_entity is empty, i.e. there is not an associated entity to the original entity, then I get an error Trying to get property of non-object.
I know this is because I am trying to get the item from an empty entity.
What is the standard way to avoid this error?
I am using the code below to get the data, but because the initial associated entity will be returned as '', then it can't then get the item from ''
public function __get($name)
{
if (isset($this->$name)){
return $this->$name;
} else {
return '';
}
}
you could try:
$associatedEntity = $entity->associated_entity;
if ($associatedEntity) {
$item = $associatedEntity->item;
}
Edit:
OK then. Try putting this in your template/view:
<?php
$department = $instruction->department;
if ($department) {
echo $department->department;
}
?>
Edit 2 (after a small discussion in the chat :D):
I think that there is no way to tell to PHP to stop the chain. E.g.
$object1->object2->attribute
If you write it this way, no matter what you put in the __get(), PHP will assume that object2 is an object and will try to fetch the requested attribute.
The easiest solution would be something like that:
<?php foreach ($this->data as $instruction) : ?>
<?php if ($dep = $instruction->department) echo $dep->department ?>
<?php endforeach ?>

idiorm / paris has_many as_array result set

I'm having trouble getting the results of a has_many query using php idiorm/paris. Following the example from the paris site the has_many result for posts returns as an object.
That's great, and I can run through the object and access individual methods, but what I want to be able to do is pass the result set as an associative array off to my template engine for display.
Example:
class Post extends Model {
}
class User extends Model {
public function posts() {
return $this->has_many('Post'); // Note we use the model name literally - not a pluralised version
}
}
The api works this way:
// Select a particular user from the database
$user = Model::factory('User')->find_one($user_id);
// Find the posts associated with the user
$posts = $user->posts()->find_many();
I am able to access the posts object and print the result set like this:
// echo each post id
foreach ($posts as $post) {
echo $post->id;
}
What I'd really like to be to do though, is use as_array() to get the entire resultset as an associative array, limited by certain fields in the way as_array works for an individual row, e.g.
$post_list = $posts()->as_array(id,title,post,date);
This, or a call on something like $user->posts()->find_many()->as_array() don't work.
What is the correct way to access this type of result set using paris?
Adding this method to idiorm.php gives me the desired functionality.
public function find_array() {
if (func_num_args() === 0) {
return $this->_run();
}
$args = func_get_args();
$array = array();
foreach ($this->_run() as $r) {
$array[] = array_intersect_key($r, array_flip($args));
}
return $array;
}
Now I can call $post_list = $posts()->find_array(); or $posts()->find_array('id','title'); etc.
find_one returns a Model object, find_many returns an array of Models.
If you want to get the entire result set as an array of associative array, one solution should be to use array_map
function model_as_array($model) {
return $model->as_array();
}
$posts = $user->posts()->find_many();
$my_view->posts = array_map(model_as_array, $posts);
var_dump($my_view->posts);
or in php 5.3+ (not tested)
$aa_posts = array_map(function($model) {return $model->as_array();} , $posts);

Can't access array members

I can't figure this out. I've create a simple class that returns an array of arrays. Here is the class contructor...
class BlogComments {
public $commentArray=array();
public $blogId;
function __construct($inId) {
if(!empty($inId)) {
$this->blogId=$inId;
$sql="select id,name,url,comment,email from blog_comment where blog_id=$inId";
$link2=GetConnection();
$query=mysql_query($sql,$link2) or die("Invalid blog id:".mysql_error());
while($row=mysql_fetch_array($query)) {
$this->commentArray=array(
"id"=>$row['id'],
"name"=>$row['name'],
"url"=>$row['url'],
"email"=>$row['email'],
"comment"=>$row['comment']
);
}
mysql_close($link2);
}
}
}
I'm trying to access each member of the array via a loop. It's entering the loop but the values returned are empty. I've verified that data is being written into the array. Here's my code...
include "include/commentclass.php";
$comments = new BlogComments($post->id);
foreach($comments as $comment) {
echo "<h4>".$comment->commentArray['name']."</h4>
".$comment->commentArray['url']."
<p>".$comment->commentArray['comment']."</p>";
}
Basically it returns empty tags. I've also verified that $post->id holds a valid value. Any ideas what I'm doing wrong?
Thanks for the help,
B
You are doing some mistakes, the first is the one netcoder pointed out: you are using the object as an array without implementing an Iterator interface. The second is that you are assigning directly the result array to $this->commentArray. You should append the result to the array this way: $this->commentArray[] = array(
Try this:
$comments = new BlogComments($post->id);
foreach ($comments->commentArray as $comment) {
echo "<h4>".$comment['name']."</h4>
".$comment['url']."
<p>".$comment['comment']."</p>";
}
The new keyword returns a single object. Unless your object (BlogComments) implements Traversable, foreach will act on the public properties commentArray and blogId, and not on the commentArray contents.
You could also have your class implement an Iterator interface.

Categories