I am posting Laravel 5.2 real life routing use case and would like to have an answer for it. Problem: same url structure for multiple different database lookups. Please do not post remarks on how to make easier URL structure, this is the way the structure must be and many sites use it in this segment.
URL structure
domain.com/{slug1}/{slug2}/{slug3}
// e.g. domain.com/cottages/slovakia/cheap
// {slug1} - DB table accommodation_types (20+)
// {slug2} - DB table locations (300+)
// {slug3} - DB table accommodation_categories e.g. cheap etc. (100+)
domain.com/{slug1}/{slug2}
// e.g. domain.com/cottages/cheap OR domain.com/slovakia/cheap
// {slug1} - DB table accommodation_types OR locations
// {slug2} - DB table locations OR accommodation_categories
domain.com/{slug}
// DB table accommodation (10000+ entries)
// or
// accommodation_types OR locations OR accommodation_categories
How would you do it nicely? I have these ideas.
a. Use closure and call appropriate controller after examining url segments?
Route::get('{slug1}', function ($slug1, $slug2 = null, $slug3 = null)
{
// Check accommodation
$object = Accommodation::where('slug', $slug1)->first();
if( !is_null($object) )
{
return app()->make('AccommodationDetailController')->view($object);
}
// Check type
$type = AccommodationType::where('slug', $slug1)->first();
if( !is_null($type) )
{
return app()->make('AccommodationListController')->view($type);
}
// etc.
});
b. Generate thousands of urls by for loop and cache it then?
I appreciate any other great solution
I think the best way is to send all these routes to the same controller action and edit your query according to the parameters that are sent.
For example, this would be your routing file:
<?php
Route::get('{slug1}', 'Controller#getPage');
Route::get('{slug1}/{slug2}', 'Controller#getPage');
Route::get('{slug1}/{slug2}/{slug3}', 'Controller#getPage');
In the controller, you can use Eloquent or the query builder to build the sql query according to the variables you received from the route. Below is a simple example:
<?php
class Controler {
public function getPage($slug1, $slug2 = null, $slug3 = null) {
$models = Model::where(function ($query) use ($slug1) {
$query->where('accomodation_types', $slug1)
->orWhere('location', $slug1);
})
->where(function ($query) use ($slug2) {
if (isset($slug2)) {
// Slug2 query
}
})
->where(function ($query) use ($slug3) {
if (isset($slug3)) {
// Slug3 query
}
})
->get();
}
}
Related
I have an Orders table that has relations to a Movements table, and im constantly doing things like this to calculate several common values for each order:
$warehouse = 7;
$order = Order::find(16111);
$entries = Movement::selectRaw("SUM(gross) AS total_gross")
->selectRaw("SUM(net) AS total_net")
->selectRaw("SUM(qty) AS total_qty")
->where('order_id', $order->id)
->where('to_id', $warehouse)
->first();
$exits = Movement::selectRaw("SUM(gross) AS total_gross")
->selectRaw("SUM(net) AS total_net")
->selectRaw("SUM(qty) AS total_qty")
->where('order_id', $order->id)
->where('from_id', $warehouse)
->first();
is it possible to create a custom function to just query the DB doing something like this:
$warehouse = 7;
$entries = Order::find(16111)->entries($warehouse);
$exits = Order::find(16111)->exits($warehouse);
If so how can it be done?
Thanks for your help...
Absolutely. What you are looking for is called local Query Scopes; it allows you to avoid repeating complexe queries in your code.
Local scopes allow you to define common sets of query constraints that you may easily re-use throughout your application.
Write your local query scope in your model and you'll never have to repeat this code again (DRY principle).
Here's an example to give you an idea, you'll need to tweak it to your needs.
In your Order model:
public function scopeEntries($query)
{
$warehouse = $this->warehouse; // Take advantage of Eloquent wherever you can
return $query->movements()->selectRaw("SUM(gross) AS total_gross")
->selectRaw("SUM(net) AS total_net")
->selectRaw("SUM(qty) AS total_qty")
->where('to_id', $warehouse->id);
}
public function scopeExits($query)
{
$warehouse = $this->warehouse; // Take advantage of Eloquent wherever you can
return $query->movements()->selectRaw("SUM(gross) AS total_gross")
->selectRaw("SUM(net) AS total_net")
->selectRaw("SUM(qty) AS total_qty")
->where('from_id', $warehouse->id)
->where('to_id', $warehouse->id);
}
Now in your code, you will be able to simply call $order->entries()->first() to retrieve the first entry but you can also call $order->exits()->get() to retrieve all exits.
public function getTourDetail(Request $req)
{
//Get link detail
$tour = Tour::where('id',$req->id)->first();
//I want to take location.city of the location table
$detail = Tour::join('location','tour.id_location','=','location.id')
->whereColumn([
['tour.id_location','=','location.id']
])
->get(array(
'tour.id as id_tour',
'location.image',
'tour.name',
'tour.id_location',
'location.city'
));
return view('page.tour-detail',compact('tour','detail'));
}
I would like to be able to combine two query statements to get information from the location table ($ detail) like the id of the link request ($ tour).
Since you use models, you can use Eloquent relationships to load related data. First, define a relationship in the Tour model:
public function location()
{
return $this->belongsTo(Location::class, 'id_location')
}
Then load Tour and get related location:
$tour = Tour::find($req->id);
$relatedLocation = $tour->location;
First thing, if you are using model then using eloquent relationship will be a better idea to deal with the situation like yours. But if you want to join your table then this will be the way:
public function getTourDetail($id)
{
$tour = Tour::where('id',$id)->first();
//I want to take location.city of the location table
$detail = DB::table('location')
->join('tour','tour.id_location','=','location.id')
->select(
'tour.id as id_tour',
'location.image',
'tour.name',
'tour.id_location',
'location.city'
)->get();
return view('page.tour-detail',compact('tour','detail'));
}
Note: if you are getting id from submitted form then replace first portion of the code with:-
public function getTourDetail(Request $request)
{
$tour = Tour::where('id',$request->id)->first();
So I have this sub-window created and I want to put customer details.
At first, opening the sub-window(without using the search boxes) it returns data, but the data from another database cannot be shown.
Now when I use the search box, it now gives me error of: undefined variable paymentgroup.
first database is: clotho_mercurop_laravel
The other database is: clotho_mercurop_eccube
I suppose my query is wrong but I don't know how to fix.
Here is my code:
public function index_sub_form(Request $request)
{
$keyword = $request->all();
$perPage = 25;
if($keyword) {
$paymentgroup = TPaymentGroup::select('t_payment_group.id',
't_payment_group.payment_group_name',
DB::raw('clotho_mercurop_eccube.getfullAdd(eccube.customer_id) as getAdd'),
't_payment_group.main_customer_id',
'eccube.name01',
'eccube.name02')
->join(\DB::raw('clotho_mercurop_eccube.dtb_customer as eccube'), function($j) {
$j->on('t_payment_group.main_customer_id', '=', DB::raw('eccube.customer_id '));
});
if ($keyword['グループ名']) {
$paymentgroup->where('m_item_detail_category.item_detail_category_name', 'like', '%'.$keyword['グループ名'].'%');
}
if($keyword['代表支払者']) {
$paymentgroup->where('m_item_category.item_category_name', 'like', '%'.$keyword['代表支払者'].'%');
}
$paymentgroup = $paymentgroup->paginate($perPage);
} else {
$paymentgroup = TPaymentGroup::paginate($perPage);
}
return view('pop_up.paygroup_sub_form', compact('paymentgroup'));
}
The following website explains the use of multiple database connections in Laravel: Fideloper: Multiple DB connections in Laravel.
Currently, you're using clotho_mercurop_laravel and clotho_mercurop_eccube as tables, not as databases. Is that correct?
I have collection that created with complicated laravel query and this query's result is too big. So i think i must use algolia. As i know, algolia gets the model table data to itself as json and serve from there.
$result = User::search("UserName")->get();
It needs to some model configurations like searchAs etc.. all are related with existing model and you can make search from model with search method (above example). What i want to ask is, i have complicated query and result has too many attributes that come from another tables (joined). I want to make search on my custom query result. Is it possible ?
My example query :
$friendShips = Friend::
join("vp_users as users","users.id","=","friendships.friendID")
->leftJoin("vp_friendships as friendshipsForFriend",function($join) use ($request)
{
$join->on("friendships.friendID","=","friendshipsForFriend.userID");
$join->on("friendshipsForFriend.friendID","=",DB::raw($request->userID));
})
->leftJoin("vp_videos_friends as videosFromFriendMedias",function($join)
{
$join->on("videosFromFriendMedias.userID","=","friendships.friendID");
$join->on("videosFromFriendMedias.friendID", "=" ,"friendships.userID");
$join->on("videosFromFriendMedias.isCalled", "=" , DB::raw(self::CALLED));
})
->leftJoin("vp_videos_friends as videosToFriendMedias",function($join)
{
$join->on("videosToFriendMedias.userID", '=', "friendships.userID");
$join->on("videosToFriendMedias.friendID", '=', "friendships.friendID");
$join->on(function($join){
$join->on("videosToFriendMedias.isCalled", '=', DB::raw(self::CALLED));
$join->orOn("videosToFriendMedias.isActive", '=', DB::raw(self::ACTIVE));
});
})
->leftJoin("vp_videos_friends as
//some join rules too
})...
I believe the best way would be to use this request and chain the searchable() method. It will index the collection returned by the query to Algolia.
$friendShips = Friend::
join("vp_users as users","users.id","=","friendships.friendID")
->leftJoin("vp_friendships as friendshipsForFriend",function($join) use ($request) {
$join->on("friendships.friendID","=","friendshipsForFriend.userID");
$join->on("friendshipsForFriend.friendID","=",DB::raw($request->userID));
})
->searchable();
I have a search query that needs to be done. However, a search doesn't always have all values set, like in this case.
$aEvents = DB::table('events')
->where('client_id', '=', $client_id);
The question is, how can I make this where statement depend on the value of $client_id. So if the value is empty I don't want the Where statement to occur.
Also, I do not want to write several complete queries with if statements in PHP. To many variables. Ideally I'd like something like this:
$aEvents = DB::table('events')
->(($client_id != "") ? where('client_id', '=', $client_id) : "");
Using eloquent is (really!) nice and save, but I'm not yet up to speed with if statements in std Class objects I guess. Any help is appreciated.
You may try something like this:
$query = DB::table('events');
if(!empty($client_id)) {
$query->where('client_id', $client_id);
}
$aEvents = $query->get(); // Call this at last to get the result
If you are passing client_id to the server via a form/query string(user input) then you may try something like this:
if($client_id = Input::get('client_id')) {
$query->where('client_id', $client_id);
}
Update: For pagination try this:
$aEvents = $query->paginate(10); // For 10 per page
So you may call links() method in your view if you pass it like this:
return View::make('viewName')->with('aEvents', $aEvents);
In the view for pagination links:
$aEvents->links()
You can also use query scopes in the model for this purpose. Scopes allow you to easily re-use query logic in your models. In the model Event, you can add the following query scope:
public function scopeClientID($query, $client_id)
{
if ($client_id != '') {
return $query->where('client_id', '=', $client_id);
} else {
return $query;
}
}
Then from your controller or wherever you're calling it from, you can do the following:
$aEvents = Event::clientID($client_id);
If you want to get all the results, then you can do:
$aEvents = Event::clientID($client_id)->get();
Or if you want pagination, you can do:
$aEvents = Event::clientID($client_id)->paginate();
You can also chain it with other methods like you'd do in a eloquent query.
You can read more about model query scopes at http://laravel.com/docs/eloquent#query-scopes