Installation:
composer require antwebes/photo-rest-bundle
Add the bundle to AppKernel.php (Symfony 2.x):
new Antwebes\PhotoRestBundle\AntwebesPhotoRestBundle(),
Configuration:
Enable the bundle in config.yml:
antwebes_photo_rest:
# Optional: Customize upload directory (default: %kernel.root_dir%/../web/uploads/photos)
upload_dir: "%kernel.root_dir%/../web/uploads/custom_photos"
First Use Case:
Upload a Photo:
Use the PhotoController (auto-generated by the bundle) to handle uploads via a form with enctype="multipart/form-data".
Example route (check routing.yml for defaults):
photo_upload:
path: /api/photos/upload
defaults: { _controller: AntwebesPhotoRestBundle:Photo:upload }
Fetch Photos:
Access photos via REST endpoints (e.g., /api/photos). The bundle provides basic CRUD operations out-of-the-box.
Photo Management:
/api/photos/upload. The bundle handles storage in the configured upload_dir and associates metadata (e.g., user_id, created_at)./api/photos (supports pagination, filtering by user_id, or date ranges).
Example API call:
curl -X GET "/api/photos?user_id=1&start_date=2015-01-01"
/api/photos/{id}/vote to increment a photo’s vote count (restricted to one vote per user per photo).
Example:
curl -X POST "/api/photos/123/vote"
Entity Integration:
Photo entity (Antwebes\PhotoRestBundle\Entity\Photo) to add custom fields:
// src/Acme/YourBundle/Entity/CustomPhoto.php
use Antwebes\PhotoRestBundle\Entity\Photo as BasePhoto;
class CustomPhoto extends BasePhoto {
/**
* @ORM\Column(type="string", length=255)
*/
private $customField;
}
PhotoRepository to add custom queries (e.g., for date-range votes):
public function getVotesByDateRange(\DateTime $start, \DateTime $end) {
return $this->createQueryBuilder('p')
->where('p.createdAt BETWEEN :start AND :end')
->setParameter('start', $start)
->setParameter('end', $end)
->getQuery()
->getResult();
}
Transformer Patterns:
IdToPhotoTransformer (hotfix in v0.1.2) to convert IDs to Photo objects in controllers:
$transformer = $this->get('antwebes_photo_rest.id_to_photo_transformer');
$photo = $transformer->transform(123); // Returns Photo entity for ID 123
Security:
voteAction in a custom controller or use Symfony’s security voters:
# security.yml
access_control:
- { path: ^/api/photos/\d+/vote, roles: ROLE_USER }
Doctrine ORM Version:
>=2.2.3,<2.5-dev. Conflicts may arise with newer Symfony/Laravel (4.x+) or Doctrine 2.6+. Workaround:
composer.json or use a wrapper library to abstract the ORM.spatie/laravel-medialibrary.File Uploads:
upload_dir is writable by the web server (e.g., chmod -R 775 uploads).public function uploadAction(Request $request) {
$file = $request->files->get('photo');
if (!$file->isValid()) {
throw new \RuntimeException('Invalid file upload.');
}
if ($file->getClientOriginalExtension() !== 'jpg') {
throw new \RuntimeException('Only JPG files allowed.');
}
// Proceed with bundle logic...
}
Vote Logic:
vote method to log issues:
public function vote(Photo $photo, User $user) {
if ($this->hasVoted($photo, $user)) {
throw new \RuntimeException("User {$user->getId()} already voted.");
}
// ... rest of logic
}
Deprecation Risks:
Custom Endpoints:
# services.yml
acme.photo_custom_controller:
class: Acme\YourBundle\Controller\CustomPhotoController
arguments: ["@antwebes_photo_rest.photo_repository"]
tags: ["controller.service_arguments"]
// src/Acme/YourBundle/Controller/CustomPhotoController.php
class CustomPhotoController extends Controller {
public function getPhotosByTagAction($tag) {
$photos = $this->get('antwebes_photo_rest.photo_repository')->findBy(['tag' => $tag]);
return $this->json($photos);
}
}
Testing:
PhotoRepository in unit tests to avoid file system dependencies:
$repository = $this->createMock(PhotoRepository::class);
$repository->method('findBy')->willReturn([$mockPhoto]);
$this->container->set('antwebes_photo_rest.photo_repository', $repository);
Performance:
user_id and created_at in the photo table:
// src/Acme/YourBundle/Resources/doc/doctrine/Photo.orm.yml
Antwebes\PhotoRestBundle\Entity\Photo:
indexes:
user_idx: { columns: [user_id] }
date_idx: { columns: [created_at] }
Laravel Adaptation:
Photo entity and repository logic, but replace Symfony-specific components (e.g., controllers, routing) with Laravel’s equivalents. Use Laravel’s Storage facade for file handling.
How can I help you explore Laravel packages today?