Currently working on lost and found project where users can make a report when they left something behind.
I'm using laravel 5.4, I have some data already on my DB and I have made every requirements according to my client. But in the end, my client want me to add unique report number ticket for every report that has been made. I've googled it but I can't find tutorial that is similar to my case
I'm totally newbie on programming, any help would be much appreciated.
There's a lot of ways you can do so, but the following two sprint to mind:
Use an auto-increment column from your database and add some other stuff to it like the current date and make sure to add a few zeros in there (e.g. 20192208-00001).
$date = new DateTime('now');
echo $id = $date->format('Y-m-d') . "-" . str_pad($ticket->id, 6, "0", STR_PAD_LEFT);
Alternatively you can use a Uuid for this. These are uniquely generated numbers with a near impossible chance of collision. To set this up you'll need a library which supports it composer require ramsey/uuid. Then you can generate your random numbers like so:
$uuid4 = Uuid::uuid4();
echo $uuid4->toString(); // i.e. 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a
You can use Unix Timestamp as your unique filed.
$token = time();
Now add this token when you are saving a new report to database. If you want to make it more unique you can add some more random strings to it like
In Laravel 5.8 You need to use use Illuminate\Support\Str; this first. and then
$token = time().Str::random(5);
In previous versions its like
$token = time().str_random(5);
Related
I'm using PHP 7 with Phalcon PHP and I'm trying to create a method to generate a booking number. Here is my current method :
public function generateNumber($company_code) {
// Build the prefix : COMPANY20190820
$prefix = $company_code . date('Ymd');
// It's like SELECT count(*) FROM bookings WHERE number LIKE 'COMPANY20190820%'
$counter = Bookings::count(array(
"number LIKE :number:",
"bind" => array('number' => $prefix.'%')
));
// Concat prefix with bookings counter with str_pad
// COMPANY20190820 + 005 (if 4 bookings in DB)
$booking_number = $prefix . str_pad($counter + 1, 3, 0, STR_PAD_LEFT);
// Return COMPANY20190820005
return $booking_number;
}
So I have a problem because sometime I have to delete 1 or multiple bookings so I can get :
COMPANY20190820001
COMPANY20190820002
COMPANY20190820005
COMPANY20190820006
COMPANY20190820007
And I need to add after the last in my DB so here 007, because I can get duplicated booking number if I count like that.
So how can I do to take the last and increment according the last booking number of the current day ?
You need to rethink what you want to do here as it will never work that way.
As I see it you have at least two options:
Use an auto-increment id and use that in combination with the prefix
Use a random fairly unique string (e.g. UUID4)
You should never manually try to get the current maximum id as that may and most likely will at some point result in race conditions and brittle code as a result of that.
So I found a solution, maybe there is a better way to do that but my function works now:
public function generateNumber($company_code) {
// Build the prefix : COMPANY20190820
$prefix = $company_code . date('Ymd');
// Get the last booking with the today prefix
// e.g : COMPANY20190820005
$last_booking = Bookings::maximum(array(
"column" => "number",
"number LIKE :number:",
"bind" => array('number' => $prefix.'%')
));
// Get the last number by removing the prefix (e.g 005)
$last_number = str_replace($prefix, "", $last_booking);
// trim left 0 if exist to get only the current number
// cast to in to increment my counter (e.g 5 + 1 = 6)
$counter = intval(ltrim($last_number, "0")) + 1;
// Concat prefix + counter with pad 006
$booking_number = $prefix . str_pad($counter, 3, 0, STR_PAD_LEFT);
// Return COMPANY20190820006
return $booking_number;
}
I reckon that the use case you describe does not justify the hassle of writing a custom sequence generator in PHP. Additionally, in a scenario where booking deletion is expected to happen, ID reusing feels more a bug than a feature, so your system should store a permanent counter to avoid reusing, making it less simple. Don't take me wrong, it can be done and it isn't rocket science, but it's time and energy you don't need to spend.
Your database engine surely has a native tool to generate autoincremented primary keys, with varying names and implementations (SQL Server has identity, Oracle has sequences and identity, MySQL has auto_increment...). Use that instead.
Keep internal data and user display separated. More specifically, don't use the latter to regenerate the former. Your COMPANY20190820007 example is trivial to compose from individual fields, either in PHP:
$booking_number = sprintf('%s%s%03d',
$company_code,
$booking_date->format('Ymd'),
$booking_id
);
... or in SQL:
-- This is MySQL dialect, other engines use their own variations
SELECT CONCAT(company_code, DATE_FORMAT(booking_date, '%Y%m%d'), LPAD(booking_id, 3, '0')) AS booking_number
FROM ...
You can (and probably should) save the resulting booking_number, but you cannot use it as source for further calculations. It's exactly the same case as dates: don't need to store dates in plain English in order to eventually display them to the end-user and you definitively don't want to parse English dates back to actual dates in order to do anything else beyond printing.
You also mention the possibility of generating long pure-digit identifiers, as Bookings.com does. There're many ways to do it and we can't know which one they use, but you may want to considering generating a numeric hash out of your auto-incremented PK via integer obfuscation.
you could split your database field in two parts, so you hold the prefix and the counter separately.
then, you simply select the highest counter for your desired prefix and increment that one.
if you can't change the table structure, you could alternatively order by the id descendingly and select the first. then you can extract its counter manually. keep in mind you should pad the numbers then, or you get #9 even if #10 exists.
if padding is not an option, you can direct the database to replace your prefix. that way, you can cast the remaining string to a number and let the database sort - this will cost some performance, though, so keep the amount of records low.
I'm trying to create an increment number licence with the current date of the year + an increment number but i really don't know how to do this i know MYSQl does not support sequences but i would like to know if there is a way to solve the problem
here my controller
public function create(){
$licence = new Licence ;
$licence ->num_licence = Carbon::now()->year -- i would like here to put the current year like 2017 with a random unique number to get the format like 20170001 for exemple !
...
how to acheice this? thanks in advance :)
you can use uniqid function with current year as prefix.
public function create(){
$licence = new Licence ;
$num_liscence_exist=true;
while($num_liscence_exist){
$num_liscence=uniqid(Carbon::now()->year);
if (!Liscence_Table::where('num_liscence', '=',"'".$num_liscence."'")->exists()) {
$liscence->num_liscence=$num_liscence;
$num_liscence_exist=false;
}
}
}
Generate the random id using uniqid() and concatenate with date:
public function create(){
$liscence=new Liscence();
$year = Carbon::now()->year;
$liscence->num_liscence= $year. uniqid();
$liscence->save();
}
using uniqid() get unique number or also you can use time stamp with it:
$liscence=new Liscence();
$year = Carbon::now()->year;
$liscence->num_liscence= $year. strtoupper(uniqid()) . Carbon::now()->timestamp;
$liscence->save();
Will look like : 2017ABC011486543961
A sequence needs to be stored somewhere so I doubt there's a sensible pure-PHP solution. But since you're already using MySQL there's no reason to not use it. I'd create a database table for that, something like:
CREATE TABLE licence_sequence (
sequence_year YEAR NOT NULL,
next_value INT UNSIGNED NOT NULL DEFAULT 1,
PRIMARY KEY (sequence_year, next_value)
)
ENGINE=InnoDB;
(Ugly sequence_year name was chosen to avoid having to quote it every time.)
You then have to manage this from code, including:
Ensuring you have rows for every year as you need them (this can be as simple as populating data for all years for next century).
Ensuring you don't assign the same value to different items.
A rough overview of stuff to consider:
You can (and should) make your licence number a unique index to avoid dupes.
You can use transactions to avoid unnecessary gaps. Transaction should wrap all the operations involved:
Get next sequence number
Save it into new licence
Increment next number
You need to ensure atomic operations in a multi-tasking environment. This is the hardest part. I've been lately being playing with MySQL named locks and they seem to work correctly.
Can I use strtotime("now") as a unique ID in php application as I assume it uses current timestamp and cannot generate the same integer in future?
It is not safe to use strtotime('now') as id
take a look at this code:
$now = strtotime('now');
$anotherNow = strtotime('now');
$sameCounter = 0;
while($anotherNow == $now){
$sameCounter++;
$anotherNow = strtotime('now');
}
echo $sameCounter; //8558
Result is 8558, very not safe, php did 8558 operations during that secondThere's big chance that you'll get the same ID few times.
you can use uniq function instead
Uniq id is itself a php function , you can have this like this
$uniq = uniqid();
you can add more entropy in this
No, don't do that. Although the timestamp is likely to always be different that doesn't mean it's unique. For instance, what would happen if two requests are issued at the same time? You will have two equal timestamp. When choosing unique IDs, you have to be sure that there's no possible cases in which there are equals values. A good solution is having an auto-increment field. That will make sure that your id will never be the same.
I'm using for small projects, like as mini blog or cms.
this function generate 10 digits with unix time
and change every second, if your project not biq and not get high request or inserts you can use this safely.
$UniqID = time();
it create ID with 10 digits like (1462570078)
for other project I use microtime more than time() or other uniq like this
$m=microtime(true);
echo sprintf("%8x%05x\n",floor($m),($m-floor($m))*10000);
My be rare chance we can get duplicates , you can prefix username
Like this echo "$username-".time(); or "$username".time(); or "$userid-".time();
In php already have uniqid .
The uniqid() function generates a unique ID based on the microtime
(current time in microseconds).
For more information please refer official website http://php.net/manual/en/function.uniqid.php
I have a column family in cassandra which records all the events emitted by a particular user over a specified time period.
I'm using a composite column consisting of a UUID1 and a UTF8 string. I'd like to select all the columns after a paticular time.
// Code to create the column family.
use phpcassa\SystemManager;
$sys = new SystemManager('127.0.0.1');
$sys->create_column_family($keyspace, 'UserActivity', array(
"comparator_type" => "CompositeType(LexicalUUIDType, UTF8Type)",
"key_validation_class" => "UTF8Type"
));
In the code below I try to read the data. Initially I tried creating an array with just the event type set at the 1 index, however although this seemed to work I got lots of errors in the log. Now, I'm trying to set a timestamp in the past and base a UUID1 on it. No errors - but no data either.
// Code to read data
$activityFam = new ColumnFamily($this->pool, 'UserActivity');
$activityFam->insert_format = ColumnFamily::ARRAY_FORMAT;
$activityFam->return_format = ColumnFamily::ARRAY_FORMAT;
$fiveMinPrev = $this->dateFactory->getDateTime();
$fiveMinPrev->sub(new \DateInterval("PT5M"));
$uuid = \phpcassa\UUID::uuid1(null, $fiveMinPrev->getTimestamp());
// Get the most recent SESSION event from the users activity log.
$slice = new ColumnSlice(array(0 => $uuid, 1=>self::EVENT_SESSION));
$columns = $activityFam->get($someUserId, $slice);
How do I achieve selecting columns from a specified time onwards?
Thanks,
Bah!
I realised this is exactly the correct approach to take however it seems I wasn't using a timestamp generated by my 'DateFactory' (which allows me to freeze and manipulate time during testing) to base the timestamp on when I actually inserted the record.
Thus producing incorrect results!
Hello im building a multilenguaje app in php, this is the first time i handle multilenguaje, im trying to do it like this.
For months for example
i have a table "months" with id | month estructure
in the users table i have id | username | month_id
my guess (bad guess) its that i can save for example $january direct on the database so in the php when its called, it looked for the defined variable.
$january = "january"; and if im on spanish web then i change this to $january = "Enero";
but this is not working (obviusly because it prints as a result of a call $january, Its saved as $january in the database)
How is the best method for what im trying to do.. cause im lost in this point.. and i need this estructure in the database for a lot of reasons i wont mention, right now,
thanks!
My code
This $row2['months']
Print this $january
Even when in the php code i have set $january = "enero";
You might rethink your strategy.
Example:
For 10 languages if you keep 10 php files defining the month names or actually all language locale words in, it will be sufficient and you can include them without disturbing the database.
<?php
// this is words_en.php, you can make another like words_de.php etc.
$months = array('january','february','march','april'....etc );
?>
If you structure your locale file consistently for instance:
$msgs = array(
'MSG1'=>'first message',...
}
keeping only the references(like'MSG1') in your code and also in your database will be sufficient. For the months, you can keep them apart from $msgs since their use is specific and numeric indexing adds more consistency to coding for their case.
Note that this is not the only method for language locales but this is an easy to maintain version.
You should save the users locale e.g. en_US in your table and base further translations on that value with a fallback to the default language.
To get php to evaluate that variable, what you need to do is eval:
$january='Enero';
$row='$january';
echo $row; //Prints $january
echo PHP_EOL;
echo eval("return ".$row.";"); //Prints Enero
Here that is in ideOne: http://ideone.com/f0LCT0