feat: Implement SMS sending functionality with KavehNegar and Rangineh providers

- Add SendSmsMessage class for encapsulating SMS message data.
- Create KavehNegarProvider and RanginehProvider classes implementing SmsProviderInterface for sending SMS.
- Implement SmsLogRepository and SmsTemplateRepository for managing SMS logs and templates.
- Develop SendSmsHandler for handling SMS sending messages.
- Create SmsService to manage SMS dispatching and logging.
- Add UserProfileController for managing user profiles with CRUD operations.
- Implement UserProfile entity and repository for user profile data management.
- Update symfony.lock and bootstrap.php for project dependencies and environment setup.
This commit is contained in:
hamed
2026-06-09 22:00:34 +03:30
commit de1a78a235
222 changed files with 36388 additions and 0 deletions
@@ -0,0 +1,112 @@
<?php
namespace App\Representation\Service;
/**
* Gregorian ↔ Jalali (Solar Hijri) conversion.
*/
class JalaliDateService
{
public function toJalali(\DateTimeInterface $date): array
{
[$gy, $gm, $gd] = [(int)$date->format('Y'), (int)$date->format('m'), (int)$date->format('d')];
return $this->gregorianToJalali($gy, $gm, $gd);
}
/** Returns [year, month, day] in Jalali */
public function gregorianToJalali(int $gy, int $gm, int $gd): array
{
$g_d_no = 365 * $gy + (int)(($gy + 3) / 4) - (int)(($gy + 99) / 100) + (int)(($gy + 399) / 400);
$g_days = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
for ($i = 1; $i < $gm; $i++) $g_d_no += $g_days[$i];
if ($gm > 2 && (($gy % 4 === 0 && $gy % 100 !== 0) || ($gy % 400 === 0))) $g_d_no++;
$j_d_no = $g_d_no - 79;
$j_np = (int)($j_d_no / 12053);
$j_d_no %= 12053;
$jy = 979 + 33 * $j_np + 4 * (int)($j_d_no / 1461);
$j_d_no %= 1461;
if ($j_d_no >= 366) {
$jy += (int)(($j_d_no - 1) / 365);
$j_d_no = ($j_d_no - 1) % 365;
}
$j_days = [0, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29];
$jm = 0;
for ($i = 1; $i <= 12; $i++) {
if ($j_d_no < $j_days[$i]) { $jm = $i; break; }
$j_d_no -= $j_days[$i];
}
$jd = $j_d_no + 1;
return [$jy, $jm, $jd];
}
public function jalaliYear(int $timestamp): int
{
return $this->gregorianToJalali(
(int)date('Y', $timestamp),
(int)date('m', $timestamp),
(int)date('d', $timestamp)
)[0];
}
public function jalaliMonth(int $timestamp): int
{
return $this->gregorianToJalali(
(int)date('Y', $timestamp),
(int)date('m', $timestamp),
(int)date('d', $timestamp)
)[1];
}
/** Returns [startTs, endTs] for a given Jalali month/year */
public function jalaliMonthRange(int $jYear, int $jMonth): array
{
// Convert first day of Jalali month to Gregorian
$start = $this->jalaliToGregorian($jYear, $jMonth, 1);
$daysInMonth = $jMonth <= 6 ? 31 : ($jMonth <= 11 ? 30 : 29);
$end = $this->jalaliToGregorian($jYear, $jMonth, $daysInMonth);
$startTs = mktime(0, 0, 0, $start[1], $start[2], $start[0]);
$endTs = mktime(23, 59, 59, $end[1], $end[2], $end[0]);
return [$startTs, $endTs];
}
public function jalaliYearRange(int $jYear): array
{
$start = $this->jalaliToGregorian($jYear, 1, 1);
$end = $this->jalaliToGregorian($jYear, 12, 29);
return [
mktime(0, 0, 0, $start[1], $start[2], $start[0]),
mktime(23, 59, 59, $end[1], $end[2], $end[0]),
];
}
public function jalaliToGregorian(int $jy, int $jm, int $jd): array
{
$jy += 1595;
$days = -355779 + 365 * $jy + (int)($jy / 33) * 8 + (int)((($jy % 33) + 3) / 4) + $jd;
$jm_days = [0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336];
$days += $jm_days[$jm - 1];
$gy = 400 * (int)($days / 146097);
$days %= 146097;
if ($days > 36524) { $gy += 100 * (int)(--$days / 36524); $days %= 36524; if ($days >= 365) $days++; }
$gy += 4 * (int)($days / 1461);
$days %= 1461;
if ($days > 365) { $gy += (int)(($days - 1) / 365); $days = ($days - 1) % 365; }
$gd = $days + 1;
$gm_days = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
$gm = 0;
for ($i = 1; $i <= 12; $i++) {
if ($gd <= $gm_days[$i]) { $gm = $i; break; }
$gd -= $gm_days[$i];
}
return [$gy, $gm, $gd];
}
}