I've the following object structure: Order->RepairJobs->Parts. Part has a boolean property InStock. What would be the most efficient way to find out whether a certain Order contains RepairJobs with Parts that are not in Stock? Should I iterate through every RepairJob and then through every Part, or does Symfony/Doctrine have some smart function for this?
In your controller add query builder:
$em = $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select('p')
->from('AppBundle:Part', 'p')
->where('p.InStock = false');
$parts = $qb->getQuery()->getResult();
Pass to render Twig template like so:
return $this->render('show/orders_without_stock.html.twig', array(
'parts' => $parts,
));
Then in Twig iterate:
<h2>Orders With Parts Not in Stock</h2>
<table>
<tr>
<th>Order</th>
</tr>
{% for part in parts %}
<tr>
<td>{{ part.getRepairJob.getOrder }}</td>
</tr>
{% endfor %}
</table>
In the above Twig, 'part' is a Part object and 'getRepairJob' is a Part method that gets the Repair Entity. This gets a RepairJob object, then 'getOrder' is the RepairJob method that gets a Order object.
I presume you've setup your Entities and the correct ORM annotations to map each of the Entities. Where both 'RepairJobs' and 'Parts' are collection of objects.
Hopefully this makes sense. But this is how it is done, and it makes things extremely easy to code.
Related
I am having issues understanding the "belongsTo" method in a class I am working with.
I have an "Asset" model which wasn't written by me, but I'd guess it works, and it has this function where I am trying to access the 'name' property of the "AssetMake" table (Which foreign and primary key args look about right):
public function assetMake()
{
return $this->belongsTo(AssetMake::class, 'assetmake_id', 'id');
}
In a blade template that looks something like this, with the $asset variable injected in (and succesfuly already being used on the same page):
#foreach($assets as $asset)
<tr>
<td width="5%" class="filter_id">{{ $asset['unit_id'] }}</td>
<td width="20%" class="filter_type">{{ $asset['TypeName'] }}</td>
<td width="25%">{{ $asset['description'] }}</td>
<td width="20%">{{ $asset->assetMake()->get() }}</td>
</tr>
#endforeach
"AssetMake" looks like this, do I need a corresponding "hasMany" function?:
class AssetMake extends Model
{
use ModelDateSerializeNonISO;
protected $table = 'assetmake';
protected $primaryKey = 'id';
protected $hidden = ['updated', 'created'];
}
I have tried acessing the injected $asset variable in a blade template as such:
<td width="20%">{{ $asset->assetMake->get }}</td>
<td width="20%">{{ $asset->assetMake->get() }}</td>
<td width="20%">{{ $asset->assetMake()->get }}</td>
<td width="20%">{{ $asset->assetMake->name }}</td>
<td width="20%">{{ $asset->assetMake()->name }}</td>
The 'name' property of the assetmake table is what I really need access to here.
Is this some kind of lazy/eager loading problem? I'm just not sure exactly what's happening here, and why I can't access the property. I've checked in various sources, and nothing I've tried works, but I'm sure it's fairly straight forward. Any tips?
The way to access a related model is to call it as you would normally call a property. So something like $asset->assetMake->name should work.
Behind the scenes, I believe Laravel uses PHP's magic methods to create properties on the model based on the method names so that they point to the related model (parent or child).
Similarly, if you have a hasMany relationship like so:
public function children()
{
return $this->hasMany(Child::class, 'child_id',);
}
You can access the children just by calling $parent->children.
And if you need to access the Child query builder from the parent, you have to call the children() method.
E.g
$parent->children()->create($childData)
Ok, I worked it out. It was an issue with the controller. I'm still working this out and the magic in Laravel can be confusing to me. I added the line "->join('assetmake', 'assetmake.id', 'asset.assetmake_id')" to the controller query. And added to the select statement as well 'assetmake.name as AssetMakeName'
$assets = FleetFuel::where('fleet_fuel.customer_id', $user->customer_id)
->where('fleet_fuel.isOrphan', 0)
->where('fleet_fuel.hours', '>=', 0) // -1.00 = first ever record
->where('fleet_fuel.burn', '>=', 0) // -1.00 = first ever record
->join('asset', function($join) {
$join->on('fleet_fuel.unit_id', '=', 'asset.Unit_ID');
$join->on('fleet_fuel.customer_id', '=', 'asset.Customer_ID');
})
->join('assettype', 'assettype.ID', 'asset.assettype_id')
->join('assetmake', 'assetmake.id', 'asset.assetmake_id')
->select('fleet_fuel.unit_id', DB::raw('max(fleet_fuel.delivery) as lastfuel'), 'asset.description', 'asset.Rego', 'assettype.Name as TypeName', 'assetmake.name as AssetMakeName')
->groupBy('fleet_fuel.unit_id')->get();
return view('fleetFuel.assets',
[
'companyName' => $companyName,
'assets' => $assets
]
);
And then accesed it in the blade view:
<td width="20%" class="filter_make">{{ (isset($asset['AssetMakeName'])) ? ($asset['AssetMakeName']) : ("No make available")}}</td>
i’m looking for a solution to a problem that I’m having for a while now. Maybe you can inspire me to do this better. I’m trying not to make a basic mistake in the planning process therefore I’m asking you for advice.
I’m having a Contact::model which has few fixed attributes like id etc. Additionally I would like to have different attributes created dynamically for the whole Contact::model. Some user will be given the functionality to add attributes like name, email, address to the whole model. I’ve dropped the idea of programmatically updating the table itself by creating/dropping columns (this would introduce different problems). As for now i've created two additional tables. One with the additional column names [Columns::model] and a pivot table to assign the value to a Contact::model and Column::model.
To list all contacts i’m preparing the ContactColumn table as array where the first key is the contact_id and the second is the column_id, therefore i get the value. This introduces the n+1 issue. This would not be that bad, but with this approach it will be extremely hard (or resource consuming) to order the contacts by dynamic column values, filtering, searching etc.
Can you somehow guide me to a better solution. How can i merge the contact collection with the values for given columns so it looks like it was a fixed table?
<table>
<thead>
<tr>
<th>Fixed columns [i.e. ID]</th>
#foreach ($columns as $column)
<th>{{ $column->name }}</th>
#endforeach
</tr>
</thead>
<tbody>
#foreach ($contacts as $contact)
<tr>
<td>{{ $contact->id }}</td>
#foreach ($columns as $column)
<td>
#if (array_key_exists($column->id, $values[$contact->id]))
{{ $values[$contact->id][$column->id] }}
#endif
</td>
#endforeach
</tr>
#endforeach
</tbody>
</table>
And the $value array.
foreach (ColumnContact::all() as $pivot) {
$values[$pivot->contact_id][$pivot->column_id] = $pivot->value;
}
return $values;
Edit: I've solved it like this
$this->contacts = Contact::when($this->dynamicColumnName, function($query) {
$query->join('column_contact', function ($join) {
$join->on('id', '=', 'column_contact.contact_id')
->where('column_contact.column_id', '=', $this->dynamicColumnName->id);
})
->orderBy('value', $this->orderingDirection);
})
(...)
->paginate(self::PER_PAGE);
Apart from the fixed fields, add an extra JSON field in your schema called 'custom_fields'. Have a look into => https://github.com/stancl/virtualcolumn
Separate table for custom fields is not a good idea because then you have to handle model events separately and so on.
I cannot wrap my mind around something.
I have a table which I render in my tables.blade.php file like this:
<table>
<thead>
<tr>
<th scope="col">Country</th>
<th scope="col">Member</th>
</tr>
</thead>
<tbody>
#foreach ($members as $member)
#if ($member->continent == 'Europe')
<tr>
<td>
{{ $member->country }}
</td>
<td class="align-middle player-code copy-code">
{{ $member->name }}
</td>
</tr>
#endif
#endforeach
</tbody>
</table>
As you can see you can click on a country which will show you members from one country in a new view (code not shown here).
The route for that single country site in the web.php looks like this:
Route::get('/{country}', 'PageController#show')->name('country');
Everything worked fine until I realized that I could put anything as 'country' and still would get shown the site for the country just with an empty table.
So '/abcde' would get you the view with just a naked table.
So I changed the route like this:
Route::get('/{country}', 'PageController#show')->name('country')->where('country', ('United Kingdom|France|Belgium|South Africa);
//the list is much longer
Ok. So now I have constrained the 'country'-parameter in a pretty static way. And I have the feeling that is not the way it should be done. Because in the end I would like to have URLS that look like this '/united-kingdom', '/france', but now they're looking like this '/United%20Kingdom'.
I saw the answers to this question Laravel clean links without spaces or uppercase , but for me they're not so useful since I'm not working with Eloquent models but the Query Builder (The db tables I get are ready made, I only have to display them).
So my questions are:
How to limit a route parameter more dynamically?
How to display data one way (written like it's also in the table like this 'United Kingdom'), but have a route like this ('united-kingdom')?
I am willing to provide more code or info if you need, I'm just pretty confused and have the feeling I'm overlooking something (big).
Thank you for your time and help!
If you would like a route parameter to always be constrained by a
given regular expression, you may use the pattern method. You should
define these patterns in the boot method of your RouteServiceProvider:
use Illuminate\Support\Facades\DB;
//...
/**
* Define your route model bindings, pattern filters, etc.
*
* #return void
*/
public function boot()
{
$list_of_countries = DB::table('members')->whereNotNull('country')->pluck("country")->unique()->map(function ($name) {
return str_slug($name, '-');
})->reject(function ($name) {
return empty($name);
})->toArray();
$regex = '(' . implode('|', $list_of_countries) . ')';
Route::pattern('{country-slug}', $regex);
parent::boot();
}
routes\web.php
Route::get('/{country-slug}', 'PageController#show')->name('country');
Docs
I am using Symfony and need to compare to variables from my database called $voorraad and $minimumvoorraad. I need to see the product when $voorraad is lower than $minimumvoorraad. Since I am using Symfony we use the PHP language. I've tried the FindByVoorrad and FindOneBy statements with no success, I only get the header from my twig but that's it.
Thanks in advance.
Given your Entity consists of whatever fields including 'voorraad' and 'minimumvoorraad', you should be able to get your database table's content via
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT e
FROM AppBundle:Entity e
WHERE e.voorraad < e.minimumvoorraad'
);
$products = $query->getResult();
Edit: the e in the query is a SQL-typical alias defined inline.
And then treat your $products variable as usual, where you can use all of your getters and setters.
After rendering and passing your products to the Twig view
return $this->render('view.html.twig', array(
'products' => $products
));
you could then proceed to print the products, for example, in a table inside your Twig view:
<table>
{% for product in products %}
<tr>
<td>{{ product.id }}</td>
<td>{{ product.voorraad }}</td>
<td>{{ product.minimumvoorraad }}</td>
</tr>
{% endfor %}
</table>
I am using a hasMany in my Model class to retrive the clients notes, how ever i want to order these notes by the latest date created in laravel blade template.
My code is below and im getting an error on this.
Please advice me..
#foreach($clients->notes->orderBy('created_at', 'desc') as $note)
<table class="table table-bordered">
<tr>
<td class="col-xs-2 col-md-2"><b>Created On:</b> {{ date('d/m/y', strtotime($note->created_at)) }} <b>#</b> {{ date('g:i A', strtotime($note->created_at)) }} </td>
<td class="col-xs-14 col-md-12">{{ $note->notes }}</td>
</tr>
</table>
#endforeach
Guessing, because you haven't told us what error you're getting, but:
$clients->notes is an already-fetched collection of results. $clients->notes() is a query builder that you can apply further logic like ordering or additional criteria to.
You likely want:
$clients->notes()->orderBy('created_at', 'desc')->get()
but you should do that in the controller and pass it to the view instead of having the query directly in the Blade template.
(You can alternatively use Laravel's collection functions on $clients->notes, including the sortBy() function).
Data must be ordered within controller or models. If you have used hasMany validation in model you can do as mentioned below
In model write association
public function notes()
{
return $this->hasMany('Note')->orderBy('created_at', 'desc');
}
In your controller function associate client with notes like this
$clients = Client::with('notes')->get();
Hope you get your answer