Laravel'de Para Birimi İşlemleri
Herkese merhaba,
Bu yazımızda Laravel projemizde para birimini nasıl tutacağımızı ele alacağız.
Genellikle float ya da decimal gibi yapılarda tutulsa da, hesaplamalarda daha kolay olması ve yuvarlama farkı gibi hatalardan sakınmak adına, para birimini integer tipinde tutmanız tavsiye edilir.
Hemen bir örnek ile başlayalım.
Önce paketler adında bir model oluşturacağız.
Ben, öncelikle model üzerinden başlamayı seviyorum. Ardından -m etiketi ile migration oluşturuyorum.
php artisan make:model Package -m
Bu komut, bize 2 tane dosya oluşturacak;
app/Models/Package.php
ve
database/migrations/2023_04_06_194259_create_packages_table.php
migration dosyasının başındaki tarih, o anki tarihe göre oluşturuluyor.
Migration dosyamızın içeriği;
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up(): void { Schema::create('packages', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('slug')->unique(); $table->unsignedBigInteger('price')->index(); $table->string('meta_title'); $table->text('meta_description'); $table->string('meta_keywords'); $table->timestamps(); }); } public function down(): void { Schema::dropIfExists('packages'); } };
app/Models/Package.php dosyamıza gidelim ve ayarlarımızı yapalım;
namespace App\Models; use App\Traits\FormatPrice; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Str; class Package extends Model { use HasFactory, HasSlug, FormatPrice; protected $fillable = [ 'name', 'slug', 'price', 'meta_title', 'meta_description', 'meta_keywords', ];
Burada FormatPrice isimli bir Trait kullandığımızı görüyorsunuz. Hemen izah edelim.
Fiyat tutacağımız tüm olası modellerde kullanabilmek için bir Trait hazırlayacağız.
Trait, PHP'de kod tekrarının önüne geçmek için, aynı yapıyı birden fazla yerde kullanacaksak işimizi kolaylaştıran bir yapıdır.
Detaylı bilgi için bu linki ziyaret edebilirsiniz;
https://www.php.net/manual/en/language.oop5.traits.php
Laravel'de Trait oluşturmak için bize sunulmuş bir artisan komutu bulunmuyor. Bu yüzden bu işlemi kendimiz gerçekleştireceğiz.
Öncelikle app klasörü içinde Traits adında bir klasör oluşturuyoruz. Olası tüm Trait'lerimi bu klasör altında tutacağım.
Ardından içerisine FormatPrice.php dosyamızı oluşturuyoruz.
app/Traits/FormatPrice.php içeriği;
namespace App\Traits; use Illuminate\Database\Eloquent\Casts\Attribute; trait FormatPrice { protected function price(): Attribute { return Attribute::make( get: fn ($value) => $value / 100, set: fn ($value) => $value * 100, ); } protected function formattedPrice(): Attribute { return Attribute::make( get: fn () => '₺'.' '.number_format($this->price, 2, ',', '.') ); } }
Buradaki metodları sırasıyla açıklayalım.
price fonksiyonumuzda get ve set yöntemleri ile veritabanına veri kaydederken ve çekerken bazı işlemleri otomatize ediyoruz.
set yöntemi, veritabanına fiyatı kaydederken, değeri 100 ile çarparak integer olarak kaydedecek.
get yöntemi, veritabanından fiyatı okurken, integer değeri 100'e bölerek fiyatı alacak.
Attribute casting işlemi yaparken, metod isminin, ilgili veritabanı sütunu ile aynı olmasına dikkat edin.
Package modelinde, 'price' olarak sütunu tuttuğumuz için, aynı ismi kullandım.
İkinci fonksiyonumuz ise formattedPrice.
Burada da fiyatı PHP'nin number_format fonksiyonuna göndererek başına Türk Lirası sembolunu ekletiyor ve ziyaretçilere daha okunaklı bir çıktı verilmesini sağlıyoruz.
Şimdi bu 2 fonksiyonu örneklerle açıklayalım;
Paketimizin fiyatının 1000 TL olduğunu varsayalım.
Bunu kaydederken price fonksiyonundaki set metodu devreye girecek ve 1000 * 100 = 100000 olarak değeri veritabanına kayıt edecek.
Bu fiyatı çekerken de;
$package = app\Models\Package::find(1); $package->price // bu da bize 100000 / 100 = 1000 değerini verecek
Eğer formattedPrice kullanırsam;
$package->formatted_price // bu da bana ₺ 1.000,00 şeklinde çıktı verecek
Fiyat bilgisini unsignedBigInteger tutmam bana bir takım avantajlar sağladı.
1-) integer tipinde olduğu ve index attığım için, okuma işlemleri çok daha hızlı olacak
2-) float ya da decimal işlemlerinde karşılaşılabilecek yuvarlama hatalarından sakınmış oldum.
NOT:İlla unsignedBigInteger kullanmanız gerekmiyor ama daha çok hane tuttuğu için bunu tercih ettim.
Integer türlerinin farklarını aşağıdaki görselde inceleyebilirsiniz;
Türkhosting tarafından sunulan Laravel Hosting paketlerimizden birini satın alarak, siz de Laravel projelerinizi hızlıca yayına alabilirsiniz!