TR
Başlangıç
60 · Formlar

Dosya yükleme

Tek ve çoklu dosya yükleme: sürükle-bırak alanı, önizlemeli dosya listesi, dosya başına ilerleme, iptal ve yeniden deneme, düzenleme formları için kayıtlı dosyalar, sıralama, avatar ve kompakt görünümler. Livewire bileşeninde de, Livewire olmayan klasik bir formda da çalışır.

PRO acun:file-upload
01

Temel kullanım

model dosyanın yükleneceği Livewire özelliğidir. Dosya alana bırakılır ya da alana tıklanarak seçilir; alanın tamamı bir düğmedir, klavyede Enter ya da Boşluk ile de açılır. Seçilen dosya alanın altındaki listede önizlemesi (görsellerde) ya da türünün simgesi, boyutu ve durumuyla görünür; yeni seçilen dosya öncekinin yerini alır. Alan odaktayken panodan yapıştırılan görsel de eklenir. Bu sayfada Livewire olmadığı için yükleme taklit edilir; adında "hata" geçen bir dosya hata satırını gösterir.

CANLI ÖRNEK
<acun:file-upload model="kimlik_belgesi" label="Kimlik belgesi" accept=".pdf,image/*" hint="Kimlik kartının ön yüzü · PDF ya da görsel" />
PropDeğerler
modelLivewire özelliği (WithFileUploads)
labelAlanın üstündeki etiket
titleAlandaki başlık; varsayılan "Dosyayı buraya bırakın"
hintAçıklama; verilmezse sınırlardan yazılır
02

Çoklu yükleme ve sınırlar

multiple ile birden çok dosya seçilir. Her dosya ayrı yüklenir ve kendi ilerleme çubuğunu gösterir; sıradakiler "Bekliyor" olarak bekler. Aktarım sürerken iptal edilebilir, hata ya da iptalden sonra yeniden denenebilir. accept, max-size-kb ve max-files tarayıcıda denetlenir: uymayan dosya yüklenmez, listede nedeniyle ("çok büyük (en fazla 2 MB)", "bu dosya türü kabul edilmiyor", "en fazla 5 dosya") görünür ve kapatılabilir. hint verilmediğinde açıklama bu sınırlardan yazılır. Bu denetimler yalnızca hızlı geri bildirimdir; aynı kuralları sunucuda da yazın (aşağıda "Livewire bileşeni").

CANLI ÖRNEK
<acun:file-upload model="belgeler" multiple accept=".pdf,.jpg,.png" :max-size-kb="2048" :max-files="5" label="Talep belgeleri" />
PropDeğerler
multipletrue | false
accept.pdf,.jpg | image/* | application/pdf
max-size-kbDosya başına KB sınırı
max-filesListedeki en fazla dosya (kayıtlılar dahil)
03

Kayıtlı dosyalar (düzenleme formu)

Daha önce kaydedilmiş dosyaları existing ile verin; her biri id, name, url, size (bayt) ve isteğe bağlı thumbnail (küçük resim adresi) taşır. Yeni dosyalarla aynı listede görünürler, adları yeni sekmede açılır ve max-files sınırına sayılırlar. Kaldırma düğmesi file-upload-remove-existing olayını { model, name, id } ile gönderir; remove-existing verilmişse o Livewire metodu da kimlikle çağrılır.

CANLI ÖRNEK
<acun:file-upload
    model="belgeler"
    multiple
    :max-files="5"
    :existing="$kayitliBelgeler"
    remove-existing="kayitliBelgeyiKaldir"
/>
PropDeğerler
existing[['id' => 7, 'name' => …, 'url' => …, 'size' => …, 'thumbnail' => …]]
remove-existingKimlikle çağrılan Livewire metodu
04

Sıralama

sortable ile çoklu listedeki dosyalar tutamaçtan sürüklenerek (fare ve dokunmatik) ya da satırdaki yukarı/aşağı düğmeleriyle (klavye) sıralanır. Her değişiklikte file-upload-sorted olayı { model, name, order } ile gönderilir; sort-method verilmişse Livewire metodu yeni sırayla çağrılır. order öğeleri kayıtlı dosya için { type: 'existing', id }, geçici yükleme için { type: 'upload', id } olur (id dosyanın getFilename() değeri). Livewire olmayan formda dosyalar form alanına liste sırasıyla eklenir.

CANLI ÖRNEK
<acun:file-upload model="fotograflar" multiple sortable sort-method="fotograflariSirala" accept="image/*" :existing="$kayitliFotograflar" />
PropDeğerler
sortabletrue | false (yalnızca multiple)
sort-methodYeni sırayla çağrılan Livewire metodu
05

Avatar

variant="avatar" tek bir görsel için yuvarlak bir seçici çizer: önizleme, "Değiştir" ve "Kaldır" düğmeleri; yükleme yüzdesi görselin üstünde görünür. accept verilmezse image/* kullanılır, multiple yok sayılır. Kayıtlı fotoğrafı existing ile verin; thumbnail yoksa url önizleme olur.

CANLI ÖRNEK
<acun:file-upload model="profil_fotografi" variant="avatar" label="Profil fotoğrafı" :max-size-kb="1024" :existing="$kayitliFotograf" remove-existing="fotografiKaldir" />
PropDeğerler
variant'default' | 'avatar' | 'compact'
06

Kompakt

variant="compact" sıkışık formlar için tek satırlık bir seçicidir: düğme, dosya adı, durum ve kaldırma aynı satırdadır; satırın üzerine dosya bırakılabilir. multiple ile kullanıldığında satırda dosya sayısı görünür, dosyalar altta listelenir.

CANLI ÖRNEK
<acun:file-upload model="fatura" variant="compact" label="Fatura" accept=".pdf" :max-size-kb="2048" />
07

Kameradan çekim

camera verildiğinde telefon ve tablet gibi dokunmatik cihazlarda "Kameradan Çek" düğmesi çıkar; arka kamerayla çekilen fotoğraf doğrudan listeye eklenir. Fare kullanılan cihazlarda düğme görünmez.

CANLI ÖRNEK
<acun:file-upload model="iade_fotografi" accept="image/*" camera hint="Hasarlı ürünün fotoğrafı" />
PropDeğerler
cameratrue | false
08

Doğrulama hataları

Bileşen modelin doğrulama hatalarını kendisi gösterir: belgeler hatası alanın altında, belgeler.2 gibi bir dosyaya ait hata o dosyanın satırında (Livewire'da özellikteki 2. sıradaki dosya). Tek dosyalı alanda hata doğrudan dosya satırında görünür. Mesajları sayfada kendiniz gösteriyorsanız :show-errors="false" verin.

CANLI ÖRNEK
<acun:file-upload model="belgeler" multiple accept=".pdf" :max-files="5" />
PropDeğerler
show-errorstrue | false
09

Livewire bileşeni

Bileşende WithFileUploads kullanın ve model ile aynı adda bir özellik tanımlayın; çoklu alan için boş bir dizi olsun (public array $belgeler = []), her dosya ayrı yüklenip bu diziye eklenir. Dosyalar önce Livewire'ın geçici klasörüne gider. updated kancasındaki doğrulama, hatayı yükleme biter bitmez dosyanın satırında gösterir. Kaydederken dosyaları store() ile kalıcı diske taşıyın ve özelliği sıfırlayın; liste sunucuyu izlediği için kendiliğinden boşalır. Listeden kaldırılan geçici dosya için bileşen $wire.removeUpload() çağırır (tek dosyalı alanda özelliği null yapar); ayrıca metot yazmanız gerekmez.

PHP
use App\Models\Talep;
use Illuminate\Support\Facades\Storage;
use Livewire\Component;
use Livewire\WithFileUploads;

class TalepBelgeleri extends Component
{
    use WithFileUploads;

    public Talep $talep;

    /** @var array<int, \Livewire\Features\SupportFileUploads\TemporaryUploadedFile> */
    public array $belgeler = [];

    /** @var array<int, int> Kaydedince silinecek kayıtlı belgeler */
    public array $silinecekler = [];

    protected function rules(): array
    {
        return [
            // Toplam 5 belge: kayıtlılar sayılır, silinecekler sayılmaz.
            'belgeler' => ['array', 'max:'.max(0, 5 - $this->kayitlilar()->count())],
            'belgeler.*' => ['file', 'mimes:pdf,jpg,png', 'max:2048'],
        ];
    }

    public function updatedBelgeler(): void
    {
        $this->validate(['belgeler.*' => $this->rules()['belgeler.*']]);
    }

    public function kayitliBelgeyiKaldir(int $id): void
    {
        $this->silinecekler[] = $id;
    }

    public function kaydet(): void
    {
        $this->validate();

        $this->talep->belgeler()->whereKey($this->silinecekler)->get()->each->delete();

        foreach ($this->belgeler as $belge) {
            $this->talep->belgeler()->create([
                'ad' => $belge->getClientOriginalName(),
                'yol' => $belge->store('talepler/'.$this->talep->id, 'public'),
                'boyut' => $belge->getSize(),
            ]);
        }

        $this->reset('belgeler', 'silinecekler');
    }

    private function kayitlilar()
    {
        return $this->talep->belgeler()->whereKeyNot($this->silinecekler);
    }

    public function render()
    {
        return view('livewire.talep-belgeleri', [
            'kayitliBelgeler' => $this->kayitlilar()->get()->map(fn ($belge) => [
                'id' => $belge->id,
                'name' => $belge->ad,
                'url' => Storage::disk('public')->url($belge->yol),
                'size' => $belge->boyut,
            ]),
        ]);
    }
}
10

Sıralamayı kaydetme

sort-method her sıralamada yeni sırayı alır. Kayıtlı dosyaların sırasını hemen yazabilir, geçici yüklemeleri aynı sıraya dizip kaydederken o sırayla saklayabilirsiniz. Kimlikleri her zaman kendi kaydınızla sınırlayın.

PHP
public function fotograflariSirala(array $sira): void
{
    foreach ($sira as $konum => $oge) {
        if ($oge['type'] === 'existing') {
            $this->urun->fotograflar()->whereKey($oge['id'])->update(['sira' => $konum]);
        }
    }

    // Geçici yüklemeler de aynı sıraya (id = getFilename()).
    $yuklemeSirasi = collect($sira)->where('type', 'upload')->pluck('id')->flip();

    $this->fotograflar = collect($this->fotograflar)
        ->sortBy(fn ($foto) => $yuklemeSirasi[$foto->getFilename()] ?? PHP_INT_MAX)
        ->values()
        ->all();
}
11

Klasik form (Livewire olmadan)

model yerine name verildiğinde önceden yükleme yapılmaz: seçilen dosyalar gizli bir <input type="file" name="ekler[]"> alanında tutulur ve form gönderilince sunucuya gider. Liste gönderimden önce düzenlenebilir; eklenen ve kaldırılan dosyalar alana hemen yansır. Form enctype="multipart/form-data" olmalıdır. Kaldırılan kayıtlı dosyaların kimlikleri removed-name ile verilen gizli alanlarla (kaldirilan_ekler[]) gönderilir. Form sıfırlandığında (reset) liste de temizlenir.

CANLI ÖRNEK
<form method="POST" action="{{ route('talepler.update', $talep) }}" enctype="multipart/form-data" class="space-y-4">
    @csrf
    @method('PUT')
    <acun:file-upload name="ekler" multiple accept=".pdf,.jpg,.png" :max-size-kb="2048" :max-files="5" :existing="$kayitliEkler" removed-name="kaldirilan_ekler" />
    <acun:button type="submit">Kaydet</acun:button>
</form>
PropDeğerler
nameForm alanı; multiple ise sonuna [] eklenir
removed-nameKaldırılan kayıtlı dosya kimliklerinin gizli alanı
12

Klasik form: controller

Doğrulamayı sunucuda yapın: dosya türü ve boyutu accept ve max-size-kb ile aynı olsun (max: kuralı KB alır); dosya sayısı max-files sınırından kayıtlı dosyaları düşerek hesaplanır. Doğrulama hatasında tarayıcı seçilen dosyaları geri getiremez; ekler ve ekler.* hataları bileşenin altında listelenir.

PHP
public function update(Request $request, Talep $talep): RedirectResponse
{
    $kaldirilan = $request->input('kaldirilan_ekler', []);
    $kalan = 5 - $talep->ekler()->whereKeyNot($kaldirilan)->count();

    $request->validate([
        'ekler' => ['array', 'max:'.max(0, $kalan)],
        'ekler.*' => ['file', 'mimes:pdf,jpg,png', 'max:2048'],
        'kaldirilan_ekler' => ['array'],
        'kaldirilan_ekler.*' => ['integer'],
    ]);

    $talep->ekler()->whereKey($kaldirilan)->get()->each->delete();

    foreach ($request->file('ekler', []) as $ek) {
        $talep->ekler()->create([
            'ad' => $ek->getClientOriginalName(),
            'yol' => $ek->store('talepler/'.$talep->id),
            'boyut' => $ek->getSize(),
        ]);
    }

    return back();
}
13

Yükleme durumu ve olaylar

Bileşen Livewire'ın yükleme olaylarını (livewire-upload-start, -finish, -error) kendisi gönderdiği için wire:loading ve wire:target model adıyla çalışır; kuyruk bitene kadar kaydet düğmesini kilitleyebilirsiniz. Pencerede file-upload-reset olayı { model } (klasik formda { name }) ile gönderilirse süren yükleme iptal edilir, bekleyenler ve hatalı satırlar temizlenir (ör. bir modal kapanırken).

BLADE
<acun:file-upload model="belgeler" multiple />

<div class="mt-4 flex justify-end gap-2">
    <acun:button variant="white" x-data x-on:click="$dispatch('file-upload-reset', { model: 'belgeler' })">Vazgeç</acun:button>
    <acun:button wire:click="kaydet" wire:loading.attr="disabled" wire:target="belgeler,kaydet">Kaydet</acun:button>
</div>
PropDeğerler
file-upload-resetPencereye gönderilir; { model: 'belgeler' }
file-upload-remove-existing{ model, name, id }
file-upload-sorted{ model, name, order }
14

Livewire olmadan yükleme (ileri düzey)

Livewire bileşeni olmayan bir sayfada model ile yükleme yapmak için kendi aktarımınızı kaydedin (ör. doğrudan bir depolama servisine). upload her dosya için { promise, cancel } döndürür; promise dosyanın kimliğiyle çözülür, cancelled: true taşıyan bir hatayla reddedilirse satır iptal edildi olarak işaretlenir. concurrency aynı anda kaç dosyanın gönderileceğidir. Livewire ile her dosya sırayla gönderilir; Livewire aynı özelliğe yüklemeleri tek tek işler.

JS
import { registerFileUpload } from '@acunsoft/acun-ui-pro';

document.addEventListener('alpine:init', () => {
    registerFileUpload(window.Alpine, {
        transport: {
            concurrency: 3,
            upload(file, { onProgress }) {
                const request = new XMLHttpRequest();
                const promise = new Promise((resolve, reject) => {
                    request.upload.onprogress = (event) => onProgress((event.loaded / event.total) * 100);
                    request.onload = () => (request.status < 300 ? resolve(JSON.parse(request.response).id) : reject(new Error('failed')));
                    request.onerror = () => reject(new Error('failed'));
                    request.onabort = () => reject(Object.assign(new Error('cancelled'), { cancelled: true }));
                });
                const body = new FormData();
                body.append('file', file);
                request.open('POST', '/yuklemeler');
                request.setRequestHeader('X-CSRF-TOKEN', document.querySelector('meta[name=csrf-token]').content);
                request.send(body);

                return { promise, cancel: () => request.abort() };
            },
        },
    });
});
API

Prop'lar ve slot'lar

Bileşenin kabul ettiği değerler.

PropVarsayılanAçıklama
modelnullDosyaların yükleneceği Livewire özelliği (WithFileUploads); model ya da name gerekir
namenullLivewire olmadan: form alanının adı; dosyalar formla gönderilir
multiplefalseBirden çok dosya
variant'default''default' | 'avatar' (yuvarlak tek görsel) | 'compact' (tek satır)
accept'''.pdf,.jpg', 'image/*' gibi; tarayıcıda denetlenir
max-size-kbnullDosya başına KB sınırı; tarayıcıda denetlenir
max-filesnullÇoklu listedeki en fazla dosya (kayıtlılar dahil)
remainingnullÇoklu modda eklenebilecek dosya sayısı (eski kullanım; yerine max-files)
existing[]Kayıtlı dosyalar: id, name, url, size, thumbnail
remove-existingnullKayıtlı dosya kaldırılınca kimlikle çağrılan Livewire metodu
removed-namenullLivewire olmadan: kaldırılan kayıtlı dosya kimliklerinin gizli alan adı
sortablefalseSürükleyerek ve düğmelerle sıralama (multiple)
sort-methodnullYeni sırayla çağrılan Livewire metodu
labelnullAlanın üstündeki etiket
requiredfalseEtikete * ekler; ekran okuyucular seçme düğmesinin adında "zorunlu" duyar. Kuralı sunucuda da yazın
titlenullAlandaki başlık; verilmezse "Dosyayı / Dosyaları buraya bırakın"
hintnullAçıklama; verilmezse sınırlardan yazılır
camerafalseDokunmatik cihazlarda "Kameradan Çek" düğmesi
show-errorstruemodel ve model.* doğrulama hatalarını gösterir
Acun UI · Dosya yüklemeDetaylı kullanım ve örnekler