Skip to content

Commit

Permalink
Create necessary endpoints and filters
Browse files Browse the repository at this point in the history
  • Loading branch information
Arman001011 committed Jan 13, 2025
1 parent afaae1c commit b9593b8
Show file tree
Hide file tree
Showing 14 changed files with 298 additions and 24 deletions.
29 changes: 29 additions & 0 deletions app/Http/Controllers/Api/OrganizationController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\OrganizationsRequest;
use App\Http\Resources\OrganizationResource;
use App\Models\Organization;

class OrganizationController extends Controller
{
public function index(OrganizationsRequest $request) {
$organizations = Organization::with(['building', 'activities'])
->filter($request->get('filter'))
->jsonPaginate();

return OrganizationResource::collection($organizations)
->response();
}

public function show(Organization $organization) {
if ($organization->status != Organization::STATUS_ACTIVE) {
abort(404);
}
$organization->load(['building', 'activities']);

return (new OrganizationResource($organization))->response();
}
}
12 changes: 0 additions & 12 deletions app/Http/Controllers/Api/TestController.php

This file was deleted.

35 changes: 35 additions & 0 deletions app/Http/Requests/OrganizationsRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class OrganizationsRequest extends FormRequest
{
public function rules()
{
return [
'filter' => ['sometimes', 'nullable', 'array'],
'filter.building_id' => ['sometimes', 'nullable', 'exists:buildings,id'],
'filter.activity_id' => ['sometimes', 'nullable', 'exists:activities,id'],
'filter.name' => ['sometimes', 'nullable', 'string', 'min:2', 'max:15'],
'filter.activity_name' => ['sometimes', 'nullable', 'string', 'min:2', 'max:15'],
'filter.circle' => ['sometimes', 'nullable', 'array', 'min:3', 'max:3'],
'filter.circle.latitude' => ['required_with:filter.circle', 'regex:/^[-]?(([0-8]?[0-9])\.(\d+))|(90(\.0+)?)$/'],
'filter.circle.longitude' => ['required_with:filter.circle', 'regex:/^[-]?((((1[0-7][0-9])|([0-9]?[0-9]))\.(\d+))|180(\.0+)?)$/'],
'filter.circle.radius' => ['required_with:filter.circle', 'numeric', 'min:0.1', 'max:250'],
'filter.square' => ['sometimes', 'nullable', 'array', 'min:4', 'max:4'],
'filter.square.latitude' => ['required_with:filter.square', 'regex:/^[-]?(([0-8]?[0-9])\.(\d+))|(90(\.0+)?)$/'],
'filter.square.longitude' => ['required_with:filter.square', 'regex:/^[-]?((((1[0-7][0-9])|([0-9]?[0-9]))\.(\d+))|180(\.0+)?)$/'],
'filter.square.width' => ['required_with:filter.square', 'numeric', 'min:0.1', 'max:250'],
'filter.square.height' => ['required_with:filter.square', 'numeric', 'min:0.1', 'max:250'],
];
}

public function messages()
{
return [

];
}
}
12 changes: 12 additions & 0 deletions app/Http/Resources/OrganizationResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;
class OrganizationResource extends JsonResource
{
public function toArray($request)
{
return parent::toArray($request);
}
}
2 changes: 1 addition & 1 deletion app/Models/Activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function children(): HasMany

public function organizations(): BelongsToMany
{
return $this->belongsToMany(Organization::class)->withTimestamps();
return $this->belongsToMany(Organization::class, 'organization_activity')->withTimestamps();
}

public static function getAvailableStatuses()
Expand Down
82 changes: 80 additions & 2 deletions app/Models/Organization.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Builder;

class Organization extends Model
{
Expand All @@ -24,12 +25,89 @@ class Organization extends Model

public function building(): BelongsTo
{
return $this->belongsTo(self::class, 'building_id', 'id');
return $this->belongsTo(Building::class, 'building_id', 'id');
}

public function activities(): BelongsToMany
{
return $this->belongsToMany(Activity::class)->withTimestamps();
return $this->belongsToMany(Activity::class, 'organization_activity')->withTimestamps();
}

public function scopeFilter(Builder $q, ?array $data = []): Builder
{
if (isset($data['name'])) {
$q->where('name', 'like', '%' . $data['name'] . '%')->get();
}
if (isset($data['building_id'])) {
$q->where('organizations.building_id', $data['building_id']);
}
if (isset($data['activity_id'])) {
$q->whereHas('activities', function ($q) use ($data) {
$q->where('id', $data['activity_id']);
});
}
if (isset($data['activity_name'])) {
$activities = Activity::with([
'children' => function ($q) {
$q->select('id', 'parent_id');
},
'children.children' => function ($q) {
$q->select('id', 'parent_id');
},
])
->where('name', 'like', '%' . $data['activity_name'] . '%')
->select('id')
->get()
->toArray();
$activityIds = [];
foreach ($activities as $activity) {
if (!in_array($activity['id'], $activityIds)) {
$activityIds[] = $activity['id'];
}
foreach ($activity['children'] as $childActivity) {
if (!in_array($childActivity['id'], $activityIds)) {
$activityIds[] = $childActivity['id'];
}
foreach ($childActivity['children'] as $subChildActivity) {
if (!in_array($subChildActivity['id'], $activityIds)) {
$activityIds[] = $subChildActivity['id'];
}
}
}
}

$q->whereHas('activities', function ($q) use ($activityIds) {
$q->whereIn('id', $activityIds);
});
}
if (isset($data['circle'])) {
$q->whereHas('building', function ($q) use ($data) {
$q->select('*', \DB::raw('(6371 * acos(
cos(radians('. $data['circle']['latitude'] . ')) *
cos(radians(latitude)) *
cos(radians(longitude) - radians('. $data['circle']['longitude'] . ')) +
sin(radians('. $data['circle']['latitude'] . ')) *
sin(radians(latitude))
)) as distance'))
->having('distance', '<=', $data['circle']['radius']);
});
}
if (isset($data['square'])) {
$latitude = $data['square']['latitude'];
$longitude = $data['square']['longitude'];
$halfWidth = $data['square']['width'] / 2;
$halfHeight = $data['square']['height'] / 2;

$latitudeOffset = $halfHeight / 111;
$longitudeOffset = $halfWidth / (111 * cos(deg2rad($latitude)));

$q->whereHas('building', function ($q) use ($latitude, $latitudeOffset, $longitude, $longitudeOffset) {
$q->whereBetween('latitude', [$latitude - $latitudeOffset, $latitude + $latitudeOffset])
->whereBetween('longitude', [$longitude - $longitudeOffset, $longitude + $longitudeOffset]);
});
}

return $q;
}

public static function getAvailableStatuses()
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"php": "^8.2",
"laravel/framework": "^11.31",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.9"
"laravel/tinker": "^2.9",
"spatie/laravel-json-api-paginate": "^1.16"
},
"require-dev": {
"fakerphp/faker": "^1.23",
Expand Down
67 changes: 66 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions config/json-api-paginate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

return [

/*
* The maximum number of results that will be returned
* when using the JSON API paginator.
*/
'max_results' => 30,

/*
* The default number of results that will be returned
* when using the JSON API paginator.
*/
'default_size' => 10,

/*
* The key of the page[x] query string parameter for page number.
*/
'number_parameter' => 'number',

/*
* The key of the page[x] query string parameter for page size.
*/
'size_parameter' => 'size',

/*
* The key of the page[x] query string parameter for cursor.
*/
'cursor_parameter' => 'cursor',

/*
* The name of the macro that is added to the Eloquent query builder.
*/
'method_name' => 'jsonPaginate',

/*
* If you only need to display Next and Previous links, you may use
* simple pagination to perform a more efficient query.
*/
'use_simple_pagination' => false,

/*
* If you want to use cursor pagination, set this to true.
* This would override use_simple_pagination.
*/
'use_cursor_pagination' => false,

/*
* use simpleFastPaginate() or fastPaginate from https://github.com/hammerstonedev/fast-paginate
* use may installed it via `composer require hammerstone/fast-paginate`
*/
'use_fast_pagination' => false,

/*
* Here you can override the base url to be used in the link items.
*/
'base_url' => null,

/*
* The name of the query parameter used for pagination
*/
'pagination_parameter' => 'page',
];
2 changes: 1 addition & 1 deletion database/factories/ActivityFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ActivityFactory extends Factory
public function definition(): array
{
return [
'name' => ucfirst(fake()->word()),
'name' => ucfirst(fake()->unique()->word()),
'parent_id' => null,
'status' => fake()->boolean(90) ? Activity::STATUS_ACTIVE : Activity::STATUS_INACTIVE,
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ public function up(): void
$table->string('city')->index();
$table->string('address_1');
$table->string('address_2')->nullable();
$table->string('latitude')->index();
$table->string('longitude')->index();
$table->decimal('latitude', 10, 8);
$table->decimal('longitude', 11, 8);
$table->index(['latitude', 'longitude']);
$table->timestamps();
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class ApiStaticKeysSeeder extends Seeder
class ApiStaticKeySeeder extends Seeder
{
/**
* Run the database seeds.
Expand Down
2 changes: 1 addition & 1 deletion database/seeders/DatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function run(): void
$this->run(BuildingSeeder::class);
$this->run(OrganizationSeeder::class);
$this->run(OrganizationActivitySeeder::class);
$this->run(ApiStaticKeysSeeder::class);
$this->run(ApiStaticKeySeeder::class);
}
}
}
Loading

0 comments on commit b9593b8

Please sign in to comment.