Add sequential number in database, that resets every year - php

I am building a project using Codeigniter + MySQL + Active Record.
In my MySQL db i have a table named Requests with columns protocol,year and some other columns where i store general information of a request (like title, subject etc...), nothing special to mention.
Protocol and year are TYPE INT and must be auto generated like below.
Every year, at 01/01/XXXX-00:00:00 the protocol field must reset to number 1 (the first request saved after 01/01/XXXX, must have protocol value 1) and for the upcoming requests, increase it sequentially by 1, until next year and so on.
To reset the protocol, i will add a cron in a later phase where i will do a trick to reset. Still don't know how.
What i need to do now:
Whenever i add a new request, the protocol of the new row must be increased by 1.
Pseudocode:
new_protocol = previous_protocol + 1
What i am doing so far
I have a function in my model which Inserts a new request, but so far i do nothing about the protocol number, i enter it manually through my form.
public function addRequest($request) {
$this->db->insert('requests', $request);
if ($this->db->affected_rows() == 1)
return $this->db->insert_id();
return FALSE;
}
What is the most efficient way to achieve this?
Should i find the last protocol number in my Controller -> add 1 -> send to model to add?
Should i find the LAST and MAX protocol number in model -> add 1 -> insert to db?
Something else?
Any ideas will be appreciated.

I'd approach like so:
add column ID in your table and set it to auto-increment
php - set the default timezone to use (since PHP 5.1): date_default_timezone_set('UTC');
php - get current year: $cyear=date("Y");
get row max(ID) and compare if the stored year has changed compared to $cyear
if it has changed and following your pseudocode example:
new_protocol = 1
otherwise
new_protocol = previous_protocol + 1

Ok so i created a library in Codeigniter and wrote 2 functions, 1 in Library and 1 in Model.
Library
public function getProtocolNumber() {
$CI = &get_instance();
$year = date('Y');
$max_protocol = $CI->request_model->getYearsProtocol($year);
$max_protocol = $max_protocol['max_protocol_number'];
if ($max_protocol && !empty($max_protocol) && $max_protocol != NULL) {
$protocol_number = (int) $max_protocol + 1;
} else {
$protocol_number = 1;
}
return $protocol_number;
}
Model
public function getYearsProtocol($year) {
$qry = $this->db->select('MAX(protocol_number) as max_protocol_number')
->from('requests')
->where('protocol_year', $year)
->get();
if ($qry->num_rows() > 0)
return $qry->row_array();
return FALSE;
}

Related

CakePHP Paginator: get first item from next page?

I have a table that contains different versions of a text. I want to display the diffs of each version with the previous version. I also want to paginate through the versions, in case there are more than 20. However, to diff the last text on each page I would need the first text of the next page. I cannot just make the page size one larger (21 in this case), because the second page would skip its first entity, and the third its first two etc.
$config = $this->Paginator->getConfig();
$this->Paginator->setConfig('limit', $config['limit'] + 1);
$inscriptions = $this->paginate($query);
I might instead be able to solve the problem by making a separate ->paginate() call for the single entity, but I would rather not execute a second query if possible.
$inscriptions = $this->paginate($query);
$config = $this->Paginator->getConfig();
$this->Paginator->setConfig([
'limit' => 1,
'page' => ($config['page'] * $config['limit']) + 1
]);
$inscriptions[] = $this->paginate($query)->first();
Is there a way to skip the first n results? In that case I could set the page size to 21 but set the page number to 1, and skip the first ((old page number - 1) * old page size) entities.
It is possible to make a custom paginator that extends the default one, but functions as described:
<?php
namespace App\Datasource;
use Cake\Core\InstanceConfigTrait;
use Cake\Datasource\Paginator;
use Cake\Datasource\QueryInterface;
use Cake\Datasource\RepositoryInterface;
class DiffPaginator extends Paginator
{
use InstanceConfigTrait;
protected function getQuery(RepositoryInterface $object, ?QueryInterface $query = null, array $data): QueryInterface
{
$data['options']['offset'] = ($data['options']['page'] - 1) * $data['options']['limit'];
$data['options']['limit'] += 1;
unset($data['options']['page']);
return parent::getQuery($object, $query, $data);
}
protected function buildParams(array $data): array
{
$paging = parent::buildParams($data);
if ($paging['current'] == $paging['perPage'] + 1) {
$paging['current'] -= 1;
}
return $paging;
}
}
In your controller then use the following:
$this->Paginator->setPaginator(new DiffPaginator);

How to get Position of Comment within a Post

So I have a Post which has Comments -- I'm trying to get the Comment # position within that post. For example, a Post has 15 comments, I want to be able to get the numerical position (i.e 1 (first post), 2 (second post), 3 (third post), etc, etc), and put this into a function somehow. That way when I can call $comment->position() and it will show as the 4th, 5th, whatever position in it is in.
I've done some searching around the web and couldn't find a solution. Any help is greatly appreciated! This is what I have so far:
public function position($id,$arr)
{
$total = $this->post->comments->count();
$position = $this->pluck('post_id')->search($this->id) + 1;
return ceil($total / $position);
//$comments_per_page = 25;
//$pos = array_search($id,$arr);
//$pos = $pos+1;
//return ceil($pos/$comments_per_page);
}
You should first get all your comments as collection.
// all comments as collection
$comments = $this->post->comments;
Then you can search through the collection using the search function and inserting an id you want to search for ... or any other param you want.
$id = 2;
$commentIndex = $comments->search(function($comment) use ($id) {
return $comment->id === $id;
});

How to set sequence data with existing random data?

I have a table entity named it as uniqueId where the entry generate randomly.Such as
$customer->uniqueId = $request->Input(['uniqueId']) ?: mt_rand(1000, 9999);
means if there is existing uniqueId it will store the existing one otherwise it will be set to the random number. Now instead of setting the random number i want to set it as sequentially . means from 1, 2, 3 like that.. as i can't delete the existing uniqueId which has already created how do I create new entry sequentially with the existing one?
If you simply set column to auto increment you will achieve this automatically you dont even need to call it.
In laravel you can achieve this in your migrations by
$table->increments('uniqueId');
OR
You can achieve this by
lets assume you have a customer Model
// find the last entry in you table
$oldCustomer = Customer::orderBy('uniqueId','DESC')->first();
$customer->uniqueId = ++($olderCustomer->uniqueId);
I hope this helps
**EDIT **
$customers = Customer::all();
$index = 1;
#foreach($customers as $customer)
{
$customer->uniqueID = $index++;
$customer->update();
}

Filtering aerospike LLIST

Can anyone please show me how to filter an Aerospike LLIST bin not by the key and return all the result using PHP.
In my case the bin 'notes' is containing many rows of key, title, desc & category. I can retrieve all rows using the following code but
I need to do a filter on the category and get the results of only those within the same category. If udf is needed please assist to show me the udf code as well and how to apply the filter to get the results.
$db = new Aerospike($config, false);<br/>
$key = $db->initKey('mynamespace', 'myset', $userid);<br/>
$list = new \Aerospike\LDT\LList($db, $key, 'notes');<br/>
$status = $list->scan($results);
The LList.scan method has an optional module name, function name pair of parameters, allowing you to call a Lua function to filter each element.
There's an example PHP script provided with the client repo, which calls an example Lua module:
function keyfilters.even_filter(element)
local remainder = -1
if type(element) == "number" then
remainder = element % 2
elseif (getmetatable(element) == getmetatable(map())) and element['key'] then
remainder = element['key'] % 2
end
if remainder == 0 then
return element
else
return nil
end
end
Is invoked by
$rental_history->scan($elements, 'keyfilters', 'even_filter');
Manage to modify the UDF as follows and it works.
local category_filters = {}
function category_filters.filterBy(element,val)
if element['category'] == val[1] then
return element
else
return nil
end
end
return category_filters
Invoked by
$status = $list->scan($results, 'category_filters', 'filterBy', array($category));

How to update database in moodle using cron

I am facing a problem. I have to update a field in database by using cron function in moodle. I am using update query in cron function to update value. But It doesn't work. I am using this function to update value:
function activitysetmodule_cron ()
{
global $CFG, $DB;
$DB->update_record("activitysetmodule",)
$sql="update {$CFG->prefix}activitysetmodule as asm set status = 1 where exists (select 1 from {$CFG->prefix}course_modules as cm where (module=asm.activityset OR module=asm.activityset2 ) AND completion=1 AND asm.course =cm.course ");
return true;
}
Please help to sought it out.
Take a look at the documentation https://docs.moodle.org/dev/Data_manipulation_API#Updating_Records
$DB->update_record takes 2 params, the name of the table to update the record in and an object containing the updated data.
e.g.
$obj = new stdClass();
$obj->id = $id_of_object_to_update;
$obj->status = 1;
$DB->update_record('tablename', $obj);
It looks like you should refactor your code to get a list of records to update, then call $DB->update_record on each in turn (or $DB->set_field, if there is only one field to update). Alternatively, you could use the $DB->execute($sql) function to directly run some SQL on the server, e.g.
$DB->execute("UPDATE {activitysetmodule} asm SET status = 1 WHERE EXISTS (SELECT 1 FROM {course_modules} cm WHERE (module=asm.activityset OR module=asm.activityset2 ) AND completion=1 AND asm.course = cm.course)");
Note the use of {tablename} rather than {$CFG->prefix}tablename and the removal of the 'AS' keyword, as that is not allowed on all DB engines.
Note also, if you haven't done so already, turning on debugging (http://docs.moodle.org/en/Debugging) will give you much more helpful error messages.

Categories