# Composer ile kendi paketimi Packagist'te yayımlamak

> Bir PHP paketini sıfırdan yapılandırıp Packagist'e göndererek başkalarının kullanımına açtım; adımları aktarıyorum.

- Yayın: 2015-11-01
- Kategori: Araçlar & Teknolojiler
- Etiketler: PHP, Composer
- Okuma süresi: 4 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/composer-ile-kendi-paketimi-packagistte-yayimlamak/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
Birkaç projede aynı yardımcı sınıfı kopyalayıp yapıştırdığımı fark ettim. Her seferinde güncel mi eski mi diye karşılaştırıyordum. Bir gün "bunu Composer paketi yapsam?" diye düşündüm ve denedim. Sonuç tahmin ettiğimden daha kolay oldu.

Bu yazıda sıfırdan bir PHP paketi yapılandırmayı ve **Packagist** (PHP paket deposu) üzerinde yayımlamayı adım adım anlatacağım. Packagist, [Composer](/blog/composera-gecis-php-bagimliliklarini-elle-yonetmeyi-birakmak)'ın varsayılan olarak baktığı genel paketi deposu.

## Paket yapısı

Bir Composer paketi aslında belirli bir yapıya sahip klasörden ibaret. Temel düzende şunlar olmalı:

```
benim-paketim/
├── src/
│   └── YardimciSinif.php
├── tests/
│   └── YardimciSinifTest.php
├── composer.json
├── .gitignore
└── README.md
```

`src/` altında PHP dosyalarınız, `tests/` altında testler, ve her şeyin merkezi olan `composer.json`.

## composer.json dosyasını hazırlamak

```json
{
    "name": "muhammetsafak/yardimci",
    "description": "Günlük PHP geliştirmede işime yarayan yardımcı sınıflar",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "Muhammet Şafak",
            "email": "ornek@ornek.com"
        }
    ],
    "require": {
        "php": ">=5.5"
    },
    "require-dev": {
        "phpunit/phpunit": "~4.0"
    },
    "autoload": {
        "psr-4": {
            "Muhammetsafak\\Yardimci\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Muhammetsafak\\Yardimci\\Tests\\": "tests/"
        }
    }
}
```

Birkaç önemli nokta:

- **`name`:** `sahip/paket` biçiminde. Packagist'te eşsiz olmalı.
- **`autoload`:** PSR-4 kuralıyla namespace ile klasör eşleştirmesi yapılıyor. `Muhammetsafak\Yardimci\` namespace'indeki sınıflar `src/` altında aranıyor.
- **`require-dev`:** Yalnızca geliştirme sırasında gereken bağımlılıklar buraya giriyor — tüketicinin `composer install` yapmasında indirilmiyor.

`type: "library"` alanını doğru yazmak önemli. Packagist bu alana bakarak paketi nasıl sınıflandıracağına karar veriyor. Bir [Laravel](/blog/laravel-5e-gecis-yeni-dizin-yapisi-ve-env) paketi yapıyorsanız `type: "library"` yine geçerli; Laravel'e özgü service provider'lar `extra` alanında tanımlanıyor.

## Basit bir sınıf yazmak

```php
<?php

namespace Muhammetsafak\Yardimci;

class Metin
{
    public static function kisalt(string $metin, int $uzunluk = 100, string $son = '...'): string
    {
        if (mb_strlen($metin) <= $uzunluk) {
            return $metin;
        }

        return mb_substr($metin, 0, $uzunluk) . $son;
    }

    public static function slug(string $metin): string
    {
        $metin = mb_strtolower($metin, 'UTF-8');
        $metin = str_replace(
            ['ç', 'ş', 'ğ', 'ı', 'İ', 'ö', 'ü'],
            ['c', 's', 'g', 'i', 'i', 'o', 'u'],
            $metin
        );
        $metin = preg_replace('/[^a-z0-9\s-]/', '', $metin);
        $metin = preg_replace('/[\s-]+/', '-', $metin);

        return trim($metin, '-');
    }
}
```

Bu sınıfı yazmadan önce fark ettiğim bir şey: kütüphanede kullanılan tüm fonksiyonlar `mb_` önekli olmalı. `strlen` yerine `mb_strlen`, `strtolower` yerine `mb_strtolower`. Kütüphane başkası tarafından kullanılacaksa ve o kişinin metin verisi UTF-8 dışında bir encoding içeriyorsa, düz string fonksiyonları sessizce yanlış sonuç üretebilir.

## GitHub'a göndermek

Packagist GitHub deposuyla çalışıyor. Paketi bir GitHub deposuna göndermek gerekiyor.

Sürüm etiketleri (tag) önemli. Composer etiketlere bakarak hangi sürümü indireceğine karar veriyor. Semantic versioning kuralına göre:

```bash
git tag v1.0.0
git push origin v1.0.0
```

`v1.0.0`, `v1.0.1`, `v1.1.0` gibi etiketler Composer tarafından sürüm olarak algılanıyor.

Etiket olmadan da `dev-main` gibi dal ismiyle paket kullanılabilir; ama bu kararlı bir bağımlılık değildir. Tüketicinin `composer.json`'unda `"minimum-stability": "dev"` ayarlanması gerekiyor ve bu pratikte önerilmiyor. Düzgün etiketlenmiş sürümler kullanmak, tüketicilerin tam olarak hangi kodu aldığını bilmesini sağlıyor.

## Packagist'e kaydetmek

packagist.org'a GitHub hesabınızla giriş yapın. "Submit" (Gönder) sayfasında GitHub deponuzun URL'ini yapıştırın — Packagist `composer.json`'u okuyup paketi oluşturuyor.

Bundan sonra:

```bash
composer require muhammetsafak/yardimci
```

komutuyla herkes paketi projelerine ekleyebiliyor.

## Otomatik güncelleme için webhook

Paketi her güncellediğinizde Packagist'i haberdar etmek için webhook kurmak gerekiyor. GitHub deposunun ayarlarından "Webhooks" bölümüne girin; Packagist size bir URL ve token veriyor. Bu ikisini webhook olarak ekleyin. Bundan sonra her `git push`'ta Packagist otomatik güncellenecek.

Webhook kurmadan da Packagist panelinden manuel "Force Update" tetikleyebilirsiniz — ama bu tek seferlik bir çözüm. Webhook, yeni sürüm etiketlediğinizde birkaç dakika içinde Packagist'in güncel bilgiyi görmesini sağlıyor.

## .gitignore ve dağıtım dosyaları

Pakete `.gitignore` eklemenin yanı sıra bir `.gitattributes` dosyası oluşturmak iyi alışkanlık. Bu dosyada test klasörü ve geliştirme araçlarını dışarıda bırakabilirsiniz:

```
/tests export-ignore
/.github export-ignore
phpunit.xml export-ignore
```

Böylece tüketici `composer install --prefer-dist` yaptığında yalnızca `src/` içeriği indiriliyor; testler ve CI yapılandırmaları indirilmiyor. Paketi kullanan projenin `vendor/` klasörü gereksiz yere şişmiyor.

## İlk yayım deneyimi

Paketi Packagist'e gönderip başka bir projede `composer require` ile kurunca garip bir his oluştu. Kendi yazdığım kodu bağımlılık olarak kullanmak. Sonraki güncellemede tüm projelerde `composer update` yeterli.

Bir hatayı düzelttim, `v1.0.1` etiketi bastım, GitHub'a gönderdim. Webhook sayesinde Packagist hemen güncellendi. Bağımlı projelerde `composer update muhammetsafak/yardimci` ile son sürüm geldi. Bu döngüyü ilk yaşadığımda kopyalayıp yapıştırmanın ne kadar kırılgan bir yöntem olduğunu bir kez daha anladım.

Kütüphane yazmak büyük bir iş gibi görünüyor ama küçük, tek amacı olan paketler gerçekten faydalı. Kopyalayıp yapıştırmak yerine versiyonlanan, paylaşılabilir kod. Bu alışkanlık zaman içinde kodu daha modüler düşünmeye de yönlendiriyor.
