Now I admit I am slightly new to laravel still, but to me this just does not make sense. The model that goes along with this table contains only 2 functions, both containing a relationship statement.
I am using Laravel4, mysql, php 5.5
Any ideas are welcome :D
The database record-definitions are for both DATETIME, allow null and no default value (changed that after the screenshots)
the $challenge variable is part of the data I pass on to the view like so:
$challenges = Auth::user()->challenges;
$data['challenges'] = $challenges;
return View::make("challenges/topic", $data);
and in the view I use
#foreach($challenges as $challenge)
read the challenge values (I am aware I cant echo like that without php tags or {{ }}, just easier to explain)
echo gettype($challenge->deadline) // results in string
echo gettype($challenge->created_at) // results in object
Depends on how you access it, if you do:
Route::any('test', ['as' => 'test', function()
{
$a = Article::first();
var_dump( gettype($a->created_at) );
$a = DB::table('articles')->first();
var_dump( gettype($a->created_at) );
}]);
You will get:
string 'object' (length=6) /// This is Eloquent
string 'string' (length=6) /// This is the QueryBuilder directly accessing your table
Related
I'm having an issue with using Laravels put() function, as I want put JSON content in this one single scenario.
$datatable->GroupsCollection = $datatable->GroupsCollection->put($job, '{"grade":'.$grade.'}' );
But when trying to create 'fake' JSON, the inserted value will be:
{\"grade\":'VALUE_OF_$GRADE'}
I've tried using str_replace() and stripslashes() to cut out the backwardslashes, but no bueno.
I've Googled around, and reading something about a cast was needed in the Model.
So I put in this:
protected $casts = [
'dvalue' => 'array',
];
This result in breaking existing functionality of the code.
public function getGroupsCollectionAttribute()
{
return collect($this->dvalue ? $this->dvalue['groups'] : null);
}
public function setGroupsCollectionAttribute($value)
{
$currentValue = $this->dvalue ?? new Collection();
$this->dvalue['groups'] = $currentValue->$value;
}
I 'fixed' the get, but I'm not sure how I should format the 'set' function with this new cast and setting it to an array.
Worth to notice is that we have mixed content in the DB-rows, so it's not always JSON.
Any easier way to go around this?
Ending up fixing it by simply creating an array like this:
$grade_json = array("grade" => $grade);
$datatable->GroupsCollection = $datatable->GroupsCollection->put($job, $grade_json);
My app reads from a DB that get's written by another API, now in some outlandish cases (that actually happened today) it wrote a customer id of 0, which ofcourse, does not exist.
I am looking for an elegant 'from-the-top' model or even presenter solution for handling erroneous ID's that do not exist.
So instead of finding every $whatever->customer->id in my app and then writing in an isset()/empty() ternary function, I am looking to pacify this error in a more elegant way where any customer instantiation/eloquent object would send the string "NA" to a non existent object, so even if an email/phone/etc or any other column of customer model, it would return a simple "NA" string.
I am struggling to find an eloquent solution that would provide 1 point of change.
you can use withDefault() modifier on your relationship.
example:
use Illuminate\Database\Eloquent\Model;
class Whatever extends Model {
public function customer() {
return $this->belongsTo(Customer::class, 'customer_id', 'id')
->withDefault([
'id' => 'NA',
'name' => 'Unknown'
// etc
]);
}
}
I would suggest you take a look at a Laravel class that most people don't know about. That is Fluent.
It allows you to do stuff like this:
$fluent = new Fluent([
'one' => 1,
'two => 2,
]);
echo $fluent->get('one'); // returns 1
echo $fluent->get('three'); // returns null
echo $fluent->get('three', 3); // returns 3
As you can imagine, it's perfect to use with third-party APIs and data that sometimes provide unexpected results. You can also do a lot more with Fluent.
Alternatively, you could look into Laravel helpers such as array_get(). From the documentation:
The array_get function retrieves a value from a deeply nested array using "dot" notation:
$array = ['products' => ['desk' => ['price' => 100]]];
$price = array_get($array, 'products.desk.price');
// 100
The array_get function also accepts a default value, which will be returned if the specific key is not found:
$discount = array_get($array, 'products.desk.discount', 0);
// 0
$somedata = Indicator::all();
$indicators = [];
// ... (re-structure the data; rows to columns)
$indicators[] = ['a'=>'2016', 'b'=>'2017', 'c'=>'2018'];
$indicators[] = ['a'=>'1232', 'b'=>'3242', 'c'=>'5467'];
$indicators[] = ['a'=>'1232', 'b'=>'3242', 'c'=>'5467'];
$indicators[] = ['a'=>'closed', 'b'=>'closed', 'c'=>'open'];>
// ??? How to form a valid object to send ???
return view('indicators.index')->with(['indicators'=> $indicators]);
I select data. I change the structure for displaying it; but cannot find the correct structure to then pass in my response.
The view throws the error "Trying to get property of non-object (View: "
(I looked at the dump of Indicator::all(); and wonder if I have the right/wrong approach)
// noob
You're returning an array, I image you are probably trying to access an index using object notation like:
$val->prop
when it should be:
$val['prop']
Indicator::all() returns a collection of objects which you're not using in your view.
As an aside, Laravel collections have some handy helper functions to work with result sets. You may be interested in:
https://laravel.com/docs/5.5/collections#method-map
As $indicators is an array so you have to use [''] instead of -> to access its data.
In my controller I am retrieving records from my institutions table with the following fields
$params = array(
'fields' => array(
'Institution.id',
'Institution.name',
'Institution.about',
'Institution.picture'),
);
$institutions = $this->Institution->find('all',$params);
How can I prefix each 'Institution.picture' field with the full URL address, 'Institution.picture' itself only holds the name of the file.
I would also like to perform html_entity_decode() on each 'Institution.about' value from the returned set.
I know how to do this only without the framework if I make custom queries from scratch, then I would iterate each row and apply PHP functions to the field of interest. But is there a place in CakePHP (find or paginator) that I can specify such PHP manipulation on each field value from the returned set?
NOTE: I don't like to do this in the View, as I want to output it as json directly
You can define a virtualField for model:
public $virtualFields = array('image_url' => "CONCAT('/img/', Institution.picture)");
$params = array(
'fields' => array(
'Institution.id',
'Institution.name',
'Institution.about',
'Institution.picture',
'Institution.image_url'),
);
$institutions = $this->Institution->find('all',$params);
Unfortunaly MySQL doesn't have a function to decode HTML entities. You may utilize an afterFind() callback instead of virtualField. This lets you to decode entities as well as add a prefix.
CakePHP is php
Just iterate over the array and prepare it however you want:
$institutions = $this->Institution->find('all',$params);
$prefix = '/img/'; // <- define this
foreach ($institutions as &$row) {
$row['Institution']['about'] = html_entity_decode($row['Institution']['about']);
$row['Institution']['picture'] = $prefix . $row['Institution']['picture'];
}
If this is always required it can be applied to all finds via an afterFind method in the institution class.
I think you should do it in the View. See this example.
Hash::map can be very useful here. By specifying path you can only modify slices of the set.
I am trying to extract ONLY the PlanDetails where PlanDetail.company_id = Company.id AND PlanDetail.id' => $id.. ( you can see the conditions in my controller below)..
Controller:
function pd_list_by_company($id = null) {
$this->recursive = 2; // I am going to use containable to trim this.
return $this->PlanDetail->find('all',
array('conditions' =>
array('AND' =>
array('PlanDetail.company_id' => 'Company.id',
array('PlanDetail.id' => $id)))));
}
Test View:
$planDetailsByCompany = $this->requestAction('/planDetails/pd_list_by_company');
debug($planDetailsByCompany );
Output result of my debug??
Array()
If I remove the conditions and just have the find all, I get all PlanDetails as expected, so I know the data is being passed.. SQL debug dump even shows the query:
WHERE ((`PlanDetail`.`company_id` = 'Company.id') AND (`PlanDetail`.`id` IS NULL))
And yes, I did notice the $id is NULL, and I know the value needs to be there.. So maybe my question is why is the $id value not being passed to the controller even though I can see the PlanDetail.id value on a find('all') w/ out the conditions??
Thanks for any tips.
Since $id seems to be null, I would assume that you call the function without the parameter. And you don't get an error message, because as far as PHP is concerned the parameter is optional. In this case it's clearly required, so you should make it a required parameter in your function declaration:
function pd_list_by_company($id) {
Also you could simplify the return statement, you do not need the AND:
return $this->PlanDetail->find('all',
array('conditions' =>
array('PlanDetail.company_id' => 'Company.id','PlanDetail.id' => $id)
)
);
To answer the question why is the $id not being passed is because you're not passing it
To pass say $id of 2 you need to do the following in your requestAction
$this->requestAction('/planDetails/pd_list_by_company/2');
Seems to me that your code should just be
return $this->PlanDetail->find('array('PlanDetail.id' => $id));
Assuming you have the $this->PlanDetail->recursive flag set to > 0, your Model should already know about and return the associated data for any 'Company' table.....
I'm used to an old (1.3) version of CakePHP but the find() function is pretty basic and is designed to only return one row.
and yes, you definitely need to call the function with the id appended to the url, eg.
$planDetailsByCompany = $this->requestAction('/planDetails/pd_list_by_company/999');