Installation
composer require c33s/attachment-bundle
Add to config/bundles.php:
return [
// ...
C33s\AttachmentBundle\C33sAttachmentBundle::class => ['all' => true],
];
Configure Database Run migrations (Propel-specific):
php app/console propel:model:build
php app/console propel:migrate
Verify attachment and attachment_object tables exist.
First Use Case
Attach a file to a model (e.g., Product):
use C33s\AttachmentBundle\Model\Attachment;
$product = ProductQuery::create()->findOne(1);
$attachment = new Attachment();
$attachment->setFile('path/to/file.pdf');
$attachment->setObject($product);
$attachment->save();
Attachments to Models
Use Attachment model to link files to any Propel object:
// Attach multiple files
$attachments = [];
foreach ($request->files as $file) {
$attachment = new Attachment();
$attachment->setFile($file->getPathname());
$attachment->setObject($model);
$attachment->save();
$attachments[] = $attachment;
}
Retrieving Attachments Fetch attachments for a model:
$attachments = AttachmentQuery::create()
->filterByObject($model)
->find();
File Management
File component to process uploads before saving:
$file = $request->files->get('file');
$attachment->setFile($file->getRealPath());
Validation Validate file types/sizes via Propel behavior or custom logic:
if ($file->getClientOriginalExtension() !== 'pdf') {
throw new \RuntimeException('Only PDF allowed.');
}
Integration with Forms
Use Symfony’s FileType field in forms:
$builder->add('attachments', CollectionType::class, [
'entry_type' => new AttachmentType(),
'allow_add' => true,
'allow_delete' => true,
]);
Propel Dependency
Attachment and AttachmentObject tables are manually created.File Storage Quirks
Attachment::getFilePath() (e.g., uploads/attachments/). Override in config:
# config.yml
c33s_attachment:
storage_path: '%kernel.project_dir%/public/uploads/custom_path'
storage_path is writable by the web server user.Memory Limits
Large files may hit PHP’s upload_max_filesize or memory_limit. Adjust in php.ini or use chunked uploads.
Deletion Handling
// src/EventListener/AttachmentListener.php
public function postRemove(Attachment $attachment)
{
if (file_exists($attachment->getFilePath())) {
unlink($attachment->getFilePath());
}
}
services.yml:
services:
app.attachment_listener:
class: App\EventListener\AttachmentListener
tags:
- { name: kernel.event_listener, event: attachment.post_remove, method: postRemove }
Symfony 4+ Compatibility
app/console commands with bin/console.Check Database
Verify attachment_object table links are correct:
SELECT * FROM attachment_object WHERE object_id = [MODEL_ID];
File Paths Log paths to confirm files are saved:
\Log::debug('Attachment path:', [$attachment->getFilePath()]);
Event Dispatching
Override events for custom logic (e.g., attachment.pre_save):
$dispatcher->addListener('attachment.pre_save', function (AttachmentEvent $event) {
$event->getAttachment()->setCustomField('processed', true);
});
Custom Storage
Extend C33s\AttachmentBundle\Model\Attachment to support S3:
use Aws\S3\S3Client;
class CustomAttachment extends Attachment
{
public function getFilePath()
{
$s3 = new S3Client([...]);
return $s3->getObjectUri('bucket', $this->getFileName());
}
}
Validation Rules Add Propel behaviors for file validation:
# schema.xml
<behavior name="attachment_validation">
<parameter name="allowed_extensions" value="pdf,jpg,png"/>
<parameter name="max_size" value="10M"/>
</behavior>
API Endpoints Create a controller to serve attachments:
public function serveAttachment(Attachment $attachment, Request $request)
{
return new BinaryFileResponse($attachment->getFilePath());
}
Route:
# routing.yml
attachment_download:
path: /attachment/{id}
defaults: { _controller: App\Controller\AttachmentController::serveAttachment }
How can I help you explore Laravel packages today?