classify admin
This commit is contained in:
624
app/Services/HelperService.php
Normal file
624
app/Services/HelperService.php
Normal file
@@ -0,0 +1,624 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Area;
|
||||
use App\Models\Category;
|
||||
use App\Models\Setting;
|
||||
use App\Services\CachingService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use JsonException;
|
||||
|
||||
class HelperService
|
||||
{
|
||||
public static function changeEnv($updateData = []): bool
|
||||
{
|
||||
if (count($updateData) > 0) {
|
||||
// Read .env-file
|
||||
$env = file_get_contents(base_path() . '/.env');
|
||||
// Split string on every " " and write into array
|
||||
// $env = explode(PHP_EOL, $env);
|
||||
$env = preg_split('/\r\n|\r|\n/', $env);
|
||||
$env_array = [];
|
||||
foreach ($env as $env_value) {
|
||||
if (empty($env_value)) {
|
||||
// Add and Empty Line
|
||||
$env_array[] = '';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$entry = explode('=', $env_value, 2);
|
||||
$env_array[$entry[0]] = $entry[0] . '="' . str_replace('"', '', $entry[1]) . '"';
|
||||
}
|
||||
|
||||
foreach ($updateData as $key => $value) {
|
||||
$env_array[$key] = $key . '="' . str_replace('"', '', $value) . '"';
|
||||
}
|
||||
// Turn the array back to a String
|
||||
$env = implode("\n", $env_array);
|
||||
|
||||
// And overwrite the .env with the new data
|
||||
file_put_contents(base_path() . '/.env', $env);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description - This function will return the nested category Option tags using in memory optimization
|
||||
*/
|
||||
public static function childCategoryRendering(&$categories, int $level = 0, ?string $parentCategoryID = ''): bool
|
||||
{
|
||||
// Foreach loop only on the parent category objects
|
||||
foreach (collect($categories)->where('parent_category_id', $parentCategoryID) as $key => $category) {
|
||||
echo "<option value='$category->id'>" . str_repeat(' ', $level * 4) . '|-- ' . $category->name . '</option>';
|
||||
// Once the parent category object is rendered we can remove the category from the main object so that redundant data can be removed
|
||||
$categories->forget($key);
|
||||
|
||||
// Now fetch the subcategories of the main category
|
||||
$subcategories = $categories->where('parent_category_id', $category->id);
|
||||
if (! empty($subcategories)) {
|
||||
// Finally if subcategories are available then call the recursive function & see the magic
|
||||
self::childCategoryRendering($categories, $level + 1, $category->id);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function buildNestedChildSubcategoryObject($categories)
|
||||
{
|
||||
// Used json_decode & encode simultaneously because i wanted to convert whole nested array into object
|
||||
try {
|
||||
return json_decode(json_encode(self::buildNestedChildSubcategoryArray($categories), JSON_THROW_ON_ERROR), false, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException) {
|
||||
return (object) [];
|
||||
}
|
||||
}
|
||||
|
||||
private static function buildNestedChildSubcategoryArray($categories)
|
||||
{
|
||||
$children = [];
|
||||
// First Add Parent Categories to root level in an array
|
||||
foreach ($categories->toArray() as $value) {
|
||||
if ($value['parent_category_id'] == '') {
|
||||
$children[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Then loop on the Parent Category to find the children categories
|
||||
foreach ($children as $key => $value) {
|
||||
$children[$key]['subcategories'] = self::findChildCategories($categories->toArray(), $value['id']);
|
||||
}
|
||||
|
||||
return $children;
|
||||
}
|
||||
|
||||
public static function findChildCategories($arr, $parent)
|
||||
{
|
||||
$children = [];
|
||||
foreach ($arr as $key => $value) {
|
||||
if ($value['parent_category_id'] == $parent) {
|
||||
$children[] = $value;
|
||||
}
|
||||
}
|
||||
foreach ($children as $key => $value) {
|
||||
$children[$key]['subcategories'] = self::findChildCategories($arr, $value['id']);
|
||||
}
|
||||
|
||||
return $children;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sagar's Code :
|
||||
* in this i have approached the reverse object moving & removing.
|
||||
* which is not working as of now.
|
||||
* but will continue working on this in future as it seems bit optimized approach from the current one
|
||||
public static function buildNestedChildSubcategoryObject($categories, $finalCategories = []) {
|
||||
echo "<pre>";
|
||||
// Foreach loop only on the parent category objects
|
||||
if (!empty($finalCategories)) {
|
||||
$finalCategories = $categories->whereNull('parent_category_id');
|
||||
}
|
||||
foreach ($categories->whereNotNull('parent_category_id')->sortByDesc('parent_category_id') as $key => $category) {
|
||||
echo "----------------------------------------------------------------------<br>";
|
||||
$parentCategoryIndex = $categories->search(function ($data) use ($category) {
|
||||
return $data['id'] == $category->parent_category_id;
|
||||
});
|
||||
if (!$parentCategoryIndex) {
|
||||
continue;
|
||||
}
|
||||
// echo "*** This category will be moved to its parent category object ***<br>";
|
||||
// print_r($category->toArray());
|
||||
|
||||
// Once the parent category object is rendered we can remove the category from the main object so that redundant data can be removed
|
||||
$categories[$parentCategoryIndex]->subcategories[] = $category->toArray();
|
||||
|
||||
$categories->forget($key);
|
||||
echo "<br>*** After all the operation main categories object will look like this ***<br>";
|
||||
print_r($categories->toArray());
|
||||
|
||||
if (!empty($categories)) {
|
||||
// Finally if subcategories are available then call the recursive function & see the magic
|
||||
return self::buildNestedChildSubcategoryObject($categories, $finalCategories);
|
||||
}
|
||||
}
|
||||
return $categories;
|
||||
} */
|
||||
|
||||
public static function findParentCategory($category, $finalCategories = [])
|
||||
{
|
||||
$category = Category::find($category);
|
||||
|
||||
if (! empty($category)) {
|
||||
$finalCategories[] = $category->id;
|
||||
|
||||
if (! empty($category->parent_category_id)) {
|
||||
$finalCategories[] = self::findParentCategory($category->id, $finalCategories);
|
||||
}
|
||||
}
|
||||
|
||||
return $finalCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Slug for any model
|
||||
*
|
||||
* @param $model - Instance of Model
|
||||
*/
|
||||
public static function generateUniqueSlug($model, string $slug, ?int $excludeID = null, int $count = 0): string
|
||||
{
|
||||
/* NOTE : This can be improved by directly calling in the UI on type of title via AJAX */
|
||||
$slug = Str::slug($slug);
|
||||
$newSlug = $count ? $slug . '-' . $count : $slug;
|
||||
|
||||
$data = $model::where('slug', $newSlug);
|
||||
if ($excludeID !== null) {
|
||||
$data->where('id', '!=', $excludeID);
|
||||
}
|
||||
|
||||
if (in_array(SoftDeletes::class, class_uses_recursive($model), true)) {
|
||||
$data->withTrashed();
|
||||
}
|
||||
while ($data->exists()) {
|
||||
return self::generateUniqueSlug($model, $slug, $excludeID, $count + 1);
|
||||
}
|
||||
|
||||
return $newSlug;
|
||||
}
|
||||
|
||||
public static function findAllCategoryIds($model): array
|
||||
{
|
||||
$ids = [];
|
||||
|
||||
foreach ($model as $item) {
|
||||
$ids[] = $item['id'];
|
||||
|
||||
if (! empty($item['children'])) {
|
||||
$ids = array_merge($ids, self::findAllCategoryIds($item['children']));
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
public static function generateRandomSlug($length = 10)
|
||||
{
|
||||
// Generate a random string of lowercase letters and numbers
|
||||
$characters = 'abcdefghijklmnopqrstuvwxyz-';
|
||||
$slug = '';
|
||||
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$index = rand(0, strlen($characters) - 1);
|
||||
$slug .= $characters[$index];
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply location filters to Item query with fallback logic
|
||||
* Priority: area_id > city > state > country > latitude/longitude
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param callable $applyAuthFilters Function to apply auth-specific filters
|
||||
* @return array ['query' => $query, 'message' => $locationMessage]
|
||||
*/
|
||||
public static function applyLocationFilters($query, $request, $applyAuthFilters)
|
||||
{
|
||||
$isHomePage = $request->current_page === 'home';
|
||||
$locationMessage = null;
|
||||
$hasLocationFilter = $request->latitude !== null && $request->longitude !== null;
|
||||
$hasCityFilter = !empty($request->city);
|
||||
$hasStateFilter = !empty($request->state);
|
||||
$hasCountryFilter = !empty($request->country);
|
||||
$hasAreaFilter = !empty($request->area_id);
|
||||
$hasAreaLocationFilter = !empty($request->area_latitude) && !empty($request->area_longitude);
|
||||
|
||||
$cityName = $request->city ?? null;
|
||||
$stateName = $request->state ?? null;
|
||||
$countryName = $request->country ?? null;
|
||||
$areaId = $request->area_id ?? null;
|
||||
|
||||
$cityItemCount = 0;
|
||||
$stateItemCount = 0;
|
||||
$countryItemCount = 0;
|
||||
$areaItemCount = 0;
|
||||
$areaName = null;
|
||||
|
||||
// Handle area location filter (find closest area by lat/long)
|
||||
if ($hasAreaLocationFilter && !$hasAreaFilter) {
|
||||
$areaLat = $request->area_latitude;
|
||||
$areaLng = $request->area_longitude;
|
||||
$haversine = "(6371 * acos(cos(radians($areaLat))
|
||||
* cos(radians(latitude))
|
||||
* cos(radians(longitude) - radians($areaLng))
|
||||
+ sin(radians($areaLat)) * sin(radians(latitude))))";
|
||||
|
||||
$closestArea = Area::whereNotNull('latitude')
|
||||
->whereNotNull('longitude')
|
||||
->selectRaw("areas.*, {$haversine} AS distance")
|
||||
// ->orderBy('distance', 'asc')
|
||||
|
||||
->orderByRaw(
|
||||
'(6371 * acos(
|
||||
cos(radians(?)) *
|
||||
cos(radians(latitude)) *
|
||||
cos(radians(longitude) - radians(?)) +
|
||||
sin(radians(?)) * sin(radians(latitude))
|
||||
)) ASC',
|
||||
[$areaLat, $areaLng, $areaLat]
|
||||
)
|
||||
|
||||
->first();
|
||||
|
||||
if ($closestArea) {
|
||||
$hasAreaFilter = true;
|
||||
$areaId = $closestArea->id;
|
||||
}
|
||||
}
|
||||
|
||||
// Get area name if area filter is set
|
||||
if ($hasAreaFilter) {
|
||||
$area = Area::find($areaId);
|
||||
$areaName = $area ? $area->name : __('the selected area');
|
||||
}
|
||||
|
||||
// Save base query before location filters for fallback
|
||||
$baseQueryBeforeLocation = clone $query;
|
||||
|
||||
// First, check for area filter (highest priority)
|
||||
if ($hasAreaFilter) {
|
||||
$areaQuery = clone $query;
|
||||
$areaQuery->where('area_id', $areaId);
|
||||
$areaQuery = $applyAuthFilters($areaQuery);
|
||||
$areaItemExists = $areaQuery->exists();
|
||||
|
||||
if ($areaItemExists) {
|
||||
$query = $areaQuery;
|
||||
$areaItemCount = 1;
|
||||
} else {
|
||||
if ($isHomePage) {
|
||||
$locationMessage = __('No Ads found in :area. Showing all available Ads.', ['area' => $areaName]);
|
||||
} else {
|
||||
$query = $areaQuery;
|
||||
}
|
||||
$areaItemCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Second, check for city filter
|
||||
if ($hasCityFilter && (!$hasAreaFilter || $areaItemCount == 0)) {
|
||||
$cityQuery = clone $query;
|
||||
$cityQuery->where('city', $cityName);
|
||||
$cityQuery = $applyAuthFilters($cityQuery);
|
||||
$cityItemExists = $cityQuery->exists();
|
||||
|
||||
if ($cityItemExists) {
|
||||
$query = $cityQuery;
|
||||
$cityItemCount = 1;
|
||||
if ($hasAreaFilter && $areaItemCount == 0 && $isHomePage) {
|
||||
$locationMessage = __('No Ads found in :city. Showing all available Ads.', ['city' => $cityName]);
|
||||
}
|
||||
} else {
|
||||
$cityItemCount = 0;
|
||||
if ($isHomePage) {
|
||||
if (!$locationMessage) {
|
||||
$locationMessage = __('No Ads found in :city. Showing all available Ads.', ['city' => $cityName]);
|
||||
} else {
|
||||
$locationMessage = __('No Ads found in :area or :city. Showing all available Ads.', ['area' => $areaName, 'city' => $cityName]);
|
||||
}
|
||||
} else {
|
||||
$query = $cityQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Third, check for state filter
|
||||
if ($hasStateFilter && (!$hasAreaFilter || $areaItemCount == 0) && (!$hasCityFilter || $cityItemCount == 0)) {
|
||||
$stateQuery = clone $query;
|
||||
$stateQuery->where('state', $stateName);
|
||||
$stateQuery = $applyAuthFilters($stateQuery);
|
||||
$stateItemExists = $stateQuery->exists();
|
||||
|
||||
if ($stateItemExists) {
|
||||
$query = $stateQuery;
|
||||
$stateItemCount = 1;
|
||||
if (($hasAreaFilter && $areaItemCount == 0) || ($hasCityFilter && $cityItemCount == 0)) {
|
||||
if ($isHomePage) {
|
||||
$locationMessage = __('No Ads found in :state. Showing all available Ads.', ['state' => $stateName]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$stateItemCount = 0;
|
||||
if ($isHomePage) {
|
||||
if (!$locationMessage) {
|
||||
$locationMessage = __('No Ads found in :state. Showing all available Ads.', ['state' => $stateName]);
|
||||
} else {
|
||||
$parts = [];
|
||||
if ($hasAreaFilter && $areaItemCount == 0) {
|
||||
$parts[] = $areaName;
|
||||
}
|
||||
if ($hasCityFilter && $cityItemCount == 0) {
|
||||
$parts[] = $cityName;
|
||||
}
|
||||
$parts[] = $stateName;
|
||||
$locationMessage = __('No Ads found in :locations. Showing all available Ads.', ['locations' => implode(', ', $parts)]);
|
||||
}
|
||||
} else {
|
||||
$query = $stateQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fourth, check for country filter
|
||||
if ($hasCountryFilter && (!$hasAreaFilter || $areaItemCount == 0) && (!$hasCityFilter || $cityItemCount == 0) && (!$hasStateFilter || $stateItemCount == 0)) {
|
||||
$countryQuery = clone $query;
|
||||
$countryQuery->where('country', $countryName);
|
||||
$countryQuery = $applyAuthFilters($countryQuery);
|
||||
$countryItemExists = $countryQuery->exists();
|
||||
|
||||
if ($countryItemExists) {
|
||||
$query = $countryQuery;
|
||||
$countryItemCount = 1;
|
||||
if (($hasAreaFilter && $areaItemCount == 0) || ($hasCityFilter && $cityItemCount == 0) || ($hasStateFilter && $stateItemCount == 0)) {
|
||||
if ($isHomePage) {
|
||||
$locationMessage = __('No Ads found in :country. Showing all available Ads.', ['country' => $countryName]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$countryItemCount = 0;
|
||||
if ($isHomePage) {
|
||||
if (!$locationMessage) {
|
||||
$locationMessage = __('No Ads found in :country. Showing all available Ads.', ['country' => $countryName]);
|
||||
} else {
|
||||
$parts = [];
|
||||
if ($hasAreaFilter && $areaItemCount == 0) {
|
||||
$parts[] = $areaName;
|
||||
}
|
||||
if ($hasCityFilter && $cityItemCount == 0) {
|
||||
$parts[] = $cityName;
|
||||
}
|
||||
if ($hasStateFilter && $stateItemCount == 0) {
|
||||
$parts[] = $stateName;
|
||||
}
|
||||
$parts[] = $countryName;
|
||||
$locationMessage = __('No Ads found in :locations. Showing all available Ads.', ['locations' => implode(', ', $parts)]);
|
||||
}
|
||||
} else {
|
||||
$query = $countryQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fifth, handle latitude/longitude location-based search
|
||||
$hasHigherPriorityFilter = ($hasAreaFilter && $areaItemCount > 0) || ($hasCityFilter && $cityItemCount > 0) || ($hasStateFilter && $stateItemCount > 0) || ($hasCountryFilter && $countryItemCount > 0);
|
||||
if ($hasLocationFilter && ((!$hasAreaFilter && !$hasCityFilter && !$hasStateFilter && !$hasCountryFilter) || $hasHigherPriorityFilter)) {
|
||||
$latitude = $request->latitude;
|
||||
$longitude = $request->longitude;
|
||||
$requestedRadius = (float)($request->radius ?? null);
|
||||
$exactLocationRadius = $request->radius;
|
||||
|
||||
$haversine = '(6371 * acos(cos(radians(?))
|
||||
* cos(radians(latitude))
|
||||
* cos(radians(longitude) - radians(?))
|
||||
+ sin(radians(?)) * sin(radians(latitude))))';
|
||||
|
||||
$exactLocationQuery = clone $query;
|
||||
$exactLocationQuery
|
||||
->select('items.*')
|
||||
->selectRaw("$haversine AS distance", [$latitude, $longitude, $latitude])
|
||||
->where('latitude', '!=', 0)
|
||||
->where('longitude', '!=', 0)
|
||||
// CHANGE THIS: Use whereRaw instead of having to support pagination count
|
||||
// Use <= so radius=0.0 still returns items at the exact same coordinates (distance 0)
|
||||
->whereRaw("$haversine <= ?", [$latitude, $longitude, $latitude, $exactLocationRadius])
|
||||
->orderBy('distance', 'asc');
|
||||
|
||||
if (Auth::check()) {
|
||||
$exactLocationQuery->with(['item_offers' => function ($q) {
|
||||
$q->where('buyer_id', Auth::user()->id);
|
||||
}, 'user_reports' => function ($q) {
|
||||
$q->where('user_id', Auth::user()->id);
|
||||
}]);
|
||||
|
||||
$currentURI = explode('?', $request->getRequestUri(), 2);
|
||||
if ($currentURI[0] == '/api/my-items') {
|
||||
$exactLocationQuery->where(['user_id' => Auth::user()->id])->withTrashed();
|
||||
} else {
|
||||
$exactLocationQuery->where('status', 'approved')->has('user')->onlyNonBlockedUsers()->getNonExpiredItems();
|
||||
}
|
||||
} else {
|
||||
$exactLocationQuery->where('status', 'approved')->getNonExpiredItems();
|
||||
}
|
||||
|
||||
$exactLocationExists = $exactLocationQuery->exists();
|
||||
|
||||
if ($exactLocationExists) {
|
||||
$query = $exactLocationQuery;
|
||||
} else {
|
||||
$searchRadius = $requestedRadius !== null && $requestedRadius > 0 ? $requestedRadius : 50;
|
||||
|
||||
$nearbyQuery = clone $query;
|
||||
$nearbyQuery
|
||||
->select('items.*')
|
||||
->selectRaw("$haversine AS distance", [$latitude, $longitude, $latitude])
|
||||
->where('latitude', '!=', 0)
|
||||
->where('longitude', '!=', 0)
|
||||
// CHANGE THIS: Use whereRaw instead of having
|
||||
->whereRaw("$haversine < ?", [$latitude, $longitude, $latitude, $searchRadius])
|
||||
->orderBy('distance', 'asc');
|
||||
|
||||
$nearbyQuery = $applyAuthFilters($nearbyQuery);
|
||||
$nearbyItemExists = $nearbyQuery->exists();
|
||||
|
||||
if ($nearbyItemExists) {
|
||||
$query = $nearbyQuery;
|
||||
if (!$locationMessage) {
|
||||
$locationMessage = __('No Ads found at your location. Showing nearby Ads.');
|
||||
}
|
||||
} else {
|
||||
if ($isHomePage) {
|
||||
$query = clone $baseQueryBeforeLocation;
|
||||
if (!$locationMessage) {
|
||||
$locationMessage = __('No Ads found at your location. Showing all available Ads.');
|
||||
}
|
||||
} else {
|
||||
$query = $nearbyQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ['query' => $query, 'message' => $locationMessage];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get watermark configuration status (enabled/disabled)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function getWatermarkConfigStatus(): bool
|
||||
{
|
||||
$enabled = CachingService::getSystemSettings('watermark_enabled');
|
||||
return !empty($enabled) && (int)$enabled === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get watermark configuration as decoded array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getWatermarkConfigDecoded(): array
|
||||
{
|
||||
$settings = CachingService::getSystemSettings([
|
||||
'watermark_enabled',
|
||||
'watermark_image',
|
||||
'watermark_opacity',
|
||||
'watermark_size',
|
||||
'watermark_style',
|
||||
'watermark_position',
|
||||
'watermark_rotation',
|
||||
]);
|
||||
|
||||
return [
|
||||
'enabled' => (int)($settings['watermark_enabled'] ?? 0),
|
||||
'watermark_image' => $settings['watermark_image'] ?? null,
|
||||
'opacity' => (int)($settings['watermark_opacity'] ?? 25),
|
||||
'size' => (int)($settings['watermark_size'] ?? 10),
|
||||
'style' => $settings['watermark_style'] ?? 'tile',
|
||||
'position' => $settings['watermark_position'] ?? 'center',
|
||||
'rotation' => (int)($settings['watermark_rotation'] ?? -30),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific setting value
|
||||
*
|
||||
* @param string $key
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getSettingData(string $key): ?string
|
||||
{
|
||||
return CachingService::getSystemSettings($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate item expiry date based on package listing duration
|
||||
* Priority: listing_duration > package expiry > default
|
||||
*
|
||||
* @param \App\Models\Package|null $package
|
||||
* @param \App\Models\UserPurchasedPackage|null $userPackage
|
||||
* @return \Carbon\Carbon|null
|
||||
*/
|
||||
public static function calculateItemExpiryDate($package = null, $userPackage = null)
|
||||
{
|
||||
|
||||
if (!$package) {
|
||||
$freeAdUnlimited = Setting::where('name', 'free_ad_unlimited')->value('value') ?? 0;
|
||||
$freeAdDays = Setting::where('name', 'free_ad_duration_days')->value('value') ?? 0;
|
||||
// Unlimited free ads
|
||||
if ((int) $freeAdUnlimited === 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Limited free ads
|
||||
if (!empty($freeAdDays) && (int) $freeAdDays > 0) {
|
||||
return Carbon::now()->addDays((int) $freeAdDays);
|
||||
}
|
||||
|
||||
// Safety fallback (no expiry)
|
||||
return null;
|
||||
}
|
||||
|
||||
// ---------------------------------------
|
||||
// PACKAGE LOGIC (existing, unchanged)
|
||||
// ---------------------------------------
|
||||
|
||||
$listingDurationType = $package->listing_duration_type ?? null;
|
||||
$listingDurationDays = $package->listing_duration_days ?? null;
|
||||
|
||||
// If listing_duration_type is null → use package expiry
|
||||
if ($listingDurationType === null) {
|
||||
if ($userPackage && $userPackage->end_date) {
|
||||
return Carbon::parse($userPackage->end_date);
|
||||
}
|
||||
|
||||
if ($package->duration === 'unlimited') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Carbon::now()->addDays((int) $package->duration);
|
||||
}
|
||||
|
||||
if ($listingDurationType === 'package') {
|
||||
if ($package->duration === 'unlimited') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Carbon::now()->addDays((int) $package->duration);
|
||||
}
|
||||
|
||||
if ($listingDurationType === 'custom') {
|
||||
if (!empty($listingDurationDays) && (int) $listingDurationDays > 0) {
|
||||
return Carbon::now()->addDays((int) $listingDurationDays);
|
||||
}
|
||||
|
||||
return Carbon::now()->addDays(30);
|
||||
}
|
||||
|
||||
// Standard fallback
|
||||
if (!empty($listingDurationDays) && (int) $listingDurationDays > 0) {
|
||||
return Carbon::now()->addDays((int) $listingDurationDays);
|
||||
}
|
||||
|
||||
return Carbon::now()->addDays(30);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user