Filtering in date range - php

I try to build custom search form and filter results in some range of dates:
$form = BootstrapForm::create (
$this,
'LetterSearchForm',
FieldList::create (
DateField::create('Sent_After','Sent After'),
DateField::create('Sent_Befor','Sent Before')
...
),
...
);
public function index (SS_HTTPRequest $request)
{
$letters = Letter::get()->sort('DateUpload');
if($search = $request->getVar('Sender')) {
$letters = $letters->filter(array(
'Sender:PartialMatch' => $search
));
}
if ( $search1 = $request->getVar('Sent_After') && $search2 = $request->getVar('Sent_Befor'))
{
What must be here?
}
}
}
Can I use here something like WithinRangeFilter?

I don't know of any range filter, but according to the documentation you could use something like:
$dateFilteredList = $letters->filter(array(
'DateUpload:LessThanOrEqual' => $search2, // Sent_Befor
'DateUpload:GreaterThanOrEqual' => $search1 // Sent_After
));
I made a few assumptions with the code above:
DateUpload is the date field you're trying to filter on.
The date format supplied by the form is already database friendly, ie yyyy-mm-dd (eg 2017-09-05)
You may need to edit it accordingly.
Hope that is what you're looking for :)

Related

Codeigniter - input data save in multiple arrays and db table

I've an existing form which is passing the input data to the model in an array format. $postdata has all the data from the view and sending to model.
Controller:
$inquiry_id = $this->input->post('inquiry_id');
$postdata = $this->input->post();
$this->load->model('Design_model');
$this->Design_model->insertdata($postdata,$inquiry_id);
Model:
function insertdata($data = array(), $inquiry_id){
$sql = $this->db->query("select * from design where inquiry_id='".$inquiry_id."'");
if($sql->num_rows() == 0){
$sql_query = $this->db->insert('design', $data);
}
else{
$this->db->where('inquiry_id', $inquiry_id);
$this->db->update('design', $data);
}
}
Above is working fine. Now, I'd like to add few fields in the view and save in a different database table. Need to exclude the new field values from $postdata array getting saved. Need to find the best approach to do this. I can start with some name for all the new fields, so that we can add any filter if available to exclude from the $postdata.
You can use elements() function from Array helper.
$array = array(
'id' => 101,
'title' => 'example',
'desc' => 'something',
'unwanted' => 'bla bla'
);
$filtered_array = elements(array('id','title','desc'),$array); //you can use this directly to the post data
$this->Design_model->insertdata($filtered_array,$inquiry_id);
You can use array_merge() or array_push() functions to add new fields to the array.
Let's say you have following data
$postdata = array("name"=>"xyz",
"email"=>"xyz#gmail.com",
"age"=>"40",
"gender"=>"Male",
"occupation"=>"Engineer"
);
Of which first 3 records are from old fields and last 2 are from new fields as you saying.
You need to find last index of first set i.e. '3' Now you can do this.
$firstDb = array_splice($postdata,0,3); //here 3 is index we are using to get first 3 records from $postdata
$secondDb = array_slice($postdata,0,3); //here 3 is index we are using to get records from position 3 from $postdata
Output:
$firstDb = array("name"=>"xyz","email"=>"xyz#gmail.com","age"=>"40");
$secondDb = array("gender"=>"Male","occupation"=>"Engineer");
Now you can insert you records as you wish to. Happy coding

Database data field check before Data insertion

I have a data coming from the HTML Page. And i want to check whether the date and the place values already exists. If they exists, it should throw an error saying Data is already present, if those date and place data is not there it should allow the user to save it.
Here is the code which i have written to save it,
public function StoreSampling(Request $request)
{
$date = Carbon::createFromFormat('d-m-Y', $request->input('date'))->format('Y-m-d');
$doctorname = Input::get('doctorselected');
$product = Input::get('product');
$product= implode(',', $product);
$quantity = Input::get('qty');
$quantity =implode(',',$quantity);
$representativeid = Input::get('representativeid');
//Store all the parameters.
$samplingOrder = new SamplingOrder();
$samplingOrder->date = $date;
$samplingOrder->doctorselected = $doctorname;
$samplingOrder->products = $product;
$samplingOrder->quantity = $quantity;
$samplingOrder->representativeid = $representativeid;
$samplingOrder->save();
return redirect()->back()->with('success',true);
}
I searched some of the Stack over flow pages. And came across finding the existence through the ID And here is the sample,
$count = DB::table('teammembersall')
->where('TeamId', $teamNameSelectBoxInTeamMembers)
->where('UserId', $userNameSelectBoxInTeamMembers)
->count();
if ($count > 0){
// This user already in a team
//send error message
} else {
DB::table('teammembersall')->insert($data);
}
But i want to compare the date and the place. And if they are not present, i want to let the user to save it. Basically trying to stop the duplicate entries.
Please help me with this.
There are very good helper functions for this called firstOrNew and firstOrCreate, the latter will directly create it, while the first one you will need to explicitly call save. So I would go with the following:
$order = SamplingOrder::firstOrNew([
'date' => $date,
'place' => $place
], [
'doctorname' => Input::get('doctorselected'),
'product' => implode(',', Input::get('product')),
'quantity' => implode(',',Input::get('qty')),
'representativeid' => Input::get('representativeid')
]);
if($order->exists()) {
// throw error
return;
}
$order->save();
// success
You need to modify your query to something like this:
$userAlreadyInTeam = SamplingOrder::where('date', $date)
->where('place', $place) // I'm not sure what the attribute name is for this as not mentioned in question
// any other conditions
->exists();
if (userAlreadyInTeam) {
// Handle error
} else {
// Create
}
You do not need to use count() as your only trying to determine existence.
Also consider adding a multi column unique attribute to your database, to guarantee that you don't have a member with the same data and place.
The best way is to use the laravel unique validation on multiple columns. Take a look at this.
I'm presuming that id is your primary key and in the sampling_orders table. The validation rule looks like this:
'date' => ['unique:sampling_orders,date,'.$date.',NULL,id,place,'.$place]
p.s: I do not see any place input in your StoreSampling()

CakePHP 3 Dynamic Finders with underscores

I would like to use a dynamic finder method. I've seen in the documentation $this->Users->findByUsername. My problem is that my column name is post_id, and I'm not sure how the underscore affects the name of my dynamic finder function. Here are the ones I've tried so far and can't seem to get working
findByPost_id( $post_id )
findByPost_Id( $post_id )
findByPost_ID( $post_id )
findByPostId( $post_id )
For context here is what my code looks like
//VotesTable.php
public function afterSaveCommit($event, $entity, $options) {
if ( $entity->vote_type_id == self::favorite ) {
$qt = TableRegistry::get('questions');
$question = $qt->findByPostId($entity->post_id);
$question->favorite_count = $question->favorite_count + 1;
if ( ! $qt->save( $question ) ) {
throw new \Exception("Unable to update favorite count", 500);
}
}
}
When I log $question it outputs a query, not an object, and the query can't be run. it ends with WHERE 'questions'.'post_id' = :c0
Cake will convert the underscores to pascal case words, so you find it like this:
$this->findByPostId();
This is the correct way to do it.
If your column name is: post_id, you should use it as follows:
findByPost_id(2);
It seems that problem is somewhere else in the code. For example, if my column name is: item_status, I would use it like this:
// In the controller:
$table = $this->loadModel('ProcessItems');
$result = $table->findByItem_status(100);

Compare PHP array value to PART of a string

I'm trying to automate sifting through my online bank statements. Here's a trivial example of what I need.
I have an array of restaurants against which I sort my credit card statements:
$restaurants = array(
array("vendor" => "default",
"type" => "default"
),
array("vendor" => "dunkin",
"type" => "pastry"
),
array("vendor" => "mcdonald",
"type" => "fastfood"
),
array("vendor" => "olive",
"type" => "italian"
)
);
The statement entries themselves can be a rather descriptive string:
$string = "McDonald's Restaurants Incorporated";
I've tried using array_search and in_array, but they seem to do the reverse of what I need, or they need an exact match like in the example below, but it is not what I need:
$result = array_search($string, array_column($restaurants, 'vendor'));
return $restaurants[$result]['type'];
// returns "default" because "McDonald's Restaurants Incorporated" != "mcdonald"
I would like to be able to match the array value "mcdonald" to any string that contains that chunk of it, and then return type "fastfood" for it. Don't worry about handling multiple occurrences.
You'll need a combination of things - a search-in-string method, and for it to be case insensitive.
You can accomplish this with something like this:
/**
* Perform a string-in-string match case insensitively
* #param string $string
* #param array $restaurants
* #return string|false
*/
function findRoughly($string, $restaurants)
{
$out = false;
foreach ($restaurants as $restaurant) {
// Set up the default value
if ($restaurant['type'] == 'default' && !$out) {
$out = $restaurant['type'];
// Stop this repetition only
continue;
}
// Look for a match
if (stripos($string, $restaurant['vendor']) !== false) {
$out = $restaurant['type'];
// Match found, stop looking
break;
}
}
return $out;
}
And use it like so:
$result = findRoughly("McDonald's", $restaurants);
Example here.
I don't think there's a function in PHP that will handle this quite as cleanly as you want. But you can whip up a quick function to loop through the array looking for matches:
$type = call_user_func( function( $restaurants, $string ) {
foreach ( $restaurants as $restaurant ) {
if ( stripos( $string, $restaurant['vendor'] ) !== FALSE ) {
return $restaurant['type'];
}
}
return $restaurant[0]['type'];
}, $restaurants, $string );
If $string is "McDonald's Restaurants Incorporated", then $type will be "fastfood". The above makes the assumption that the first instance in the array is your default return if none of the specified values match.
I just built this as an anonymous function/closure out of convenience, which I usually would to do cleanly enclose something I only plan to run once. But it may be cleaner as a named function in your application.
I took a different (functional) approach by using array_map and array_filter. It's rather compact due to the use of builtin functions, and gets the job done.
// Anonymous function which gets passed to array_map as a callback
// Checks whether or not the vendor is in the $key_string (your restaurant)
$cmp = function ($array) use ($key_string) {
if (stristr($key_string, $array['vendor'])) {
return $array['type'];
}
return "default";
};
function validResult($item) {
return isset($item) && gettype($item)=="string";
}
$key_string = "McDonald's Restaurants Incorporated";
$results = array_map($cmp, $restaurants);
$results = array_pop(array_filter($results, validResult));
I got fixated on the in_array portion of the question. Editing this to use strpos instead.
Try this:
foreach($restaurants as $restaurant)
{
if(strpos($restaurant['vendor'], $string) !== FALSE)
{
return $restaurant['type']; //Or add to an array/do whatever you want with this value.
}
}
http://php.net/manual/en/function.strpos.php

Only show todays news - Silverstripe

Hello Silverstripe Specialists!
I made the tutorial "extending a basic site"
(http://doc.silverstripe.org/en/tutorials/extending_a_basic_site)
That all worked very well so far.
I made this to show the latest news on the HomePage:
In HomePage.php:
// ...
public function LatestNews($num=5) {
$holder = ArticleHolder::get()->First();
return ($holder) ? ArticlePage::get()->filter('ParentID',
$holder->ID)->sort('Date DESC')->limit($num) : false;
}
And this in HomePage.ss:
// ...
public function LatestNews($num=5) {
$holder = ArticleHolder::get()->First();
return ($holder) ? ArticlePage::get()->filter('ParentID',
$holder->ID)->sort('Date DESC')->limit($num) : false;
}
That works very well!
Now my Question: All my News have a Date-Field. Is it possible to show only
the News of the current Date on the HomePage?
I tried this, but this wont work (Server Error) (Datum is my Date of the News):
public function LatestNews($num) {
$holder = ArticleHolder::get()->First();
return ($holder) ? ArticlePage::get()->filter('ParentID', "datum == CURDATE()",
$holder->ID)->sort('Date DESC')->limit($num) : false;
}
Thank you very much for your help!
filter() needs either two values (column and value) or an array of key-value pairs of what to filter. So if you want to filter for more than one thing you need an array as parameter:
$today = date('Y-m-d');
$todaysNews = ArticlePage::get()->filter(array(
'ParentID' => $holder->ID,
'datum' => $today
));
This will return a DataList you can sort and limit like you did in your example.
See also in docs:
Data Model and ORM general overview
Search filters how to filter "greater than" etc...
EDIT:
So a method in your controller could look like:
public function getTodaysNews($num=5) {
$holder = ArticleHolder::get()->First();
$today = date('Y-m-d');
return $holder
? ArticlePage::get()->filter(array(
'ParentID' => $holder->ID,
'datum' => $today
))->sort('Date DESC')->limit($num)
: false;
}

Categories