Laravel query with multiple 'with' statements - sql

I'm not sure if there's a a way of doing this but I would like to add a where clause to the second with in my query but it doesn't work. It just returns all the votes as if the condition wasn't there. Any help would be appreciated.
public function PostId($request)
{
$post_id = $request->post_id;
$user_id = auth('api')->user();
$post = Post::with('categories')
->where('id', $post_id)
->with('votes')
->where('user_id', $user_id->id)
->first();
return $post;
}

You need to use closure in your with statement.
Also, I'd recommend using findOrFail() instead of where conditional for your query. Therefore, in case you pass a wrong post_id in your request an exception 404 will be thrown.
A nicer way to accomplish what you want could be:
public function PostId($request)
{
$post = Post::with(['categories', 'votes' => function($query){
$query->where('user_id', auth('api')->user()->id);
})
->findOrFail($request->post_id);
return $post;
}

$post = Post::find($post_id) // Find method will return only first record. no need to call ->first() explicitly.
->with([
'categories',
'votes'
])
For the ->where('user_id', $user_id->id), you dont need to do it in here as you already have defined the relation 'votes'.
Class Post
{
public function votes()
{
return $this->hasMany(Vote::class)->where('user_id', $this->user_id); // You can have the where condition here assuming you have user id field present in the Post model. Else you can keep it as below in your query
}
}
With user id in the runtime query
$post = Post::find($post_id)
->with([
'categories',
'votes' => function($query) use($user_id) {
$query->where('user_id', $user_id->id);
}
])

Related

laravel Show only related data in search filter

I am trying to create a search filter:
if ($request->has('street')) {
$streets->where('name', 'like', '%'.$request->street.'%');
}
if ($request->has('house')) {
$streets->whereHas('properties', function ($query) use ($request) {
$query->where('house_number', $request->house);
});
}
return $streets->get();
This currently gets the street data. I want to do something like this ?street=b-34&house=21 and to display the house data.
At the moment I am only getting the street data.
Your problems seems one every Laravel developer will go through one day. You forgot to return the query to the original constructor.
You have:
$streets->where('name', 'like', '%'. request('street') .'%');
when you should have:
$streets = $streets->where('name', 'like', '%'. request('street') .'%');
You are chaining the methods so you should have it return the original query constructor
EDIT Based on comments:
Besides from not returning the query as I stated above you are using whereHas as #thisiskelvin have pointed out in his answer.
You should be using
if (request()->has('street')) {
$streets = $streets->where('name', 'like', '%'. request('street') .'%');
}
if (request()->has('house')) {
$streets = $streets->with(['properties' => function ($query) {
$query->where('house_number', request('house'));
}]);
}
return $streets->get();
You should be able to achieve this by using the ->with() eloquent method. If the request has a house query, it will return all properties where the house_number equals the queried house number. Once found will attach to the returned results:
if (request()->has('street')) {
$streets = $streets->where('name', 'like', '%'. request('street') .'%');
}
if (request()->has('house')) {
$streets = $streets->with(['properties' => function ($query) {
$query->where('house_number', request('house'));
}]);
}
return $streets->get();
Note: I have changed $request to use the request() helper.

Eloquent filtering with multiple parameters

I am writing a search functionality which basically looks up several tables.
The DB structure and relationships are as follows:
`users`
id
name
user_type_id
`user_type`
id
type
`user_nicknames`
id
user_id
nickname
User model has a \Illuminate\Database\Eloquent\Relations\BelongsTo relationship with user_type
and a \Illuminate\Database\Eloquent\Relations\HasMany relationship to user_nicknames
What I am trying to get is search against a specific searchTerm which can be found either in users table and in user_nicknames
This one is failing right now:
$user = $this->user->newQuery();
$user->whereHas('userType', function ($query) use ($filters) {
$query->where('type', $filters['type']);
});
$user->whereHas('userNickName', function ($query) use ($searchTerm) {
$query->where('custom_title', 'like', '%'.$nickname.'%');
});
Please take note that I'd prefer to use the eloquent relationships for this rather than multiple joins.
Any ideas?
In your User model add these functions:
public function scopeUserTypeFilter($query, $filters)
{
return $query->whereHas('user_type', function ($query) use ($filters) {
$query->where('type', $filters['type']);
});
}
public function scopeNicknameFilter($query, $nickname)
{
return $query->whereHas('user_nick_name', function ($query) use ($searchTerm) {
$query->where('custom_title', 'like', '%'.$nickname.'%');
});
}
Then you can use these on your controller:
public function search(Request $reqeust)
{
$users = User::where(function ($query) use ($request) {
return $query->when($request->filled('s'), function($query) use ($request) {
return $query->nicknameFilter($request->s);
});
})->where(function ($query) use ($request) {
return $query->when($request->filled('userType'), function($query) use ($request){
return $query->userTypeFilter($request->userType);
});
})->get();
}

Yii2 Sort multiple parameters URL

I have an endpoint in yii2 where I need to sort by multiple parameters. Im using ActiveDataProvider. This is the enpdoint:
public function actionIndex($client)
{
$sort = new Sort([
'attributes'=> ['name','mail','crdate']
]);
$query = Customer::find()
->andWhere(['client' => $client])
->orderBy($sort->orders);
$provider = new ActiveDataProvider(['query' => $query]);
return $provider->getModels();
}
Now sorting by a single parameter as in: customers?client=1&sort=mail works fine.
I want to sort by multiple parameters though. How should I do this in the url?
Set
$sort = new Sort([
'attributes'=> ['name','mail','crdate'],
'enableMultiSort' => true,
]);
Now you can pass multiple sort column by separating them with , like
?sort=name,mail
If you prepend name with - you get descending order otherwise it's ascending.
If you want to change , separator to something else set it in separator configuration key for Sort object.
You should try search model for Costumer model
public function search($params)
{
$query = Costumer::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
$query->andFilterWhere([some condition for search]);
return $dataProvider;
}

Eloquent select all children and sort them by order

I have problem write correct select with ordering for my Page table.
Actual implementation:
private function findPageBySlug($slug)
{
$page = Page::with('children')
->where('active', 1)
->where('slug', $slug)
->first();
if (property_exists($page, 'chidlren')) {
return $page->whereHas('children', function ($child) {
return $child->where('active', 1)->orderBy('order', 'asc');
});
} else {
return $page;
}
}
I need select all child of Page and order them by order column and also children can have another child and so on is no restriction to deepth.
Is posible to write select for this?
Thanks for your help
If you want to get all children and not filter pages by children, use with(). Instead of:
return $page->whereHas('children', function ($child) {
return $child->where('active', 1)->orderBy('order', 'asc');
});
Do:
return $page->with(['children' => function ($child) {
return $child->where('active', 1)->orderBy('order', 'asc');
}]);
If you want bith filter and load children, chain both wherHas() and with()

Is my order complete return approach correct?

When a customer is returned to the following URL (example);
http://prestashop.dev/index.php?action=completed&controller=callback&fc=module&hmac={valid-hmac}&merchant_order_id=14&module=chippin
After a successful payment, It will call on this FrontController sub-class;
class ChippinCallbackModuleFrontController extends ModuleFrontController
{
public function postProcess()
{
$chippin = new Chippin();
$payment_response = new PaymentResponse();
$payment_response->getPostData();
// if a valid response from gateway
if(ChippinValidator::isValidHmac($payment_response)) {
// "action" is passed as a param in the URL. don't worry, the Hmac can tell if it's valid or not.
if ($payment_response->getAction() === "completed") {
// payment_response->getMerchantOrderId() will just return the id_order from the orders table
$order_id = Order::getOrderByCartId((int) ($payment_response->getMerchantOrderId()));
$order = new Order($order_id);
// this will update the order status for the benefit of the merchant.
$order->setCurrentState(Configuration::get('CP_OS_PAYMENT_COMPLETED'));
// assign variables to smarty (copied this from another gateway, don't really understand smarty)
$this->context->smarty->assign(
array(
'order' => $order->reference,
)
);
// display this template
$this->setTemplate('confirmation.tpl');
I'm quite new to Prestashop. I'm just not sure if this is technically done or not. The confirmation.tlp view does display with the order->reference and the order status is updated to "Completed" but is this all I need?
Are there any other considerations? I have the opportunity to call a hookDisplayPaymentReturn at this point but why should I?
I seem to have a pretty standard return page. Is this enough;
Update - Do I just call a hook something like;
public function displayPaymentReturn()
{
$params = $this->displayHook();
if ($params && is_array($params)) {
return Hook::exec('displayPaymentReturn', $params, (int) $this->module->id);
}
return false;
}
As far as I can see everything seems okay for me.
You should consider adding hookDisplayPaymentReturn it allows other modules to add code to your confirmation page. For example a Google module could add javascript code that sends order informations to analytics on confirmation page.
EDIT
class ChippinCallbackModuleFrontController extends ModuleFrontController
{
public function postProcess()
{
$chippin = new Chippin();
$payment_response = new PaymentResponse();
$payment_response->getPostData();
// if a valid response from gateway
if(ChippinValidator::isValidHmac($payment_response)) {
// "action" is passed as a param in the URL. don't worry, the Hmac can tell if it's valid or not.
if ($payment_response->getAction() === "completed") {
// payment_response->getMerchantOrderId() will just return the id_order from the orders table
$order_id = Order::getOrderByCartId((int) ($payment_response->getMerchantOrderId()));
$order = new Order($order_id);
// this will update the order status for the benefit of the merchant.
$order->setCurrentState(Configuration::get('CP_OS_PAYMENT_COMPLETED'));
// assign variables to smarty (copied this from another gateway, don't really understand smarty)
$this->context->smarty->assign(
array(
'order' => $order->reference,
'hookDisplayPaymentReturn' => Hook::exec('displayPaymentReturn', $params, (int) $this->module->id);
)
);
$cart = $this->context->cart;
$customer = new Customer($cart->id_customer);
Tools::redirect('index.php?controller=order-confirmation&id_cart='.$cart->id.'&id_module='.$this->module->id.'&id_order='.$order->id.'&key='.$customer->secure_key);
And in your module :
class myPaymentModule extends PaymentModule
{
public function install()
{
if (!parent::install() || !$this->registerHook('paymentReturn'))
return false;
return true;
}
// Example taken from bankwire module
public function hookPaymentReturn($params)
{
$state = $params['objOrder']->getCurrentState();
$this->smarty->assign(array(
'total_to_pay' => Tools::displayPrice($params['total_to_pay'], $params['currencyObj'], false),
'bankwireDetails' => Tools::nl2br($this->details),
'bankwireAddress' => Tools::nl2br($this->address),
'bankwireOwner' => $this->owner,
'status' => 'ok',
'id_order' => $params['objOrder']->id
));
if (isset($params['objOrder']->reference) && !empty($params['objOrder']->reference))
$this->smarty->assign('reference', $params['objOrder']->reference);
return $this->display(__FILE__, 'confirmation.tpl');
}
}