How to Get Data When Using first() Equivalent in Laravel Model? - php

I use Laravel version 5.7 and want to get data from the database. I tried using $genre->name but it didn't work, and also I tried $genre->toArray() but got another error.
Controller
<?php
namespace App\Http\Controllers;
use App\genre;
class Mins extends Controller
{
public function genget($data)
{
foreach ($data as $key => $value) {
$genre = genre::where('name', $value)->first();
echo $genre->name;
}
}
}
Here's the data in $data when I var_dump.
array(4) { [0]=> string(6) "Comedy" [1]=> string(3)
"Action" [2]=> string(8) "Bad" [3]=> string(7) "Good" }
I'm getting the following error (echo in the controller):
"Trying to get property 'name' of non-object"
However, when I try to do dd($genre->name) in the controller I did get the data.
Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class genre extends Model
{
protected $fillable = ['name', 'slug'];
}
I'm also trying:
$genre = genre::where('name', $value)->first()->toArray();
dd($genre);
Response:
array:6 [▼
"id" => 1
"name" => "Comedy"
"slug" => "comedy"
"created_at" => "2019-01-11 15:02:31"
"updated_at" => "2019-01-11 15:02:31"
"deleted_at" => null
]
But when I call specified value like echo $g['name']; I get the error:
"Call to a member function toArray() on null"
I try to change the $value using a string like:
$genre = genre::where('name', 'Comedy')->first();
This works perfectly, does anyone know what the problem is?

Check for empty result :
foreach ($data as $key => $value)
{
$genre = genre::where('name', $value)->first();
if ($genre)
{
echo $genre->name;
}
}

Firstly, with the code in your example, I would suggest checking to see if the model actually exists before doing anything with it, this way you're not going to have an error thrown when it doesn't exist. When using first() it is either going to return the Eloquent model or null so an easy check would be something like:
$genre = genre::where('name', $value)->first();
if ($genre) {
echo $genre->name;
}
That being said, performing a query inside a loop is pretty inefficient and considered bad practice. In this case you'd be better of using whereIn() and then looping through the results:
public function genget($data)
{
$genres = genre::whereIn('name', $data)->get();
foreach ($genres as $genre) {
echo $genre->name;
}
}
This way you're only ever performing one query (instead of 4 like in your example) and you won't have to worry about them existing when you loop through them.
NB
This isn't essential but I would strongly recommend following the PSR's, specifically in this case PSR-1 - Namespace and Class Names so you're genre class should be Genre e.g.
class declaration: class Genre (not class genre)
class file name: Genre.php (not genre.php)
class usage: Genre::someMethod() (genre::someMethod())

Related

Why would PHP json_encode not returning the correct value from passed in array?

all. I am working on a custom-build API built in PHP. I have an array (see below) that has been returned from my database access object. When I use the json_encode function, the int value assigned to phone1Type gets encoded incorrectly. I have tried this with multiple records, and the value in the encoded json object always matches the phone2Type. Any ideas as to what might be going on? (I've included two sample arrays below in addition to their corresponding json object.)
The code that I'm using to check the array and json values is the following:
$responseObject = $userCtrl->selectPersonForUserId($userId);
var_dump($responseObject);
var_dump(json_encode($responseObject));
One example array to encode is as follows. (The phone1Type and phone2Type keys are at the very end, but include the full array here for completeness. Also, as a side note, the other int values in the array are encoding fine.)
object(Adult)#13 (8) {
["person":protected]=>
object(Person)#14 (4) {
["id":protected]=>
int(3)
["firstName":protected]=>
string(7) "William"
["lastName":protected]=>
string(3) "Smith"
["hasVerified":protected]=>
bool(false)
}
["address":protected]=>
object(Address)#17 (4) {
["id":protected]=>
int(2)
["address1":protected]=>
string(15) "520 Hilbert Dr."
["address2":protected]=>
string(0) ""
["city":protected]=>
object(City)#18 (3) {
["zip":protected]=>
string(5) "71342"
["city":protected]=>
string(11) "West Monroe"
["state":protected]=>
string(2) "AL"
}
}
["email":protected]=>
string(14) "wmrmay#spam.com"
["phone1":protected]=>
string(10) "6195080000"
["phone1Type":protected]=>
int(1)
["phone2":protected]=>
string(10) "3188126574"
["phone2Type":protected]=>
int(0)
["teacher":protected]=>
NULL
}
This encodes to the following json object:
{"person":{"id":3,"firstName":"William","lastName":"Smith","hasVerified":false},"address":{"id":2,"address1":"520 Hilbert Dr.","address2":"","city":{"zip":"71342","city":"West Monroe","state":"AL"}},"email":"wmrmay#spam.com","phone1":"6195080000","phone1Type":0,"phone2":"3188126574","phone2Type":0,"teacher":null}
For brevity, here's the last few lines of another array followed by its json counterpart:
["email":protected]=>
string(20) "wltrallen2#gmail.com"
["phone1":protected]=>
string(10) "6192047586"
["phone1Type":protected]=>
int(1)
["phone2":protected]=>
NULL
["phone2Type":protected]=>
NULL
["teacher":protected]=>
NULL
"email":"wltrallen2#gmail.com","phone1":"6192047586","phone1Type":null,"phone2":null,"phone2Type":null,"teacher":null}
Edited to add original Adult.php model class:
class Adult implements JsonSerializable {
protected $person; // Person object
protected $address; // Address object
protected $email;
protected $phone1;
protected $phone1Type; // PhoneType object
protected $phone2;
protected $phone2Type; // PhoneType object
protected $teacher; // Teacher object
public function __construct($person, $address, $email, $phone1, $phone1Type, $phone2, $phone2Type, $teacher)
{
$this->person = $person;
$this->address = $address;
$this->email = $email;
$this->phone1 = $phone1;
$this->phone1Type = $phone1Type;
$this->phone2 = $phone2;
$this->phone2Type = $phone2Type;
$this->teacher = $teacher;
}
... // Getters and Setters removed for brevity
private function getPhoneType($type) {
if(PhoneTypes::isValid($type)) {
return PhoneTypes::StringDict[$type];
}
return '';
}
function jsonSerialize() {
$array = [
'person' => $this->person,
'address' => $this->address,
'email' => $this->email,
'phone1' => $this->phone1,
'phone1Type' => $this->phone2Type,
'phone2' => $this->phone2,
'phone2Type' => $this->phone2Type,
'teacher' => $this->teacher
];
return $array;
}
}
So, embarrassingly, this was just caused by an initial typo and then forgetfulness on my part.
In the Adult.php model class, I has implemented the JsonSerializable interface to make sure that an Adult object could be encoded in Json. When doing so, I made a typographical error when building the array:
'phone1Type' => $this->phone2Type,
which should have been, of course...
'phone1Type' => $this->phone1Type,
This typo was the source of my issue. Ugh!
However, as I've been deeply mired in this project and it had been some time since I originally built those model classes, I had completely forgot that for an object to be encodable by JSON that it had to implement the JsonSerializable interface. So, as I was debugging, it never occurred to me to look back in my model at the very end of the file to examine the jsonSerialize() function. (Insert face palm here.)
Thank you for your responses. This is the first time that I've actually gotten to post a question on stackOverflow, and I appreciate you all taking a look. Sorry that it wasn't an exciting question and merely a silly novice programmer moment.

Codeigniter 4 Entity Property cast as array not autoserializing

I'm trying to cast an entity property into an array so that it autoserializes.
The Entity is set up as follows
\App\Entities\Submission.php
<?php
namespace App\Entities;
use CodeIgniter\Entity;
class Submission extends Entity
{
protected $casts =[
'field2' => 'array'
];
}
Then in a controller I create a new entity, filling it using the constructor
<?php
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
?>
Dumping the submission at this point (var_dump()) shows field2 being an array, it's not serialised.
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
array(2) {
[0]=>
int(0)
[1]=>
int(1)
}
}
if I do
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
$submission->field2 = $submission->field2;
and then var_dump, field2 is correctly serialised.
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
string(22) "a:2:{i:0;i:0;i:1;i:1;}"
}
For some reason, it seems like filling using the constructor does not autoserialize, I have to manually set the field. Am I doing something wrong?
The problem this caused is that when I tried inserting that entity into the Database, it threw an error saying
"mysqli_sql_exception Operand should contain 1 column(s)"
which went away when I flattened the array (first by dropping all but one values to test and then by using what I've done above)
================
EDIT 11/05: This turned out to be an issue on the core code. fill() (and the constructor) were not configured to use __set() so autoserialization was not happening. See the PR on Codeigniter's Github page here.
I'll be accepting Kulshreshth K's answer because, for now, this provides an adequate workaround but in the future it will most likely not be needed.
Add this in your Entity:
public function __construct($arr) {
$this->field2 = $arr['field2'];
}
Controller:
$allowedFromPost = [
'field1'=>'value1',
'field2'=>[0,1],
];
$submission = new \App\Entities\Submission($allowedFromPost);
var_dump($submission)
Result:
["attributes":protected]=>
array(2) {
["field1"]=>
string(6) "value1"
["field2"]=>
string(22) "a:2:{i:0;i:0;i:1;i:1;}"
}
As per CI documentation you need to set it after initialize its model anyway:
<?php namespace App\Entities;
use CodeIgniter\Entity;
class User extends Entity
{
protected $casts => [
'options' => 'array',
'options_object' => 'json',
'options_array' => 'json-array'
];
}
$user = $userModel->find(15);
$options = $user->options;
$options['foo'] = 'bar';
$user->options = $options;
$userModel->save($user);

Array and object issue in symfony

I'm sending an object via my Action in Symfony, but I cannot retrieve it in my view.
This is the Action code:
public function testphpAction()
{
/*SOME DOCTRINE CODE*/
$productos = $consulta->getResult();
return $this->render('TPMainBundle:Default:test.html.php', array(
'productos' => $productos,
));
}
I tried the solutions from this thread but with no effort: PHP Error: Cannot use object of type stdClass as array (array and object issues)
This is the code of my view 'test.html.php':
foreach($productos as $producto) {
echo $producto['descripcion'];
}
// This displays the error: "Cannot use object of type TP\MainBundle\Entity\Works as array
So I tried the solution from the other thread:
foreach ($productos as $producto) {
$id = $producto->id;
echo $id;
//But it throws the error: Cannot access private property TP\MainBundle\Entity\Works::$id
Neither this worked:
$id = $productos->id;
// Throw: "Trying to get property of non-object"
How can I access it? I don't have this problem if I render to a twig template, but I need to use php.
The var_dump of $productos is this: (I ommited the other objects in this chain)
array(3) { [0]=> object(TP\MainBundle\Entity\Works)#290 (4) { ["id":"TP\MainBundle\Entity\Works":private]=> int(1) ["descripcion":"TP\MainBundle\Entity\Works":private]=> string(30) "Landing page for a toys store." ["img":"TP\MainBundle\Entity\Works":private]=> string(12) "images/1.jpg" ["preview":"TP\MainBundle\Entity\Works":private]=> string(13) "images/1m.jpg" }
Define your getters, and then use them.
for example in this
foreach ($productos as $producto)
{ $id = $producto->id; echo $id; }
Try
$producto->getId();
instead of
$producto->id;
assuming you defined your getter.
$id = $producto->id;
This won't work because whether the property is not publicly accessible or the Object does not have that property.
The Work object has description, but it's private, so you'd have to create a getter function to echo it.
e.g
echo $producto->getDescription();

Convert Entity to array in Symfony

I'm trying to get a multi-dimensional array from an Entity.
Symfony Serializer can already convert to XML, JSON, YAML etc. but not to an array.
I need to convert because I want have a clean var_dump. I now have entity with few connections and is totally unreadable.
How can I achieve this?
You can actually convert doctrine entities into an array using the built in serializer. I actually just wrote a blog post about this today:
https://skylar.tech/detect-doctrine-entity-changes-without/
You basically call the normalize function and it will give you what you want:
$entityAsArray = $this->serializer->normalize($entity, null);
I recommend checking my post for more information about some of the quirks but this should do exactly what you want without any additional dependencies or dealing with private/protected fields.
Apparently, it is possible to cast objects to arrays like following:
<?php
class Foo
{
public $bar = 'barValue';
}
$foo = new Foo();
$arrayFoo = (array) $foo;
var_dump($arrayFoo);
This will produce something like:
array(1) {
["bar"]=> string(8) "barValue"
}
If you have got private and protected attributes see this link : https://ocramius.github.io/blog/fast-php-object-to-array-conversion/
Get entity in array format from repository query
In your EntityRepository you can select your entity and specify you want an array with getArrayResult() method.
For more informations see Doctrine query result formats documentation.
public function findByIdThenReturnArray($id){
$query = $this->getEntityManager()
->createQuery("SELECT e FROM YourOwnBundle:Entity e WHERE e.id = :id")
->setParameter('id', $id);
return $query->getArrayResult();
}
If all that doesn't fit you should go see the PHP documentation about ArrayAccess interface.
It retrieves the attributes this way : echo $entity['Attribute'];
PHP 8 allows us to cast object to array:
$var = (array)$someObj;
It is important for object to have only public properties otherwise you will get weird array keys:
<?php
class bag {
function __construct(
public ?bag $par0 = null,
public string $par1 = '',
protected string $par2 = '',
private string $par3 = '')
{
}
}
// Create myBag object
$myBag = new bag(new bag(), "Mobile", "Charger", "Cable");
echo "Before conversion : \n";
var_dump($myBag);
// Converting object to an array
$myBagArray = (array)$myBag;
echo "After conversion : \n";
var_dump($myBagArray);
?>
The output is following:
Before conversion :
object(bag)#1 (4) {
["par0"]=> object(bag)#2 (4) {
["par0"]=> NULL
["par1"]=> string(0) ""
["par2":protected]=> string(0) ""
["par3":"bag":private]=> string(0) ""
}
["par1"]=> string(6) "Mobile"
["par2":protected]=> string(7) "Charger"
["par3":"bag":private]=> string(5) "Cable"
}
After conversion :
array(4) {
["par0"]=> object(bag)#2 (4) {
["par0"]=> NULL
["par1"]=> string(0) ""
["par2":protected]=> string(0) ""
["par3":"bag":private]=> string(0) ""
}
["par1"]=> string(6) "Mobile"
["�*�par2"]=> string(7) "Charger"
["�bag�par3"]=> string(5) "Cable"
}
This method has a benefit comparing to Serialiser normalizing -- this way you can convert Object to array of objects, not array of arrays.
I had the same issue and tried the 2 other answers. Both did not work very smoothly.
The $object = (array) $object; added alot of extra text in my key
names.
The serializer didn't use my active property because it did not have is in front of it and is a boolean. It also changed the sequence of my data and the data itself.
So I created a new function in my entity:
/**
* Converts and returns current user object to an array.
*
* #param $ignores | requires to be an array with string values matching the user object its private property names.
*/
public function convertToArray(array $ignores = [])
{
$user = [
'id' => $this->id,
'username' => $this->username,
'roles' => $this->roles,
'password' => $this->password,
'email' => $this->email,
'amount_of_contracts' => $this->amount_of_contracts,
'contract_start_date' => $this->contract_start_date,
'contract_end_date' => $this->contract_end_date,
'contract_hours' => $this->contract_hours,
'holiday_hours' => $this->holiday_hours,
'created_at' => $this->created_at,
'created_by' => $this->created_by,
'active' => $this->active,
];
// Remove key/value if its in the ignores list.
for ($i = 0; $i < count($ignores); $i++) {
if (array_key_exists($ignores[$i], $user)) {
unset($user[$ignores[$i]]);
}
}
return $user;
}
I basicly added all my properties to the new $user array and made an extra $ignores variable that makes sure properties can be ignored (in case you don't want all of them).
You can use this in your controller as following:
$user = new User();
// Set user data...
// ID and password are being ignored.
$user = $user->convertToArray(["id", "password"]);

Using json_encode on objects in PHP (regardless of scope)

I'm trying to output lists of objects as json and would like to know if there's a way to make objects usable to json_encode? The code I've got looks something like
$related = $user->getRelatedUsers();
echo json_encode($related);
Right now, I'm just iterating through the array of users and individually exporting them into arrays for json_encode to turn into usable json for me. I've already tried making the objects iterable, but json_encode just seems to skip them anyway.
edit: here's the var_dump();
php > var_dump($a);
object(RedBean_OODBBean)#14 (2) {
["properties":"RedBean_OODBBean":private]=>
array(11) {
["id"]=>
string(5) "17972"
["pk_UniversalID"]=>
string(5) "18830"
["UniversalIdentity"]=>
string(1) "1"
["UniversalUserName"]=>
string(9) "showforce"
["UniversalPassword"]=>
string(32) ""
["UniversalDomain"]=>
string(1) "0"
["UniversalCrunchBase"]=>
string(1) "0"
["isApproved"]=>
string(1) "0"
["accountHash"]=>
string(32) ""
["CurrentEvent"]=>
string(4) "1204"
["userType"]=>
string(7) "company"
}
["__info":"RedBean_OODBBean":private]=>
array(4) {
["type"]=>
string(4) "user"
["sys"]=>
array(1) {
["idfield"]=>
string(2) "id"
}
["tainted"]=>
bool(false)
["model"]=>
object(Model_User)#16 (1) {
["bean":protected]=>
*RECURSION*
}
}
}
and here's what json_encode gives me:
php > echo json_encode($a);
{}
I ended up with just this:
function json_encode_objs($item){
if(!is_array($item) && !is_object($item)){
return json_encode($item);
}else{
$pieces = array();
foreach($item as $k=>$v){
$pieces[] = "\"$k\":".json_encode_objs($v);
}
return '{'.implode(',',$pieces).'}';
}
}
It takes arrays full of those objects or just single instances and turns them into json - I use it instead of json_encode. I'm sure there are places I could make it better, but I was hoping that json_encode would be able to detect when to iterate through an object based on its exposed interfaces.
All the properties of your object are private. aka... not available outside their class's scope.
Solution for PHP >= 5.4
Use the new JsonSerializable Interface to provide your own json representation to be used by json_encode
class Thing implements JsonSerializable {
...
public function jsonSerialize() {
return [
'something' => $this->something,
'protected_something' => $this->get_protected_something(),
'private_something' => $this->get_private_something()
];
}
...
}
Solution for PHP < 5.4
If you do want to serialize your private and protected object properties, you have to implement a JSON encoding function inside your Class that utilizes json_encode() on a data structure you create for this purpose.
class Thing {
...
public function to_json() {
return json_encode(array(
'something' => $this->something,
'protected_something' => $this->get_protected_something(),
'private_something' => $this->get_private_something()
));
}
...
}
A more detailed writeup
In PHP >= 5.4.0 there is a new interface for serializing objects to JSON : JsonSerializable
Just implement the interface in your object and define a JsonSerializable method which will be called when you use json_encode.
So the solution for PHP >= 5.4.0 should look something like this:
class JsonObject implements JsonSerializable
{
// properties
// function called when encoded with json_encode
public function jsonSerialize()
{
return get_object_vars($this);
}
}
In RedBeanPHP 2.0 there is a mass-export function which turns an entire collection of beans into arrays. This works with the JSON encoder..
json_encode( R::exportAll( $beans ) );
Following code worked for me:
public function jsonSerialize()
{
return get_object_vars($this);
}
I didn't see this mentioned yet, but beans have a built-in method called getProperties().
So, to use it:
// What bean do we want to get?
$type = 'book';
$id = 13;
// Load the bean
$post = R::load($type,$id);
// Get the properties
$props = $post->getProperties();
// Print the JSON-encoded value
print json_encode($props);
This outputs:
{
"id": "13",
"title": "Oliver Twist",
"author": "Charles Dickens"
}
Now take it a step further. If we have an array of beans...
// An array of beans (just an example)
$series = array($post,$post,$post);
...then we could do the following:
Loop through the array with a foreach loop.
Replace each element (a bean) with an array of the bean's properties.
So this...
foreach ($series as &$val) {
$val = $val->getProperties();
}
print json_encode($series);
...outputs this:
[
{
"id": "13",
"title": "Oliver Twist",
"author": "Charles Dickens"
},
{
"id": "13",
"title": "Oliver Twist",
"author": "Charles Dickens"
},
{
"id": "13",
"title": "Oliver Twist",
"author": "Charles Dickens"
}
]
Hope this helps!
I usually include a small function in my objects which allows me to dump to array or json or xml. Something like:
public function exportObj($method = 'a')
{
if($method == 'j')
{
return json_encode(get_object_vars($this));
}
else
{
return get_object_vars($this);
}
}
either way, get_object_vars() is probably useful to you.
$products=R::findAll('products');
$string = rtrim(implode(',', $products), ',');
echo $string;
Here is my way:
function xml2array($xml_data)
{
$xml_to_array = [];
if(isset($xml_data))
{
if(is_iterable($xml_data))
{
foreach($xml_data as $key => $value)
{
if(is_object($value))
{
if(empty((array)$value))
{
$value = (string)$value;
}
else
{
$value = (array)$value;
}
$value = xml2array($value);
}
$xml_to_array[$key] = $value;
}
}
else
{
$xml_to_array = $xml_data;
}
}
return $xml_to_array;
}
for an array of objects, I used something like this, while following the custom method for php < 5.4:
$jsArray=array();
//transaction is an array of the class transaction
//which implements the method to_json
foreach($transactions as $tran)
{
$jsArray[]=$tran->to_json();
}
echo json_encode($jsArray);

Categories