Query with date range works when executed directly on Mongo but fails when used from Laravel - laravel-5.5

I have two collections called promotions and coupons
Coupons has promotion._id as reference to promotion collection.
I want to fetch the promotions within a date range. For this, I have two fields valid_from and apply_till.
"valid_from" : ISODate("2018-09-10T06:15:02.000Z"),
"apply_till" : ISODate("2018-10-20T06:15:02.000Z")
This direct MongoDb query works when executed directly:
db.getCollection('coupons').aggregate([
{"$match":{"code":"PYDY25"}},
{"$lookup":{"from":"promotions","localField":"promotion_id","foreignField":"_id","as":"promotion"}},
{"$match":{
"promotion.valid_from":{"$lte": ISODate("2018-09-12 06:31:30")},
"promotion.apply_till":{"$gt": ISODate("2018-09-12 06:31:30")}
}
},
{"$project":{"_id":0,"code":1,"promotion":1}}
])
However when I try to do the same via Laravel it doesn't work. The ISODate formatting is missing in the query generated by Laravel.(Have given the generated query below)
In Laravel:
Promotion Model have:
protected $dates = [
'valid_from',
'valid_till',
'apply_till',
'created_at',
'updated_at'
];
Raw query used for aggregation in Laravel:
// Filter for code.
$aggregateBy[] = [
'$match' => [
'code' => $coupon->code
]
];
// JOINing table (promotion) for coupon table.
$aggregateBy[] = [
'$lookup' => [
'from' => 'promotions',
'localField' => 'promotion_id',
'foreignField' => '_id',
'as' => 'promotion'
]
];
$aggregateBy[] = [
'$unwind' => '$promotion'
];
$currentTime = Carbon::now()->format('Y-m-d\TH:i:s');
//$currentTime = new UTCDateTime((new \DateTime($currentTime))->getTimestamp());
$aggregateBy[] = [
'$match' => [
'promotion.valid_from' => [
'$lte' => $currentTime,
],
'promotion.apply_till' => [
'$gt' => $currentTime,
]
]
];
// SELECT ed fields.
$aggregateBy[] = [
'$project' => [
'_id' => 0,
'code' => 1,
'promotion' => 1,
]
];
\DB::connection('mongodb')->enableQueryLog();
$couponPromotion = Coupon::raw(function ($collection) use ($aggregateBy) {
return $collection->aggregate($aggregateBy);
});
\Log::info(\DB::connection('mongodb')->getQueryLog());
When I add $match condition for promotion.valid_from and/or promotion.apply_till it does not gives the result. My variable $currentTime is working in Model::where() conditions but not working here.
In the log the query generated as:
db.getCollection('coupons').aggregate([
{"$match":{"code":"PYDY25"}},
{"$lookup":{"from":"promotions","localField":"promotion_id","foreignField":"_id","as":"promotion"}},
{"$match":{
"promotion.valid_from":{"$lte":"2018-09-12 06:31:30"},
"promotion.apply_till":{"$gt":"2018-09-12 06:31:30"}}
},
{"$project":{"_id":0,"code":1,"promotion":1}}
])
How can I pass ISODate to the generated query?

Related

Remember me cookie cakephp 4 not working correctly after logout

I’m working with CakePHP 4.
Following the documentation, I set up ‘remember me’ cookie, when I pass login, I see in the browser the CookieAuth controller with correct values for username e password.
Point is that when I logout, I still see the cookie in my browser (it will expires in few days) but I expected username e password input text with precompiled value in the login form.
Is this the correct behaviour?
I tried to get these fields populated but incurred in many different errors related to cookie reading/writing as
Argument 1 passed to Cake\Http\Response::withCookie() must implement interface Cake\Http\Cookie\CookieInterface, string given
This is my code:
in app_local.php:
‘Security’ => [
‘salt’ => env(‘SECURITY_SALT’, ‘string’, //here my random string
],
-in Application.php
$cookies = new EncryptedCookieMiddleware(
[‘CookieAuth’],
Configure::read(‘Security.cookieKey’)
);
and inside getAuthenticationService(ServerRequestInterface $request), after Session and before Form:
$authenticationService->loadAuthenticator(‘Authentication.Cookie’, [
‘rememberMeField’ => ‘remember_me’,
‘fields’ => [
‘username’ => ‘email’,
‘password’ => ‘password’,
],
‘loginUrl’ => ‘/’,
‘cookie’=>[
‘name’=>‘CookieAuth’,
‘expire’=> new DateTime(‘Thu, 31 Dec 20 15:00:00 +0000’)
]
]);
in UsersController, login function
public function login()
{
$this->Authorization->skipAuthorization();
$cookie = [‘email’=>’’, ‘password’=>’’, ‘remember_me’=>0];
if ($this->request->getCookie('CookieAuth')) {
$cookie = $this->request->getCookie('CookieAuth');
debug('cookie');
}
// if remember_me
if($this->request->getData('remember_me') == 1) {
$this->response = $this->response->withCookie(new Cookie('CookieAuth'), $this->request->getData());
}
else {
//$this->Cookie->delete('CookieAuth');
}
$this->set($cookie);
// other code
}
-Templates\Users\login.php:
<?= $this->Form->control('email', ['required' => true]) ?>
<?= $this->Form->control('password', ['required' => true]) ?>
<?= $this->Form->control('remember_me', ['type' => 'checkbox']);?>
<?= $this->Form->submit(__('Login')); ?>
Any help would be really appreciated, thanks.
Ii tried it on version 4.x. It works fine
config/app.php
'Security' => [
'salt' => env('SECURITY_SALT', 'string'), //here my random string
'cookieKey' => env('SECURITY_COOKIE_KEY', 'string'), //here my random string],
Application.php | function middleware
->add(new EncryptedCookieMiddleware(['CookieAuth'],Configure::read('Security.cookieKey')))
Application.php | function getAuthenticationService
$service->loadAuthenticator('Authentication.Cookie', [ 'fields' => $fields, 'cookie' => [ 'name' => 'CookieAuth', 'expires' => (new Time())->addDays(30), ], 'loginUrl' => '/users/login', ]);
<?= $this->Form->control('remember_me', ['type' => 'checkbox']);?>

Customized Reordering/Sorting of a List in Perl in O(n)

I am re-ordering a list.
My OrignalList, INPUT: #lineItems
[
{id=> 'id1', ..},
{id=> 'id2', 'groupId'=>45D,.. },
{id=> 'id3', 'groupId'=>56A, .. },
{id=> 'id4', 'groupId'=>45D, 'isParent'=>1 .. },
{id=> 'id5', ..},
{id=> 'id6', 'groupId'=>56A, 'isParent'=>1.. },
]
In above list, groupId signifies that the item is a part of bundle. GroupId uniquely determines the bundle group. If group Id is not present then its a non bundle item.
Aim - To re-order the list such that all the bundle items should be grouped together with parent item in the starting of every bundle and the incoming order of the bundle and non bundle items (when groupId not present) should remain unchanged.
To sort the list in O(n)
Expected Output:
[
{id=> 'id1', ..},
{id=> 'id4', 'groupId'=>45D, 'isParent'=>1 .. },
{id=> 'id2', 'groupId'=>45D,.. },
{id=> 'id6', 'groupId'=>56A, 'isParent'=>1.. },
{id=> 'id3', 'groupId'=>56A, .. },
{id=> 'id5', ..},
]
Here my Algo:
Create a sortedList of Ids = #sortedLineitemsIds
Use sortedIdsList to form the final sorted list
Code for #1
my $grouIdToLineItemIdMap;
foreach my $lineItem (#$lineItems) {
if(!$lineItem->{'groupID'}) { #non bundle item, add as it is
push #sortedLineitemsIds, $lineItem->{'id'};
} else {
if($lineItem->{'IsParent'} eq 1) {
unshift #{$grouIdToLineItemIdMap->{$groupId}}, $lineItem->{'id'};
} else {
push #{$grouIdToLineItemIdMap->{$groupId}}, $lineItem->{'id'};
}
}
}
push #sortedLineitemsIds, $grouIdToLineItemIdMap; # **[[Question 1]]** This will always add bundle items at the end irrespective of whether it was in starting or end.
Now this will yield sortedLineitemsIds =>
$VAR1 = [
'id1',
'id5',
{
'45D' => [
'id4:',
'id2:'
],
'56A' => [
'id6:',
'id3:'
]
}
];
Code for #2
foreach my $Id (#sortedLineitemsIds) {
if(determineIfSingleIdOrMapOfGroupId) { #**[[Question 2]]**
my $lineItem = grep #lineItems with $Id; #**[[Question 3]]**
push #sortedLineItems, $lineItem;
} else {
my $listOfLineItemsForGroupId = $sortedLineitemsIds->{$Id};
foreach groupLineItemId (#$listOfLineItemsForGroupId) {
my $lineItem = grep #lineItems with groupLineItemId; #**[[Question 3]]**
push #sortedLineItems, $lineItem;
}
}
}
I have now 3 questions marked above at different places in the code:
Question 1 -> Here I dont want to change the incoming order of
items. Just group them. But what I am doing is it is pushing all the
lineItems of the group in map, which I am appending at end after the
loop. How can I can do that in the loop to preserve that order?
Question 2 -> How can I determine whether it is a single Id (non
bundle id) or a groupID (basically a ref containing the
lineItemIds)?
Question 3 -> How can I grep the orginal list based on
the 'id' and get the corresponding lineItem?
You say you don't want to change the order of the items, but that's clearly not true. I'm going to assume you meant this:
I want to preserve the relative order of items which are either independent or the first of their group.
This can indeed be done in O(N).
We're going to build this:
my #grouped = (
[ $lineItem_id1 ],
[ $lineItem_id4, $lineItem_id2 ],
[ $lineItem_id6, $lineItem_id3 ],
[ $lineItem_id5 ],
);
To achieve that, we're going to use the following algorithm:
For each item,
If the item is independent,
Add it to #grouped.
Else,
Lookup if we've encountered the item's group before.
If the item is part of a group we haven't encountered before,
If it's the parent,
Add it to start of the existing group.
Else,
Add it to end of the existing group.
Else,
Create a new group from the item.
Add the new group to #grouped.
Add the new group to the lookup hash.
At the end of this, we'll end up with the following:
my $group_45D = [ $lineItem_id4, $lineItem_id2 ];
my $group_56A = [ $lineItem_id6, $lineItem_id3 ];
my %groups = (
'45D' => $group_45D,
'56A' => $group_56A,
);
my #grouped = (
[ $lineItem_id1 ],
$group_45D,
$group_56A,
[ $lineItem_id5 ],
);
Solution:
my #grouped;
{
my %groups;
for my $lineItem (#$lineItems) {
if ( my $groupId = $lineItem->{groupId} ) {
if (!$groups{$groupId}) {
push #grouped, $groups{$groupId} = [];
}
if ($lineItem->{isParent}) {
unshift #{ $groups{$groupId} }, $lineItem;
} else {
push #{ $groups{$groupId} }, $lineItem;
}
} else {
push #grouped, [ $lineItem ];
}
}
}
Finally, we simply need to flatten the list.
my #ordered = map { #$_ } #grouped;
Tested.

How to add additional variables to an existing template config in Drupal 8?

I have one theme config in one module.
/**
* Implements hook_theme().
*/
function module1_context_theme($existing, $type, $theme, $path) {
return [
'custom_theme' => [
'template' => 'custom_theme',
'variables' => [
'var1' => NULL,
'var2' => NULL,
],
],
];
}
I want to add an extra variable to the theme config via other module.
How can I do that ?
You can use HOOK_theme_registry_alter to alter this. Try the below code.
/**
* Implements hook_theme_registry_alter
*/
function my_module_theme_registry_alter(&$theme_registry) {
$theme_registry['custom_theme']['variables'][] = 'var3';
}

dd/mm/yyyy format date validation in yii2

I would like to validate date field to accept only (dd/mm/yyyy) format, for example
(14/11/1993)
In addition if the month is February it should not accept day 30 and 31. Please help any one, I've already tried with the pattern below but it's not working in Yii 2. It shows error in RegularExpressionValidator.php
[
['dateofbirth'],
'match',
'pattern' => '/^((([1-2][0-9])|([1-9]))/([2])/[0-9]{4})|((([1-2][0-9])|([1-9])|(3[0-1]))/((1[0-2])|([3-9])|([1]))/[0-9]{4})$/',
'message' =>'Invalid date'
],
public function rules()
{
return [
['dateofbirth', 'date', 'format' => 'dd/MM/yyyy'],
];
}
Another way was taken from this answer.
public function rules()
{
return [
['dateofbirth', 'validateDateOfBirth'],
];
}
public function validateDateOfBirth($attribute)
{
$dateTime = DateTime::createFromFormat('d/m/Y', $this->$attribute);
$errors = DateTime::getLastErrors();
if (!empty($errors['warning_count'])) {
$this->addError($attribute, 'Invalid date');
}
}
try
(/^((0[1-9]|[12][0-9]|3[01])(/)(0[13578]|1[02]))|((0[1-9]|[12][0-9])(/)(02))|((0[1-9]|[12][0-9]|3[0])(/)(0[469]|11))(/)\d{4}$/)
or
(^((0[1-9]|[12][0-9]|3[01])(/)(0[13578]|1[02]))|((0[1-9]|[12][0-9])(/)(02))|((0[1-9]|[12][0-9]|3[0])(/)(0[469]|11))(/)\d{4}$)
That one worked for me fine
public function rules()
{
return [
['dateofbirth', 'date', 'format' => 'php:Y-m-d'];
];
}
Here is more info on that YII2 DateValidator docs

using Cakephp Restful WS with primary key different from default 'id'

I want to create a Webservice in cakephp but the primary key is not id_supp but taken the default value id
this is the modal:
<?php
App::uses('AppModel', 'Model');
class Supplier extends AppModel {
var $primaryKey = 'id_supp';
this is the route
Router::mapResources(array('suppliers'));
and this is the view action
public function view($id) {
$supplier = $this->Supplier->findById($id);
$this->set(array(
'supplier' => $supplier,
'_serialize' => array('supplier')
));
}
The result when accessing the following url via GET
/suppliers/54f4dc83-0bd0-4fdd-ab8b-0a08ba3b5702.json
is:
{
"code": 500,
"url": "\/TN\/Back_rest\/suppliers\/54f4dc83-0bd0-4fdd-ab8b-0a08ba3b5702.json",
"name": "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Supplier.id' in 'where clause'",
"error": {
"errorInfo": [
"42S22",
1054,
"Unknown column 'Supplier.id' in 'where clause'"
],
"queryString": "SELECT `Supplier`.`id_supp`, `Supplier`.`company_name`, `Supplier`.`contact_name`, `Supplier`.`contact_title`, `Supplier`.`address`, `Supplier`.`postcode`, `Supplier`.`phone`, `Supplier`.`fax`, `Supplier`.`www`, `Supplier`.`active`, `Supplier`.`created`, `Supplier`.`modified` FROM `tn`.`suppliers` AS `Supplier` WHERE `Supplier`.`id` = '54f4dc83-0bd0-4fdd-ab8b-0a08ba3b5702' LIMIT 1"
}}
Because cakephp uses convention over configuration you should use id for your table primary id field. In your example you could find what you are looking for like this:
public function view($id = null) {
$supplier = $this->Supplier->find('first', array(
'conditions' => array(
'Supplier.id_supp' => $id
)
));
$this->set(array(
'supplier' => $supplier,
'_serialize' => array('supplier')
));
}
or like this:
public function view($id = null) {
$this->Supplier->primaryKey = $id;
$supplier = $this->Supplier->find('first');
$this->set(array(
'supplier' => $supplier,
'_serialize' => array('supplier')
));
}
or like this:
public function view($id = null) {
$supplier = $this->Supplier->findByIdSupp($id);
$this->set(array(
'supplier' => $supplier,
'_serialize' => array('supplier')
));
}
Choose what ever pleases you the most.