Skip to content

Commit

Permalink
#24 - news pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysztofrewak committed Aug 12, 2024
1 parent e7f1c62 commit 4e2de86
Show file tree
Hide file tree
Showing 14 changed files with 185 additions and 52 deletions.
2 changes: 1 addition & 1 deletion app/Http/Controllers/Public/NewsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function index(): Response
{
$news = News::query()
->orderBy("published_at", "desc")
->paginate(10);
->paginate(9);

return inertia("Public/News/Index", [
"paginator" => $news,
Expand Down
7 changes: 2 additions & 5 deletions app/Models/GradeColumn.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use App\Observers\GradeColumnObserver;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
Expand All @@ -23,6 +24,7 @@
* @property-read Group $group
* @property-read Collection<Grade> $grades
*/
#[ObservedBy(GradeColumnObserver::class)]
class GradeColumn extends Model
{
use HasFactory;
Expand All @@ -46,9 +48,4 @@ public function grades(): HasMany
{
return $this->hasMany(Grade::class);
}

protected static function booted(): void
{
self::observe(GradeColumnObserver::class);
}
}
3 changes: 3 additions & 0 deletions app/Models/News.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace App\Models;

use App\Observers\NewsObserver;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
Expand All @@ -16,6 +18,7 @@
* @property string $content
* @property Carbon $published_at
*/
#[ObservedBy(NewsObserver::class)]
class News extends Model
{
use HasFactory;
Expand Down
45 changes: 45 additions & 0 deletions app/Observers/NewsObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace App\Observers;

use App\Models\News;
use Illuminate\Support\Str;

class NewsObserver
{
public function creating(News $news): void
{
if ($news->slug) {
return;
}

$slug = Str::slug($news->published_at->format("Y-m-d") . " " . $news->title);

if (!$this->checkIfSlugExists($slug)) {
$news->slug = $slug;

return;
}

$i = 2;

while (true) {
$newSlug = Str::slug($slug . " " . $i);

if (!$this->checkIfSlugExists($newSlug)) {
$news->slug = $newSlug;

return;
}

$i++;
}
}

protected function checkIfSlugExists(string $slug): bool
{
return News::query()->where("slug", $slug)->count() > 0;
}
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"keywords": ["framework", "laravel"],
"license": "MIT",
"require": {
"php": "^8.2",
"php": "^8.3",
"ext-pdo": "*",
"fakerphp/faker": "^1.23",
"guzzlehttp/guzzle": "^7.8",
Expand Down
16 changes: 11 additions & 5 deletions database/factories/NewsFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@

namespace Database\Factories;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class NewsFactory extends Factory
{
protected const array NEWS_TITLES = [
"Odwołane zajęcia",
"Przeniesione zajęcia",
"Nieobecność",
"Początek roku akademickiego",
"Koniec roku akademickiego",
"Terminy egzaminów",
];

public function definition(): array
{
$title = fake()->unique()->name();
$title = fake()->randomElement(static::NEWS_TITLES);

return [
"title" => $title,
"slug" => Str::slug($title),
"content" => fake()->realText(),
"published_at" => Carbon::now(),
"published_at" => fake()->dateTimeThisYear(),
];
}
}
26 changes: 0 additions & 26 deletions database/migrations/2023_10_01_181311_create_news_table.php

This file was deleted.

16 changes: 16 additions & 0 deletions database/seeders/DemoSeeder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Database\Seeders;

use App\Models\News;
use Illuminate\Database\Seeder;

class DemoSeeder extends Seeder
{
public function run(): void
{
News::factory(20)->create();
}
}
13 changes: 3 additions & 10 deletions resources/js/Components/BackgroundGrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,14 @@ defineProps({
</script>

<template>
<svg class="absolute inset-0 -z-10 size-full stroke-gray-200"
:class="'[mask-image:radial-gradient(100%_100%_at_top_' + maskDirection + ',white,transparent)]'"
aria-hidden="true"
>
<svg class="absolute inset-0 -z-10 size-full stroke-gray-200" :class="'[mask-image:radial-gradient(100%_100%_at_top_' + maskDirection + ',white,transparent)]'" aria-hidden="true">
<defs>
<pattern id="83fd4e5a-9d52-42fc-97b6-718e5d7ee527" width="200" height="200" x="50%" y="-1"
patternUnits="userSpaceOnUse"
>
<pattern id="83fd4e5a-9d52-42fc-97b6-718e5d7ee527" width="200" height="200" x="50%" y="-1" patternUnits="userSpaceOnUse">
<path d="M100 200V.5M.5 .5H200" fill="none" />
</pattern>
</defs>
<svg x="50%" y="-1" class="overflow-visible fill-gray-50">
<path d="M-100.5 0h201v201h-201Z M699.5 0h201v201h-201Z M499.5 400h201v201h-201Z M-300.5 600h201v201h-201Z"
stroke-width="0"
/>
<path d="M-100.5 0h201v201h-201Z M699.5 0h201v201h-201Z M499.5 400h201v201h-201Z M-300.5 600h201v201h-201Z" stroke-width="0" />
</svg>
<rect width="100%" height="100%" stroke-width="0" fill="url(#83fd4e5a-9d52-42fc-97b6-718e5d7ee527)" />
</svg>
Expand Down
21 changes: 21 additions & 0 deletions resources/js/Components/Pagination.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup>
defineProps({
pagination: Object,
})
</script>

<template>
<nav class="relative flex justify-center">
<template v-for="link in pagination.links" :key="link.label">
<InertiaLink
preserve-scroll
:href="link.url ?? ''"
class="flex items-center justify-center rounded-lg px-3 py-2 text-sm text-gray-600"
:class="{ 'bg-gray-200': link.active, '!text-gray-300': !link.url }"
>
{{ link.label }}
</InertiaLink>
</template>
</nav>
</template>
5 changes: 2 additions & 3 deletions resources/js/Layouts/PublicLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const mobileMenuOpen = ref(false)
</Dialog>
</header>

<div class="flex-1">
<div class="flex-1 bg-white">
<slot />
</div>

Expand All @@ -92,8 +92,7 @@ const mobileMenuOpen = ref(false)
<p class="text-center text-xs leading-5 text-gray-500">
2023
<EllipsisHorizontalIcon class="mx-2 inline-block w-6" />
<a class="font-semibold" href="https://github.com/blumilksoftware/keating" target="_blank">keating
management system</a>
<a class="font-semibold" href="https://github.com/blumilksoftware/keating" target="_blank">keating management system</a>
developed at
<a class="font-semibold" href="https://blumilk.pl/" target="_blank">Blumilk</a>
</p>
Expand Down
6 changes: 6 additions & 0 deletions resources/js/Pages/Public/News/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
import PublicLayout from '@/Layouts/PublicLayout.vue'
import BackgroundGrid from '../../../Components/BackgroundGrid.vue'
import SectionHeader from '../../../Components/SectionHeader.vue'
import Pagination from '../../../Components/Pagination.vue'
defineProps({
paginator: Object,
})
</script>

<template>
Expand Down Expand Up @@ -41,6 +43,10 @@ defineProps({
</div>
</article>
</div>

<div class="mt-24 flex justify-center">
<Pagination :pagination="paginator" />
</div>
</div>
</div>
</div>
Expand Down
3 changes: 2 additions & 1 deletion routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
use Illuminate\Support\Facades\Route;

Route::get("/", HomeController::class)->name("main");
Route::get("/aktualnosci", NewsController::class);
Route::get("/aktualnosci", [NewsController::class, "index"]);
Route::get("/aktualnosci/{slug}", [NewsController::class, "get"]);

Route::middleware("guest")->group(function (): void {
Route::get("/login", [LoginController::class, "create"])->name("login");
Expand Down
72 changes: 72 additions & 0 deletions tests/Feature/NewsSlugTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Models\News;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class NewsSlugTest extends TestCase
{
use RefreshDatabase;

public function testNewsSlugging(): void
{
News::factory()->create([
"title" => "Test",
"published_at" => "2024-06-01 15:00:00",
]);

$this->assertEquals("2024-06-01-test", News::query()->first()->slug);
}

public function testMultipleNewsSlugging(): void
{
News::factory()->create([
"title" => "Test",
"published_at" => "2024-06-01 15:00:00",
]);

News::factory()->create([
"title" => "Test",
"published_at" => "2024-06-15 15:00:00",
]);

$news = News::query()->get();

$this->assertEquals("2024-06-01-test", $news[0]->slug);
$this->assertEquals("2024-06-15-test", $news[1]->slug);
}

public function testMultipleNewsWithRepeatedTitleSlugging(): void
{
News::factory()->create([
"title" => "Test",
"published_at" => "2024-06-01 15:00:00",
]);

News::factory()->create([
"title" => "Test",
"published_at" => "2024-06-01 15:00:00",
]);

News::factory()->create([
"title" => "Test",
"published_at" => "2024-06-15 15:00:00",
]);

News::factory()->create([
"title" => "Test",
"published_at" => "2024-06-01 15:00:00",
]);

$news = News::query()->get();

$this->assertEquals("2024-06-01-test", $news[0]->slug);
$this->assertEquals("2024-06-01-test-2", $news[1]->slug);
$this->assertEquals("2024-06-15-test", $news[2]->slug);
$this->assertEquals("2024-06-01-test-3", $news[3]->slug);
}
}

0 comments on commit 4e2de86

Please sign in to comment.