Laravel SUBSTRING on Eloquent query - mysql

Question
How do I put a limit on one of the rows in an Eloquent result?
Scenario
I need to retrieve only around 100 characters from one of the fields in my result. Currently I'm using a join statement so multiple results are being returned. I basically need only the first 100 characters from post.content
Code
public function getAll()
{
return Post::select('posts.id', 'posts.title', 'posts.content', 'posts.views', 'posts.comments', 'posts.tags', 'posts.date_created', 'users.image_url', 'users.username', 'users.toxick')
->join('users', 'posts.user_id', '=', 'users.id')
->get();
}
I'm not sure how to go about putting a filter on the query to only return 100 characters. I've looked around briefly but I've not found anything useful, not to my specific scenario at least.

Cant test this at the moment (sorry) but what about:
public function getAll(){
$query = Post::select('posts.id', 'posts.title', 'posts.content','posts.views', 'posts.comments', 'posts.tags', 'posts.date_created', 'users.image_url', 'users.username', 'users.toxick')
->join('users', 'posts.user_id', '=', 'users.id')
->get();
foreach($query as $entries){
$entries->content = substr($entries->content, 1, 100);
}
return $query;
}

Related

Laravel join use to get one to many relations?

Is there any way to get relational data ( one to many relation records ) using joins in laravel without creating different records in collection :
Example:
$orders = DB::table('orders')
->join('users', 'users.id', '=', 'orders.users_id')
->join('order_items', 'order_items.order_id', '=', 'orders.id')
->select('users.*', 'order_items.*')
->get();
So here what's happening is that its creating 6 records if order has 6 items but i want something like single records in which it has array or collection where are order items are listed.
Output I want is generally of this order:
Collection {# ▼
#items: array:[▼
0 => {
+'id':1,
...,
+ 'items: [
//here i want all the records of relation order items
]
}
]
}
Is there any way to achieve this result without using with() or load() and just only with joins or raw queries?
You should try this:
$orders = DB::table('orders')
->select('users.*', 'order_items.*')
->leftJoin('users', 'users.id', '=', 'orders.users_id')
->leftJoin('order_items', 'order_items.order_id', '=', 'orders.id')
->get();
This answer is speculative, but perhaps you want to report a single row for each user, with a CSV list of order items:
$orders = DB::table('orders AS o')
->join('users AS u', 'u.id', '=', 'o.users_id')
->join('order_items AS oi', 'oi.order_id', '=', 'o.id')
->select('u.id', DB::raw('GROUP_CONCAT(oi.name) AS orders'))
->groupBy('u.id')
->get();
If there's no reason stopping you from using the Eloquent, is the best way for working with databases.
The Eloquent ORM included with Laravel provides a beautiful, simple
ActiveRecord implementation for working with your database
Here is the Documentation Eloquent: Getting Started
The model relationship made easy in laravel, you can get you want as following:
The User model relationships:
//user orders
public function orders() {
return $this->hasMany('App\Order');
}
The Order model relationships:
//order items
public function items() {
return $this->hasMany('App\OrderItem');
}
//order owner
public function user() {
return $this->belongsTo('App\User');
}
The OrderItem model relationships:
//order
public function order() {
return $this->belongsTo('App\Order');
}
Here is a quick example of how you may get the order's items
$orders = User::find($id)->orders
foreach($orders as $order) {
$orderItems = $order->items;
}
you can make the collection the way you prefer, but strongly recommend using Eloquent Resources, since most apps these days expecting JSON responses.

Laravel Query Builder - where clause equals anything programmatically

I'm using Laravel 5.6 - Query Builder.
Is it possible to make a query builder where statement that a value equals everything programmatically?
Let's say that I have this code:
$foo = 1;
DB::table('users')
->select('*')
->where('status', '=', $foo)
->get();
If $foo = 1 then it's straightforward. The query will select everything with the status of 1.
Q: Is it possible to assign something to the $foo variable so the select query returns every record regardless of the status from the DB?
Of course, I can make it happen with 2 query statements like this:
$foo = 1;
if ($foo === null) {
DB::table('users')
->select('*')
->get();
} else {
DB::table('users')
->select('*')
->where('status', '=', $foo)
->get();
}
However, I'm looking for a shorter / more effective solution. Is it possible somehow - without using raw code inside the Where statement?
You may try something like this:
$query = DB::table('users')->select('*');
// $foo = 'get it...';
if ($foo) {
$query->where('status', $foo);
}
$result = $query->get();
Or even more laravel-ish:
$result = DB::table('users')->select('*')
->when($foo, function ($query) use ($foo) {
return $query->where('status', $foo);
})
->get();
Check more here.

Laravel 5.4 Raw Join Query

I have a table TBL_POST used to store blog posts. A post can be assigned to multiple categories, there is a column, cat_id that stores category ID's in comma separated pattern like 2,4,6. I want to use FIND_IN_SET() method in this line
->leftJoin(TBL_CAT.' as c', 'p.cat_id', '=', 'c.id')
to show the associated category names. How can I do that?
public static function getPostWithJoin($status="")
{
$query = DB::table(TBL_POST .' as p')
->select('p.id','p.post_title','p.post_status','u.name as author','c.name as cat_name','p.updated_at')
->leftJoin(TBL_ADMINS.' as u', 'p.post_author', '=', 'u.id')
->leftJoin(TBL_CAT.' as c', 'p.cat_id', '=', 'c.id')
->where('p.post_type','post');
if($status!="all") {
$query->where('p.post_status',$status);
}
$query->orderby('p.id','DESC');
$data = $query->paginate(20);
return $data;
}
You can use callback to create more complicated join query.
->leftJoin(TBL_CAT, function($query){
$query->on(TBL_CAT.'id', '=', 'p.cat_id')->where("**", "**", "**");
})
Here is link on laravel doc - https://laravel.com/docs/5.4/queries#joins "Advanced Join Clauses" section.
UPD::
As mentioned in comment it is not good idea to have string for such types of data. Cause search by equality should be much simpler than string check. Even if your amount of data should not have big difference, you never know what will happen with your app in future.
But if you still want to do that i think you can try like this
->leftJoin(TBL_CAT, function($query){
$query->where(DB::raw("FIND_IN_SET(".TBL_CAT.".id, p.cat_id)"), "<>", "0");
})
Join that will check existence of id in cat_id.

MYSQL QUERY multiple tables count

I am having problems building a query which delimit the number of lawyers by branch of law in one particular territory(province) of the country.
I have four tables, one with the branchlaws, one for users, one where lawyers add branches where the practice law and one for territories.
I am able to summarize all this information with the following query:
$lawyersbyprovince = DB::table('branchlawsubareas')
->leftJoin('lawyerbranches', function($join) {
$join->on( 'branchlawsubareas.id', '=', 'lawyerbranches.subarea_id');
})
->leftJoin('users', function($join) {
$join->on( 'lawyerbranches.user_id', '=', 'users.id');
})
->leftJoin('states', function($join) {
$join->on('users.working_province', '=', 'states.id_state');
})
->leftJoin('branchlaws', 'branchlawsubareas.area_id', '=', 'branchlaws.id')
->select('branchlawsubareas.name as subarea',
DB::raw('count(lawyerbranches.subarea_id) as total'),
'branchlawsubareas.id'
)
->where('states.id_state','=', $province)
->groupBy('branchlawsubareas.id')
->get();
This query returns the number of lawyers per branch of law but it does not delimit by province. I have spent enough time trying things but obviously I missing something.
Any help will be much appreciated.
Try not to join instead the states of leftjoin.
$lawyersbyprovince = DB::table('branchlawsubareas')
->leftJoin('lawyerbranches', 'branchlawsubareas.id', '=', 'lawyerbranches.subarea_id')
->leftJoin('users', 'lawyerbranches.user_id', '=', 'users.id')
->leftJoin('branchlaws', 'branchlawsubareas.area_id', '=', 'branchlaws.id')
->join('states', 'users.working_province', '=', 'states.id_state')
->where('states.id_state','=', $province)
->select('branchlawsubareas.name as subarea',
DB::raw('count(lawyerbranches.subarea_id) as total'),
'branchlawsubareas.id'
)
->groupBy('branchlawsubareas.id')
->get();
Now if this does not work, you have another way. Remove where() clause and change your select like this
...
->select(''branchlawsubareas.id', 'states.id as state_id')
...
This will return a collection with ALL the data. Then you can manipulate that collection like this
$newCollection = $resultFromQuery->where('state_id', $province);
$newCollection->count(); //number of laywer in that state
I hope this helps, or simply gives you a hint.

Retrieve data from one table and order by related table column using Laravel eloquent

I have two models Category and Transaction the table structures are like this
Categories:
id,category_name,..
and
Transactions:
id,category_id,amount..
The relation is
Category hasMany transactions
public function transactions()
{
return $this->hasMany('App\Transaction');
}
Transactions blongsTo Category
public function category()
{
return $this->belongsTo('App\Category', 'category_id');
}
I want to retrieve all data of transaction table which are sorted by category name.
Most importantly I want to get it using the eloquent method.
I have tried eager load which I think doesn't work on the belongsTo relationship.
Here is the code I have used for the eager load.
$transactions = Transaction::with(['category' => function ($query) {
$query->orderBy('category_name', 'asc');
}])->paginate(10);
So far I can achieve this by writing a query like below, but I'd like to use the eloquent method.
$transactions = Transaction::select(DB::raw('transactions.*'))
->leftJoin(DB::raw('(select id,category_name from categories) as categories'), 'categories.id', '=', 'transactions.category_id')
->orderBy('category_name', 'asc')
->paginate(10);
It'd be nice if someone can help me with this. Thank You.
Note: I am using Laravel 5.1
You have to provide the method name that defines the relationship, in your case this is category.
$transactions = Transaction::all()->with('category')->group_by('category.name')->get();
$transactions = Transaction::with('categories')->group_by('category.name')->get();
$cs = Course::where(['courses.active' => 1])
->whereHas('course_dates', function ($join) use ($now) {
$join->where('course_dates.start_date_time', '>', $now);
$join->orderBy('course_dates.start_date_time', 'asc');
})
->whereHas('category', function ($join) use ($cat_slug) {
$join->where('categories.url_slug', '=', $cat_slug);
})
->whereHas('language', function ($join) use ($cat_slug) {
$join->where('languages.string_id', '=', strtoupper(App::getLocale()));
})
->with(['course_dates' => function($q){
$q->orderBy('course_dates.start_date_time', 'desc');
}])
->join('course_dates' ,'course_dates.course_id', '=', 'courses.id')
->orderby('course_dates.start_date_time')
->limit(7)
->get();
To return Eloquent models ordered by related model (hasMany) column, I had to join the tables and then orderBy, still get the models, but correctly ordered by course_date.start_date_time.
Laravel 5.7, I don't think there is a cleaner solution (at least after few hours of tinkering and searching the web).