I'm new to Eloquent and I'm having trouble when using it with loops.
Imagine I have a table in my db called ‘Jobs’ with:
Id – 1; value: engineer
Id – 2 ; value: doctor
Id – 3 ; value: nurse
I'd also have a JobTranslations table with each job translations. Then, I have this piece of code:
$jobTranslations = [];
$lang = $request->input('lang') ?? 'pt';
foreach(Job::all() as $job) {
$job = $job->with(['jobtranslations' => function($query) use ($lang) {
$query->where('languageCode', $lang);
}])->firstOrFail();
$jobTranslations[] = $job;
}
return ['translatedJobs' => $jobTranslations];
When I run this code, I’m expecting to get an array (jobTranslations) with those 3 jobs in it and each job’s translation.
However, I get instead an array with three items, but they’re all the same:
array([‘id’ => 1, ‘value’ => ‘engineer’, ‘jobtranslations’ => [another array]],
[‘id’ => 1, ‘value’ => ‘engineer’, ‘jobtranslations’ => [another array]],
[‘id’ => 1, ‘value’ => ‘engineer’, ‘jobtranslations’ => [another array]]
);
I’ve realized this is happening due to ‘firstOrFail’ but I don’t understand why. $job->firstOrFail() doesn’t make sense to me because it’s only one job (the current one in the loop) but I don’t want to use get() either.
In C#, using EF, I’d do something like this (no need to call get or first):
foreach(var job in jobs) {
translatedJobs.Add(job.Include(j => j.jobtranslations.FirstOrDefault(jt => jt.languageCode == lang)));
}
return translatedJobs;
Thanks in advance!
I assum what you ar looking for ist this:
$lang = $request->input('lang', 'pt');
$jobTranslations = Job::with([
'jobtranslations' => function ($query) use($lang)
{
$query->where('languageCode', $lang);
}
])->get()->toArray();
return ['translatedJobs' => $jobTranslations];
There is no need to do a Foreach Loop if you setup your Model correct.
Related
I have table attribute_values(id, value, attr_group_id).
I need to return the collection grouped by key attr_group_id.
in clear php using ORM RedBean i made:
$data = \DB::table('attribute_values')->get();
$attrs = [];
foreach ($data as $k => $v){
$attrs [$v['attr_group_id']][$k] = $v['value'];
}
return $attrs;
I need same using Laravel, after this one:
$data = \DB::table('attribute_values')->get();
My table
id value attr_group_id
1 one 1
2 two 1
3 three 2
4 four 2
5 five 3
6 six 3
And i need result
Array(
[1] => Array
(
[1] => one
[2] => two
)
[2] => Array
(
[3] => three
[4] => four
)
[3] => Array
(
[5] => five
[6] => six
)
)
Fetch all data, and map it with attribute id of every row will work,
$data = \DB::table('attribute_values')->get();
$attrs = [];
foreach ($data as $key => $value) {
// -> as it return std object
$attrs[$value->attr_group_id][] = $value->value;
}
dd($attrs);
You can use the groupBy() function of collection as:
$data = \DB::table('attribute_values')->get()->groupBy('attr_group_id');
It merges records with same attr_group_id under this field's value as making key of the collection.
Doing all this in raw SQL will be more efficient, SQL database are quite good at these operations. SQL has a group by function, since you are overwriting value, i just get it out with max() (this seems weird, that you overwrite the value, do you actually just want unique results?).
DB::table('attribute_values')
->select('attr_group_id', DB::raw('max(value)'))
->groupBy('attr_group_id')
->get();
EDIT
Since the scope has changed, you can utilize Laravels Collection methods, that is opreations on a Collection.
DB::table('attribute_values')
->get()
->groupBy('attr_group_id')
->toArray();
Friends, this is a ready task that I needed !
I did it myself and you helped me. If anyone interested can read.
I'll explain to you why I needed this particular method. I am doing an online store with a clock and now there was a task to make filters and attributes for filters.
So there are three tables
attribute_groups table
attribute_products table
attribute_values
I need to display the Laravel widget on my .blade.php like as
{{ Widget::run('filter', 'tpl' => 'widgets.filter', 'filter' => null,]) }}
When i creating a new product in the admin panel.
I must to save the product id and attribute_id in attribute_products, but there can be as many attributes as possible for one product. so, if I'll use this option
$data = \DB::table('attribute_values')
->get()
->groupBy('attr_group_id')
->toArray();
I got result:
But! each new array starts with index 0. But I need an index that means its id. attr_group_id from table attribute_value for saving into attribute_products.
And after I see only one method for me.
$data = \DB::table('attribute_values')->get();
$attrs = [];
foreach ($data as $key => $value) {
$attrs[$value->attr_group_id][$value->id] = $value->value;
}
return $attrs;
and the result I was looking for
now you can see what's the difference and what was needed. Array index starts 1,2,3,4,5 and this index = attr_group_id. Unfortunately I could not initially ask the right question. thanks to all.
Laravel Version 5.8
So You need to Group the id
if You need in the Model Way I have created the Model as AttributeValue
$modelWay = \App\AttributeValue::get()
->groupBy('attr_group_id');
if You need in the DBWay I have created the table as attribute_values
$dbWay = \DB::table('attribute_values')
->get()
->groupBy('attr_group_id');
Both Will give the Same Result
Can anybody help is this code can be called OOP design. How to Create a class in PHP which shows that is OOP design.
I'm trying to create a simple example class before I start implementing the following into my projects and I would like to know if there is something I could/should improve. I will be very glad if someone gives me some input of how am I doing now.
This is simple class which is sorting associative array columns. Can anybody write simple class regarding sorting associative array. It can be anything just should follow OOP design pattern.
Thanks in advance for help.
<?php
interface PassangerBoardingInterface
{
public function ArrageBoardingTicket(string $from, string $to, string $instruction) ;
public function GetEmbededHTMlTemplate ( $template, $regrex);
}
class PassengerBoardingSorterOOP implements PassangerBoardingInterface
{
// Boarding list
public $boardingList;
// Journey start message
public $startMessage;
// End message
public $endMessage;
// Get Template
public $getTemplate;
public function __construct(array $boardingList )
{
$this->boardingList = $boardingList;
}
public function ArrageBoardingTicket(string $from, string $to , string $instruction)
{
foreach($this->boardingList as $boardingList)
{
usort($this->boardingList, function ($a, $b) use ($to, $from){
return ($a[$to] === $b[$from] ) ? 0 : 1;
});
}
// Defining index
$i = 0;
$coutboarding = count($this->boardingList);
// Appending data to start index
$this->boardingList[0][$instruction] = $this->startMessage;
// Appending string to end column
$this->boardingList[$coutboarding - 1 ][$instruction] = $this->endMessage;
}
public function GetEmbededHTMlTemplate($template, $regrex)
{
$result = '';
/* Loop each data */
for($j = 0; $j < count($this->boardingList); $j++)
{
/* Get the template */
$output = $template;
/* where indexs matches in template */
foreach($this->boardingList[$j] as $key => $value)
{
$reg = str_replace('(.*?)',$key, $regrex);
/* Check with regular expression */
if(preg_match($reg,$template))
{
/* Replace with */
$output = preg_replace($reg,$value,$output);
}
}
$result .= $output;
}
$this->getTemplate = $result;
}
}
==============================
I am using below structure
//My array of information
$cards = [
[
"from" => "Barcelona",
"to" => "New York",
"instruction" => "",
'time' => '2018-02-02 20:05',
'transport' => 'Flight' ,
'transportno' => 'B33',
'seatno' => 'Y15'
],
[
"from"=> "Barcelona",
"to" => "Gerona",
"instruction" => "",
'time' => '2018-02-02 20:05',
'transport' => 'Bus' ,
'transportno' => 'M31, M32, M33','seatno' => 'Any'
], // 1
[
"from" => "Madrid",
"to" => "Barcelona",
"instruction" => "",
'time' => '2018-02-02 20:05',
'transport' => 'Bus' ,
'transportno' => 'M31, M32, M33',
'seatno' => 'Any'
],
["from" => "New York",
"to" => "Stockholm",
"instruction" => "",
'time' => '2018-02-02 20:05', 'transport' => 'Flight' ,
'transportno' => 'M31, M32, M33','seatno' => 'Any'
], // 0
[
"from" => "Gerona",
"to" => "Barcelona",
"instruction" => "",
'time' => '2018-02-02 20:05',
'transport' => 'Bus' ,
'transportno' => 'M31, M32, M33',
'seatno' => 'Any'
], // 2
];
$obj = new PassengerBoardingSorterOOP($cards);
$obj->startMessage = 'Your journey start from here ';
// End message
$obj->endMessage = 'Your journey ends here';
$obj->ArrageBoardingTicket('from', 'to', 'instruction');
// Form a template so you can get template list
$template = '<li class="list-group-item">{{&instruction}}Take {{&transport}} From {{&from}} To {{&to}},
{{&transport}} No {{&transportno}}, {{&transport}} Departure Date {{&time}}. Seat Number {{&seatno}}.</li>';
$regrex = '/{{&(.*?)}}/';
$obj->GetEmbededHTMlTemplate($template, $regrex);
echo $obj->getTemplate;
The code you provided violates a few rules for OOP hence can not be considered as such.
It is a representation of objects that interact with each other in order to create your program, instead of scripts that call each other (hope this makes sense).
You have to start thinking how you can represent your problem into objects.
Let's say you have a car to represent in PHP.
You will start to think you can have:
A car class;
A Wheel class (you car can have 4 wheels);
Then you think "But a car is a vehicle and, for example, a bike only have 2 wheels" and then you create your "Vehicle class";
Then you enhance your Car Class and extend it from Vehicle;
Now, each Vehicle have tyres, but you do not specify how many, that is for each type to decide, not the parent class that "abstracts them".
And so on. You quickly see here that to tackle this problem (and we are on the very start) you already have;
Abstract Class Vehicle;
Car Class (that extends Vehicle);
Bike Class (that extends Vehicle);
Wheel Class (That can be added to Vehicle types -> Your Car and your Bike);
When you want to move to OOP there are a few rules you need to consider:
Encapsulation;
Polymorphism;
Open/Close implementation;
Inheritance;
Open Recursion;
You want to restrict your Class objects to only understand "what they are". So a Car does not hold logic for a Bike and vice-versa.
1. Encapsulation -> This prevents external code from manipulating or "holding concern" to what happens on the target class internally;
It refers to the use of private and protected methods;
How the Car class behaves and what it triggers to work in whatever logic you decide a Car should work, is completely hidden for the other classes like Bike. They do not need to know what clicks on each other!
2. Polymorphism -> For example, the number of tyres, or even the Tyre types for each Vehicle, it will be different. Therefore you can declare the Vehicle can addTyres BUT each Vehicle type (like Car and Bike) will implement how to addTyres differently (You can limit bikes to have 2 tyres only whilst cars have 4);
3. Open/Close implementation -> When you create classes you should think on them as they should be OPEN for extension BUT CLOSED for modification. This means you can extend their behaviour BUT you should never have to go back and change your object behaviour;
4. Inheritance -> Allows your Classes to implement "hierarchy". Think of it as "parent" and "children". What came "First" and what came "after". Like a Shape is a parent of a Circle. If you announcing your argument, Shape is very abstract as it represents anything from Squares, Triangles, Circles, etc. But if you refer to a Square you know about it in more detail, like vertices, angles, etc! Shapes represent that but refine nothing towards what type, just what structure should be but not "how it will be";
5. Open Recursion -> Classes are able to call each other and even other classes. That is how they interact. Hell they can even have other objects as part of their attributes;
In a very resumed source this is a very BRIEF introduction to OOP!
Once you get the hang of it it is amazing and you will have such a powerful logical code and so organised I swear to you, you will not go back :3
But yeah, this is not enough to even begin telling you OOP! :x Just think of it this way, it is a walk, not a destination :D
PS: A great way to start getting used to OOP is also starting to look at Design Patterns
I am using Laravel Collections methods and am trying to key my query results (which are a collection) by the id. The problem is I have multiple entries with the same id, but point to different countries and I want to have all of the values, not just the last one.
Here is my code that i am using so far:
$allCountries = new Collection($allCountries);
$offerCountries = $allCountries->keyBy('id');
dd($offerCountries);
foreach ($offer as $o) {
$o->countries = $allCountries->get($o->id);
}
To explain, my query puts the results in $allCountries which contains ids and countries and those results looks something like this
id=>225, country=>US
id=>225, country=>IT
id=>3304, country=>NZ
Just to give you a quick idea. I want to key this by the id which results in $offerCountries. I then loop thru a previous Collection that contains offers which have a certain ID that relates to the country result by id. So for the offer 225, the countries it contains are US and IT. I loop thru each offer and set the countries object equal to all the $allCountries id that it equals. The problem I have here is keyBy overwrites the value and only takes the last one. I am hoping to get some results like this:
[
225 => countries: {'id' => 225, 'country' => 'US'}, {'id' =>
'225', 'country' => 'IT'}
3304 => ['id' => 3304, 'country' => 'NZ'],
]
Is there a laravel method to do this, or do I need to write my own keyBy so it does not overwrite. If so, how can I get started to write this method?
Thanks
Instead of using keyBy, use groupBy:
$countriesById = collect($allCountries)->groupBy('id');
You could use filter and create a custom filter
$filtered = $allCountries->filter(function ($item) use ($id) {
return $item->id == $id;
});
$filtered->all();
I'm Trying to solve this error i'm having with PHP, i'm not completely familiar with the Language, so it would be nice if you would help me out, I can't figure out this error.
I have this Code Here:
public function index() {
$counterino = ClientsJobs::all()->count();
$MasterArray = array();
/* Go Through All of the Records in the Client-Jobs Table and Resolve their columns to Desired Names */
for ($i = 1; $i <= $counterino; $i++ ) {
//Temporary Array for one Name-Resolved-Row of the Table.
$tempArray = array(
'id' => ClientsJobs::find( $i )->id, // id
'client_name' => ClientsJobs::find( $i )->clients->fname , // get the first name ( based on fk )
'job_name' => ClientsJobs::find( $i )->jobs->name, // get the name of the job ( based on fk )
'wage' => ClientsJobs::find( $i )->wage, // wage for the job
'productivity'=> ClientsJobs::find( $i )->producivity // productivity level for the job
);
$MasterArray[] = $tempArray; //add the row
}
return $MasterArray;
}
This code changes the names of the of the Columns in the ClientsJobs Junction Table.
public function up()
{
Schema::create('clients-jobs', function(Blueprint $table)
{
$table->increments('id')->unsigned();
$table->integer('client_id')->unsigned();
$table->foreign('client_id')->references('id')->on('clients');
$table->integer('job_id')->unsigned();
$table->foreign('job_id')->references('id')->on('jobs');
$table->decimal('wage', 4, 2);
$table->decimal('productivity', 5, 2); // 0.00 - 100.00 (PERCENT)
$table->timestamps();
});
}
The Jobs and Clients Table are very simple.
I am having the Error in the index() function I posted above, it says
'Trying to get property of non-object'
Starting on the Line
'client_name' => ClientsJobs::find( $i )->clients->fname,
It's also mad at me for the other parts of setting the array.
I have tested the individual functions I am using to set the array and they all work, fname should also return a string, I used dd() to get the value.
I have tried:
-Using FindorFail
-Setting the Array without the for loop and setting each element manually
-Dumping out multiple parts of the function to make sure it works( counterino, all of the functions for the array, .. )
My guess is that it has to do with the type-deduction of PHP, I actually only need a string array, but would still like to use the name mappings because I am going to be passing this a View I am using for some of my other stuff. The Code was actually working earlier, but I broke it somehow (adding a new record or running a composer update?) anyway, there's some serious voodoo going on.
Thanks in Advance for the help, I am working on this project for a Non-Profit Organization for free.
P.S. I am using Laravel 4.2, and Platform 2.0
First off, this is a horrible practice:
$tempArray = array(
'id' => ClientsJobs::find( $i )->id, // id
'client_name' => ClientsJobs::find( $i )->clients->fname , // get the first name ( based on fk )
'job_name' => ClientsJobs::find( $i )->jobs->name, // get the name of the job ( based on fk )
'wage' => ClientsJobs::find( $i )->wage, // wage for the job
'productivity'=> ClientsJobs::find( $i )->producivity // productivity level for the job
);
By calling ClientJobs::find($i) multiple times, you are doing multiple times the same lookup - either to your DB, or to your cache layer if you have one configured.
Secondly, the answer to your question depends on your ClientJobs model. For your example to work, it needs:
A valid clients relations, defined as follows:
public function clients()
{
return $this->hasOne(...);
}
clients also needs to be a valid 1:1 always existing relation. i.e. there must always be one client. If there isn't, you are susceptible to the error you just got (as the `clients̀ magic would end up being null)
The same applies to jobs.
In every case, it is better to make sure everything is set first. Check using the following:
$clientJob = ClientJobs::find($i);
if (!$clientJob->clients || $clientJob->jobs) throw new \RangeException("No client or job defined for ClientJob $i");
And then catch the exception at whichever level you prefer.
Best approach
public function index() {
$masterArray = array();
ClientsJobs::with('clients', 'jobs')->chunk(200, function($records) use (&$masterArray) {
foreach ($records as $record) {
$masterArray[] = array(
'id' => $record->id, // id
'client_name' => !empty($record->clients) ? $record->clients->fname : null,
'job_name' => !empty($record->jobs) ? $record->jobs->name : null,
'wage' => $record->wage,
'productivity'=> $record->productivity,
);
}
});
return $MasterArray;
}
Your Approach is very wrong
If you want to return an array you can do like this
$counterino = ClientsJobs::all()->toArray();
This will fetch all rows from the table and the toArray will convert the object into an array
Ok, trying to make a function that I can pass a variable to, that will search a static currently hardcoded multi dimensional array for its keys, and return the array matched to the key found (if found).
This is what I have thus far.
public function teamTypeMapping($teamType)
{
//we send the keyword football, baseball, other, then we return the array associated with it.
//eg: we send football to this function, it returns an array with nfl, college-football
$mappings = array(
"football" => array('nfl', 'college-football'),
"baseball" => array('mlb', 'college-baseball'),
"basketball" => array('nba', 'college-basketball'),
"hockey" => array('nhl', 'college-hockey'),
);
foreach($mappings as $mapped => $item)
{
if(in_array($teamType, $item)){return $mapped;}
}
return false;
}
And I'd like to make a call to it, example:
teamTypeMapping("football");
Amd have it return the array associated with the key "football", I have tried this a couple ways, and each time I come up false, maybe I am missing something so Im up for taking some advice at this point.
The reason it's not working is that you are looping through the $mappings array, and trying to see if $teamType is in the $item.
There are two problems with your approach:
You are looking in the $item (this is the array('nfl', 'college-football')) for 'football'. This is incorrect.
You are using in_array() which checks if a 'value' is in the array, not the 'key' that you have used. You might want to take a look at the array_key_exists() function - I think this is what you meant to use.
My personal preference is to use isset() instead of array_key_exists(). Slightly different syntax, but both do the same job.
See below for a revised solution:
public function teamTypeMapping($teamType)
{
//we send the keyword football, baseball, other, then we return the array associated with it.
//eg: we send football to this function, it returns an array with nfl, college-football
$mappings = array(
"football" => array('nfl', 'college-football'),
"baseball" => array('mlb', 'college-baseball'),
"basketball" => array('nba', 'college-basketball'),
"hockey" => array('nhl', 'college-hockey'),
);
if (isset($mappings[$teamType]))
{
return $mappings[$teamType];
}
return false;
}
I checked your function
public function teamTypeMapping($teamType)
{
//we send the keyword football, baseball, other, then we return the array associated with it.
//eg: we send football to this function, it returns an array with nfl, college-football
$mappings = array(
"football" => array('nfl', 'college-football'),
"baseball" => array('mlb', 'college-baseball'),
"basketball" => array('nba', 'college-basketball'),
"hockey" => array('nhl', 'college-hockey'),
);
foreach($mappings as $mapped => $item)
{
if(in_array($teamType, $item)){return $mapped;}
}
return false;
}
And when you like to make a call to it, example:
teamTypeMapping("football");
then it return false.
Solution is If your want the array then you want
foreach($mappings as $mapped => $item)
{
if($mapped == $teamType){return $mapped;}
}