how to create custom auto increment for string field in laravel - laravel

i need to save a custom auto increment string when a new product is created. What is the best way to achieve this in laravel
this is the outcome that i want
id sku product_name
1 'sku-001' milk
2 'sku-002' cerelac
2 'sku-003' milo
this is my current code
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('sku');
$table->string('name')->unique();
});

You could also use model event's. Below you have the boot function in which you would put into your model. After that you would have access to various of event's like creating, created, updating, updated .. so on and so for. We are interested in created, as it is triggered after your model is saved.
The static method receives a function that has as parameter an instance of the model that was just saved so you can access the id and concatenate with the string you want.
/**
* Enables us to hook into model event's
*
* #return void
*/
public static function boot()
{
parent::boot();
static::created(function($product) {
$product->sku .= 'sku-' . $product->id;
$product->save();
});
}

Yes sure, but you have to generate it in your own. like this one
$id = "sku-000";
echo ++$id; // sku-001
echo "<br>";
echo ++$id; // sku-002
Remember that you to have fetch first the last inserted Id and get the sku of this then do the increment process. like this one
$last_id = Product::orderBy('sku', 'desc')->first()->sku;
$last_id = $last_id++;
Product::create(['sku' => $last_id, 'name' => 'test product']);

Try This Method:
$latestorder = Order::where('status','processing')->latest('created_at')->first();
if($latestorder->exists()) {
$total = $latestorder->total_count+1;
} else {
$total = 1;
}
$order->status = 'processing';
$order->total_count = $total;

Related

Laravel : insert random id on field have autoincrement id

I have generate random id function :
class CreateRandomId {
public static function get_id($my_table) {
$id = mt_rand(1000000, 9999999999);
if(self::check_id($id,$my_table)){
get_id($my_table);
}
return $id;
}
public static function check_id($id,$my_table) {
$table=DB::table($my_table)->where('id',$id)->get();
if (count($table)==0) {
return false;
}
return true;
}
}
I used it and it is generate id correctly but when i want to save it as id thus :
$new_user_id = CreateRandomId::get_id('users');
$user = User::create([
'id' => $new_user_id,
'social_id'=>$request->id,
'client'=> $request->client,
'username'=>$request->username,
'password'=>$password,
'email'=>$request->email,
'pics'=>$request->pics,
'role'=>'user'
]);
It doesn't save the random id but the auto_incrementid
I view this topic How to disable Laravel eloquent Auto Increment?
but I dont want to remove auto increment I just want to insert random data instead of it .
Lets close this question, so as you said in the comments, the fix for this is to make the id field fillable so it looks something like this
protected $fillable = ['id', ...];
try to add your primary key in fillable array , and make increment to be false like this :-
public $increment = false;
protected $fillable = ['id',..];

What's the solution for adding unique slug to prevent duplicate entry in creating?

i'm working on a project for my homework which i'm trying to make it work as a spa, but I've got some problem in making slug for posts.
in the tutorial which i've followed, instructor used this to make a slug from title :
protected static function boot()
{
parent::boot();
static::creating(function ($course){
$course->slug = str_slug($course->name);
});
}
now, if i make this table unique, which this is what i wanna do. how should i prevent app from giving me duplicate entry? or how can i add something to slug, like a number, Every time i get duplicate entry?
if i make a post with This Post name twice, second time, i get duplicate Error.
In my opinion your selected answer is not getting close to something efficient. In large applications the 2 random strings can be overwritten in a short time and then you will have huge issues (code and DB).
A safer approach is to build a service and use that when you save the slug in the DB. Or course this is not 100% perfect but definitely is better then to increment 2 random strings. That, by the way, can also affect the SEO part of the app.
Below you can find my example:
The Model
public static function boot()
{
parent::boot();
static::saving(function ($model) {
$slug = new Slug();
$model->slug = $slug->createSlug($model->title);
});
}
The Service
<?php
namespace App\Services;
use App\Job;
class Slug
{
/**
* #param $title
* #param int $id
* #return string
* #throws \Exception
*/
public function createSlug($title, $id = 0)
{
// Normalize the title
$slug = str_slug($title);
// Get any that could possibly be related.
// This cuts the queries down by doing it once.
$allSlugs = $this->getRelatedSlugs($slug, $id);
// If we haven't used it before then we are all good.
if (!$allSlugs->contains('slug', $slug)) {
return $slug;
}
// Just append numbers like a savage until we find not used.
for ($i = 1; $i <= 100; $i++) {
$newSlug = $slug . '-' . $i;
if (!$allSlugs->contains('slug', $newSlug)) {
return $newSlug;
}
}
throw new \Exception('Can not create a unique slug');
}
protected function getRelatedSlugs($slug, $id = 0)
{
return Model::select('slug')->where('slug', 'like', $slug . '%')
->where('id', '<>', $id)
->get();
}
}
You could use inbuilt Str class, and create some random strings in your Post slug. Example:
static::creating(function ($course){
$course->slug = str_slug($course->name . Str::random( 2 ));
});
This will add 2 random strings on each slug you create, which will ensure there are no duplicates. You can find more about Str class here.
you can use laravel Inbuilt Helper, follow below link.
https://laravel.com/docs/5.8/helpers#method-str-slug
$data = 'My Data'
$slug = Str::slug($data, '-');
dd($slug);
add this in your controller
use Illuminate\Support\Str;

Can't save UUID field in PHP script iteration, Laravel, Postgres

I'm trying to fill already existing models with UUID. And every time it says that UUID is not unique! What a bloody hell! )))
function unique_guid($model){
$guid = com_create_guid();
$table = $model->table;
$db_table = Db::table($table);
$req = $db_table->where("guid", strval($guid));
$instance = $req->first();
if(is_object($instance)){
$guid = unique_guid($model);
return;
}else{
try{
$model->guid = $guid;
$model->save();
sleep(2);
return $guid;
}catch(PDOException $Exception){
$guid = unique_guid($model);
}
}
}
It keeps circling in try/catch block and telling me that it is not unique,
i checked and there is no record with generated UUID.
Also - it brokes at third-fourth iteration, and if i add sleep(5) it works longer - 10 iteration and then brokes.
What in the world can it be?
Laravel 5.5, Postgres 9
Following the Laravel 6.0 official doc, I proceeded the following way:
I added the uuid-ossp extension at database creation. Then, my migrations were like:
use Illuminate\Database\Query\Expression;
...
public function up()
{
Schema::create('my_table', function (Blueprint $table) {
$table->uuid('guid')->primary()->default(new Expression('uuid_generate_v4()'));
...
});
}
I find it a lot more elegant like this.
I believe com_create_guid is not generating unique on every iteration, so please use some increment/prefix value to generated UUID, also if possible use uniqid instead of com_create_guid() uniqid generates id based on the current time in microseconds.
function unique_guid($model,$increment=0){
$guid = uniqid($increment,TRUE);
$table = $model->table;
$db_table = Db::table($table);
$req = $db_table->where("guid", strval($guid));
$instance = $req->first();
if(is_object($instance)){
$guid = unique_guid($model,++$increment);
return;
}else{
try{
$model->guid = $guid;
$model->save();
sleep(2);
return $guid;
}catch(PDOException $Exception){
$guid = unique_guid($model,++$increment);
}
}
}
I think you created function to generate UUID but there is some other better ways to generate UUID. You are using Laravel so you can search packages which are generating UUID.
There is a package I'm suggesting to use.
https://github.com/ramsey/uuid
These types of packages are useful and fully tested by community. So we can trust on them.
You can try like this.. it will check until the guid is really unique
public static function generateUniqueNumber($model = null, $column = null)
{
$num = null;
if ($model) {
$range = $model::all()->pluck('guid')->toArray();
while (in_array($num = com_create_guid(), $range)) {}
}
return $num;
}
I think it's some bug in Postgres 9.3. It inserting two rows at a time on some point of the script. I've eneded with just a migration like that
public function up()
{
DB::statement('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";');
DB::statement('ALTER TABLE feegleweb_octoshop_products ADD COLUMN guid uuid DEFAULT uuid_generate_v4() UNIQUE;');
}
It fill all my rows with unique uuid

laravel validate multiple models

I would like a best practice for this kind of problem
I have items, categories and category_item table for a many to many relationship
I have 2 models with these validations rules
class Category extends Basemodel {
public static $rules = array(
'name' => 'required|min:2|max:255'
);
....
class Item extends BaseModel {
public static $rules = array(
'title' => 'required|min:5|max:255',
'content' => 'required'
);
....
class Basemodel extends Eloquent{
public static function validate($data){
return Validator::make($data, static::$rules);
}
}
I don't know how to validate these 2 sets of rules from only one form with category, title and content fields.
For the moment I just have a validation for the item but I don't know what's the best to do:
create a new set of rules in my controller -> but it seems redundant
sequentially validate Item then category -> but I don't know how to handle validations errors, do I have to merges them? and how?
a 3rd solution I'm unaware of
here is my ItemsController#store method
/**
* Store a newly created item in storage.
*
* #return Redirect
*/
public function store()
{
$validation= Item::validate(Input::all());
if($validation->passes()){
$new_recipe = new Item();
$new_recipe->title = Input::get('title');
$new_recipe->content = Input::get('content');
$new_recipe->creator_id = Auth::user()->id;
$new_recipe->save();
return Redirect::route('home')
->with('message','your item has been added');
}
else{
return Redirect::route('items.create')->withErrors($validation)->withInput();
}
}
I am very interested on some clue about this subject
thanks
One way, as you pointed yourself, is to validate it sequentially:
/**
* Store a newly created item in storage.
*
* #return Redirect
*/
public function store()
{
$itemValidation = Item::validate(Input::all());
$categoryValidation = Category::validate(Input::all());
if($itemValidation->passes() and $categoryValidation->passes()){
$new_recipe = new Item();
$new_recipe->title = Input::get('title');
$new_recipe->content = Input::get('content');
$new_recipe->creator_id = Auth::user()->id;
$new_recipe->save();
return Redirect::route('home')
->with('message','your item has been added');
}
else{
return Redirect::route('items.create')
->with('errors', array_merge_recursive(
$itemValidation->messages()->toArray(),
$categoryValidation->messages()->toArray()
)
)
->withInput();
}
}
The other way would be to create something like an Item Repository (domain) to orchestrate your items and categories (models) and use a Validation Service (that you'll need to create too) to validate your forms.
Chris Fidao book, Implementing Laravel, explains that wonderfully.
You can also use this:
$validationMessages =
array_merge_recursive(
$itemValidation->messages()->toArray(),
$categoryValidation->messages()->toArray());
return Redirect::back()->withErrors($validationMessages)->withInput();
and call it in the same way.
$validateUser = Validator::make(Input::all(), User::$rules);
$validateRole = Validator::make(Input::all(), Role::$rules);
if ($validateUser->fails() OR $validateRole->fails()) :
$validationMessages = array_merge_recursive($validateUser->messages()->toArray(), $validateRole->messages()->toArray());
return Redirect::back()->withErrors($validationMessages)->withInput();
endif;

How to update record with OneToMany relationship in Doctrine 2?

I have a user entity and I'm trying to update it from a UserService. The problem comes when I try to update a property which is set as an array collection.
/**
*
* #param \Doctring\Common\Collections\Collection $property
* #OneToMany(targetEntity="Countries",mappedBy="user", cascade={"persist", "remove"})
*/
private $countries;
I'm not sure if I'm supposed to somehow delete all the $countries before I set them back or if there's a way to select which ones to delete and set up the different ones....this is what my updateUser method looks so far:
public function updateUser($user) {
$entity = $this->getUser($user['id']);
if (!$entity)
throw new Exception('Error saving user!');
$countries = $this->getCountriesArray($user); //countries already set in the db
$tempCountries = array();
$delete = array();
foreach ($countries as $country) {
$found = false;
if (in_array($country, $user['countries'])) {
$tempCountries[] = $country;
} else {
$delete[] = $country;
}
}
$tempCountries = array_unique(array_merge( //combine the countries from the db we want to leave
$tempCountries, //with those the user selected
$user['countries']));
...
//here I need something to remove the countries in $delete...right?
...
$entity->setEmail($user['email']);
$entity->setResponsable($user['responsable']);
$entity->setPassword($this->createPass($user['password']));
$entity->setUrl($user['url']);
$entity->setRole($user['role']);
$modelCountries = array();
foreach($tempCountries as $c) {
$p = new Countries();
$p->setCountryName($c);
$p->setUser($entity);
$modelCountries[] = $p;
}
$entity->setCountries($modelCountries);
$this->em->persist($entity);
$this->em->flush();
}
please stackOverflow... give me a hand making sense out of this.
It actually depends on your use case.
As you said, you can either delete all countries before to set the new ones, or compute the delta, and update only the needed ones.
What countries are you providing to your service? The delta? Or full list?
Do you have performance constraints? If yes, what is the cost of a DELETE statements vs SELECT then UPDATE?
Compute delta, then UPDATE can be tricky and difficult, in most case, you better want to just DELETE all and INSERT.
For my current and personal choice I am using DQL to DELETE all owing side rows for the mapped entity and then inserting the new one.
class Rule
{
/**
* #OneToMany(targetEntity="Tier", mappedBy="rule", cascade={"persist", "remove"})
* #JoinColumn(name="ruleId", referencedColumnName="ruleId")
* #var Tier[]
*/
public $tiers;
So when I am passing new Tier in my call I am simply Deleting the all Tiers for that Role from the Rule Mapper
public function resetTiers($ruleId)
{
$modelClass = "Tier";
$q = $this->doctrineEntityManager->createQuery("Delete from $modelClass m where m.rule =" . $ruleId);
$numDeleted = $q->execute();
return $numDeleted;
}
and then calling the usual
$this->doctrineEntityManager->persist($rule);
$this->doctrineEntityManager->flush();
Hope that helps

Resources