tiloweb/uploaded-file-type-bundle 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

tiloweb/uploaded-file-type-bundle

Composer 安装命令:

composer require tiloweb/uploaded-file-type-bundle

包简介

A Symfony bundle that handles file uploads via forms and stores the URL automatically using Flysystem

README 文档

README

CI Latest Stable Version Total Downloads License PHP Version

A Symfony bundle that handles file uploads via forms and automatically stores the resulting URL in your entity. No more manual file handling in controllers!

✨ Features

  • 🚀 Zero-configuration file uploads - Just add an option to your form field
  • 📦 Flysystem integration - Works with any storage backend (local, S3, GCS, SFTP, etc.)
  • 🔄 Automatic URL storage - The file URL is stored directly in your entity
  • 🎯 Custom naming strategies - Full control over uploaded file names
  • 🗑️ Auto-cleanup - Optionally delete previous files when uploading new ones
  • 🎨 Twig integration - Preview uploaded images in your forms

📋 Requirements

Version PHP Symfony
2.x ≥ 8.1 6.4, 7.x, 8.x
1.x ≥ 8.1 6.x, 7.x

📥 Installation

composer require tiloweb/uploaded-file-type-bundle

If you're not using Symfony Flex, add the bundle manually:

// config/bundles.php
return [
    // ...
    Tiloweb\UploadedFileTypeBundle\UploadedFileTypeBundle::class => ['all' => true],
];

⚙️ Configuration

Step 1: Configure Flysystem

First, configure your filesystem adapter using the OneupFlysystemBundle:

# config/packages/oneup_flysystem.yaml
oneup_flysystem:
    adapters:
        default_adapter:
            local:
                location: '%kernel.project_dir%/public/uploads'

    filesystems:
        default_filesystem:
            adapter: default_adapter
            alias: League\Flysystem\Filesystem

Step 2: Configure Upload Destinations

# config/packages/uploaded_file_type.yaml
uploaded_file_type:
    configurations:
        # Default configuration for general uploads
        default:
            filesystem: 'oneup_flysystem.default_filesystem'
            base_uri: 'https://example.com/uploads'
            path: '/files'

        # Separate configuration for user avatars
        avatars:
            filesystem: 'oneup_flysystem.default_filesystem'
            base_uri: 'https://example.com/uploads'
            path: '/avatars'

        # S3 configuration for large files
        documents:
            filesystem: 'oneup_flysystem.s3_filesystem'
            base_uri: 'https://cdn.example.com'
            path: '/documents'

Configuration Options

Option Type Required Description
filesystem string The Flysystem filesystem service ID
base_uri string The base URL for accessing uploaded files
path string The subdirectory path within the filesystem

🚀 Usage

Basic Usage

Simply add the upload option to any FileType field:

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;

class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name')
            ->add('image', FileType::class, [
                'upload' => 'default',  // Use the 'default' configuration
                'required' => false,
            ])
        ;
    }
}

That's it! When the form is submitted:

  1. The file is uploaded to your configured filesystem
  2. The URL is automatically stored in the $image property
  3. No additional controller code needed!

Custom Filename Strategy

Control how files are named when uploaded:

$builder->add('avatar', FileType::class, [
    'upload' => 'avatars',
    'filename' => function (UploadedFile $file, User $user): string {
        return sprintf(
            'user_%d_%s.%s',
            $user->getId(),
            bin2hex(random_bytes(8)),
            $file->guessClientExtension() ?? 'bin'
        );
    },
]);

Disable Auto-Cleanup

By default, the previous file is deleted when uploading a new one. Disable this behavior:

$builder->add('document', FileType::class, [
    'upload' => 'documents',
    'delete_previous' => false,  // Keep old files
]);

Available Form Options

Option Type Default Description
upload string - The configuration name to use
filename callable auto Custom filename generator
delete_previous bool true Delete previous file on update

📖 Complete Example

Entity

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Product
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    private string $name = '';

    #[ORM\Column(length: 500, nullable: true)]
    private ?string $image = null;

    // Getters and setters...
    
    public function getImage(): ?string
    {
        return $this->image;
    }

    public function setImage(?string $image): static
    {
        $this->image = $image;
        return $this;
    }
}

Form

namespace App\Form;

use App\Entity\Product;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Image;

class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('name', TextType::class, [
                'label' => 'Product Name',
            ])
            ->add('image', FileType::class, [
                'upload' => 'default',
                'required' => false,
                'label' => 'Product Image',
                'constraints' => [
                    new Image([
                        'maxSize' => '5M',
                        'mimeTypes' => ['image/jpeg', 'image/png', 'image/webp'],
                    ]),
                ],
            ])
        ;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => Product::class,
        ]);
    }
}

Controller

namespace App\Controller;

use App\Entity\Product;
use App\Form\ProductType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class ProductController extends AbstractController
{
    #[Route('/product/new', name: 'product_new')]
    public function new(Request $request, EntityManagerInterface $em): Response
    {
        $product = new Product();
        $form = $this->createForm(ProductType::class, $product);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em->persist($product);
            $em->flush();

            // $product->getImage() now contains the URL!
            // e.g., "https://example.com/uploads/files/product_a1b2c3d4.jpg"

            return $this->redirectToRoute('product_show', ['id' => $product->getId()]);
        }

        return $this->render('product/new.html.twig', [
            'form' => $form,
        ]);
    }
}

Twig Template

The bundle provides a form theme that displays the current image:

{# templates/product/new.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h1>New Product</h1>

    {{ form_start(form) }}
        {{ form_row(form.name) }}
        {{ form_row(form.image) }}  {# Shows current image if exists #}
        <button type="submit">Save</button>
    {{ form_end(form) }}
{% endblock %}

🎨 Customizing the Form Theme

Override the default template to customize how uploaded files are displayed:

{# templates/form/uploaded_file.html.twig #}
{% extends '@UploadedFileType/form.html.twig' %}

{% block file_widget %}
    {{ parent() }}
    
    {% if url is defined and url is not null %}
        <div class="uploaded-file-preview">
            {% if url matches '/\\.(jpg|jpeg|png|gif|webp)$/i' %}
                <img src="{{ url }}" alt="Preview" class="preview-image">
            {% else %}
                <a href="{{ url }}" target="_blank">View current file</a>
            {% endif %}
        </div>
    {% endif %}
{% endblock %}

Register your custom theme:

# config/packages/twig.yaml
twig:
    form_themes:
        - 'form/uploaded_file.html.twig'

🔧 Advanced Usage

Using the Service Directly

use Tiloweb\UploadedFileTypeBundle\UploadedFileTypeService;

class MyService
{
    public function __construct(
        private UploadedFileTypeService $uploadService,
    ) {}

    public function uploadFile(UploadedFile $file): string
    {
        return $this->uploadService->upload(
            filename: 'custom-name.pdf',
            uploadedFile: $file,
            configuration: 'documents'
        );
    }

    public function deleteFile(string $url): bool
    {
        return $this->uploadService->delete($url, 'documents');
    }

    public function fileExists(string $url): bool
    {
        return $this->uploadService->exists($url, 'documents');
    }
}

Cloud Storage Examples

Amazon S3

# config/packages/oneup_flysystem.yaml
oneup_flysystem:
    adapters:
        s3_adapter:
            awss3v3:
                client: Aws\S3\S3Client
                bucket: '%env(AWS_S3_BUCKET)%'
                prefix: uploads

    filesystems:
        s3_filesystem:
            adapter: s3_adapter

# config/packages/uploaded_file_type.yaml
uploaded_file_type:
    configurations:
        s3:
            filesystem: 'oneup_flysystem.s3_filesystem'
            base_uri: 'https://%env(AWS_S3_BUCKET)%.s3.%env(AWS_REGION)%.amazonaws.com'
            path: '/uploads'

Google Cloud Storage

oneup_flysystem:
    adapters:
        gcs_adapter:
            googlecloudstorage:
                client: Google\Cloud\Storage\StorageClient
                bucket: '%env(GCS_BUCKET)%'

    filesystems:
        gcs_filesystem:
            adapter: gcs_adapter

uploaded_file_type:
    configurations:
        gcs:
            filesystem: 'oneup_flysystem.gcs_filesystem'
            base_uri: 'https://storage.googleapis.com/%env(GCS_BUCKET)%'
            path: '/uploads'

🧪 Testing

# Run tests
composer test

# Run static analysis
composer phpstan

# Fix coding standards
composer cs-fix

🤝 Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This bundle is released under the MIT License.

🙏 Credits

🔗 Links

tiloweb/uploaded-file-type-bundle 适用场景与选型建议

tiloweb/uploaded-file-type-bundle 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 9.55k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2021 年 04 月 28 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「symfony」 「file」 「storage」 「s3」 「form」 「bundle」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 tiloweb/uploaded-file-type-bundle 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 tiloweb/uploaded-file-type-bundle 我们能提供哪些服务?
定制开发 / 二次开发

基于 tiloweb/uploaded-file-type-bundle 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 9.55k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 16
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 2
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2021-04-28