# Repository Pattern Documentation

This project uses the Repository Pattern to centralize data access logic and avoid code duplication between API endpoints and Blade views.

## Structure

```
app/
├── Repositories/
│   ├── Contracts/              # Repository Interfaces
│   │   ├── RepositoryInterface.php
│   │   ├── ListingRepositoryInterface.php
│   │   ├── ConditionRepositoryInterface.php
│   │   └── DealerRepositoryInterface.php
│   └── Eloquent/               # Repository Implementations
│       ├── BaseRepository.php
│       ├── ListingRepository.php
│       ├── ConditionRepository.php
│       └── DealerRepository.php
└── Providers/
    └── RepositoryServiceProvider.php
```

## Usage

### In Controllers (API or Blade)

Both API and Blade controllers can use the same repository methods:

```php
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Repositories\Contracts\ListingRepositoryInterface;

class ListingController extends Controller
{
    public function __construct(
        protected ListingRepositoryInterface $listingRepository
    ) {}

    public function index()
    {
        // Same method works for both API and Blade
        $listings = $this->listingRepository->getFeatured(12);
        
        // Return JSON for API
        return response()->json(['data' => $listings]);
    }
}
```

```php
<?php

namespace App\Http\Controllers\Buyer;

use App\Http\Controllers\Controller;
use App\Repositories\Contracts\ListingRepositoryInterface;
use Illuminate\View\View;

class FrontendController extends Controller
{
    public function __construct(
        protected ListingRepositoryInterface $listingRepository
    ) {}

    public function index(): View
    {
        // Same method works for both API and Blade
        $listings = $this->listingRepository->getFeatured(12);
        
        // Return Blade view
        return view('buyer.home', ['listings' => $listings]);
    }
}
```

## Available Repository Methods

### ListingRepository

- `getFeatured(int $limit, array $with)` - Get featured listings
- `getApprovedPaginated(int $perPage, array $with, array $filters)` - Get paginated approved listings with filters
- `getByOwner(int $ownerId, array $with, array $filters)` - Get listings by dealer/owner
- `getRelated(string $listingId, int $limit, array $with)` - Get related listings
- `findByUuidWith(string $uuid, array $with)` - Find listing by UUID with relations
- `getByCondition(int $conditionId, int $perPage, array $with)` - Get listings by condition
- `getStatistics(?int $ownerId)` - Get listing statistics

### ConditionRepository

- `getActive()` - Get all active conditions
- `getWithCounts()` - Get conditions with listing counts

### DealerRepository

- `findByUserId(int $userId, array $with)` - Find dealer by user ID
- `getVerified(array $with)` - Get verified dealers
- `findByUuidWith(string $uuid, array $with)` - Get dealer with full details

### UserRepository

- `createBuyer(array $userData, array $settings)` - Create a user with buyer role
- `findByEmail(string $email)` - Find user by email
- `authenticate(array $credentials, bool $remember)` - Authenticate user (login)
- `getAuthenticatedUser()` - Get currently authenticated user
- `logout()` - Logout authenticated user

### BuyerRepository

- `findByUserId(int $userId, array $with)` - Find buyer by user ID
- `findByUserEmail(string $email, array $with)` - Find buyer by user email

## Base Repository Methods

All repositories inherit these methods from `BaseRepository`:

- `all(array $columns)` - Get all records
- `paginate(int $perPage, array $columns)` - Get paginated records
- `find(string|int $id, array $columns)` - Find by ID
- `findByUuid(string $uuid, array $columns)` - Find by UUID
- `findOrFail(string|int $id, array $columns)` - Find or throw exception
- `create(array $data)` - Create new record
- `update(string|int $id, array $data)` - Update record
- `delete(string|int $id)` - Delete record
- `findBy(array $criteria, array $columns)` - Find by criteria
- `findOneBy(array $criteria, array $columns)` - Find one by criteria

## Creating a New Repository

1. Create the interface in `app/Repositories/Contracts/`:

```php
<?php

namespace App\Repositories\Contracts;

interface ProductRepositoryInterface extends RepositoryInterface
{
    public function getRelatedProducts(string $productId, int $limit = 4): Collection;
}
```

2. Create the implementation in `app/Repositories/Eloquent/`:

```php
<?php

namespace App\Repositories\Eloquent;

use App\Models\Product;
use App\Repositories\Contracts\ProductRepositoryInterface;

class ProductRepository extends BaseRepository implements ProductRepositoryInterface
{
    public function getRelatedProducts(string $productId, int $limit = 4): Collection
    {
        // Your implementation
    }
}
```

3. Register in `RepositoryServiceProvider`:

```php
$this->app->bind(
    ProductRepositoryInterface::class,
    function ($app) {
        return new ProductRepository(new Product());
    }
);
```

## API Authentication

The project uses API routes for authentication to avoid CSRF issues. The same repository methods work for both API and Blade:

**API Routes** (`routes/api.php`):
- `POST /api/auth/register` - Register new buyer
- `POST /api/auth/login` - Login user
- `POST /api/auth/logout` - Logout user (requires auth)
- `GET /api/auth/me` - Get authenticated user (requires auth)

**Blade Routes** (`routes/auth.php`):
- `GET /buyers-register` - Show registration form
- `POST /buyers-register` - Register new buyer (uses same repository)

Both use the same `UserRepository` methods, ensuring consistency.

## Benefits

1. **Code Reusability**: Same methods work for both API and Blade views
2. **Maintainability**: Data access logic in one place
3. **Testability**: Easy to mock repositories for testing
4. **Flexibility**: Easy to swap implementations if needed
5. **Consistency**: Ensures data is fetched the same way everywhere
6. **CSRF-Free API**: API routes don't require CSRF tokens, perfect for mobile apps

