Yeniden oluşturma (Rebuild) sistemi
Bazı veriler başka verilerden türetilir: bir kategorideki yazı sayısı, bir bölümün konu sayısı, bir sayfanın kayıtlı HTML çıktısı, bir arama dizini. Türetilmiş veri zamanla bozulabilir: bir içe aktarma, elle yapılan SQL, bir kütüphane yükseltmesi ya da yarıda kalmış bir işlem sayaçları yanlış bırakır. Rebuild sistemi bu veriyi kaynağından yeniden hesaplar.
Kural
İçerik üreten her modül, yeniden oluşturma sistemine kendini dahil etmelidir.
Çekirdek, hiç duymadığı bir tabloyu yeniden sayamaz. Forum modülü rebuilder kaydetmezse Rebuild ekranı forum konularını ve sayaçlarını düzeltemez. Bu yüzden kural bir tercih değil, modülün sözleşmesinin parçasıdır.
Kuralın iki yolu vardır:
- Bir rebuilder kaydetmek (aşağıda), ya da
- Neden gerekmediğini söylemek: modülün türetilmiş verisi yoksa
module.jsoniçine yazın:
"rebuild": {
"exempt": "Notes keeps no derived counters or indexes; every value is stored as the user wrote it."
}
Bu kural cp:doctor tarafından denetlenir: varlığı (Entity/ klasöründe sınıfı) olan etkin bir modül ne bir rebuilder kaydediyor ne de muafiyet bildiriyorsa rebuild.module_uncovered uyarısı çıkar. Uyarı hangi modülün eksik olduğunu adıyla söyler.
php cp-core/bin/console cp:doctor
Nasıl çalışır
RebuilderInterface uygulayan her sınıf cpalius.rebuilder etiketini otomatik alır; modülün services.yaml'ında yalnızca sınıfın bulunduğu klasörün tanımlı olması yeter (Modules\Foo\Rebuild\: resource: '../../Rebuild/'). RebuilderRegistry hepsini kimliğine göre toplar; aynı kimlik iki kez kayıtlıysa bu bir hatadır, çünkü iki iş aynı rotayı ve ilerleme durumunu ezerdi. Pasif modülün rebuilder'ı konteynerde yoktur, liste kendiliğinden küçülür.
İş parti parti çalışır. Tarayıcıdaki koşucu her istekte rebuild($offset, $limit) çağırır; dönen sayı $limit'ten küçükse iş biter. Bu, ucuz barındırmada PHP zaman aşımına takılmadan milyonlarca satırı işlemenin yoludur.
İki ekran vardır:
| Ekran | Adres | Neyi gösterir |
|---|---|---|
| Studio → Yeniden oluştur | /admin/tools/rebuild |
Site masası: içerik sayaçları (isStudioVisible() = true olanlar) |
| AACP → Bakım → Yeniden oluştur | /aacp/maintenance/rebuild |
Platform masası: Core önbellekleri dahil tüm işler; tek tek ya da "hepsini" sırayla |
"Hepsini yeniden oluştur" işleri getPriority() sırasıyla çalıştırır: önce içerik sayaçları, en sonda Core önbellekleri.
Rebuilder yazmak
namespace Modules\Foo\Rebuild;
use App\Core\Rebuild\RebuilderInterface;
use Doctrine\ORM\EntityManagerInterface;
final class FooCountRebuilder implements RebuilderInterface
{
public function __construct(private readonly EntityManagerInterface $em) {}
public function getId(): string { return 'foo.counts'; } // <modül>.<ne>; yayınlandıktan sonra asla değişmez
public function getName(): string { return 'foo.rebuild.counts'; } // çeviri anahtarı
public function getDescription(): string { return 'foo.rebuild.counts_desc'; }
public function getBatchSize(): int { return 100; } // bir istekte işlenecek satır
public function getPriority(): int { return 50; } // küçük önce
public function isStudioVisible(): bool { return true; }
public function getTotal(): int
{
return (int) $this->em->getRepository(Foo::class)->count([]);
}
public function rebuild(int $offset, int $limit): int
{
$rows = $this->em->getRepository(Foo::class)->findBy([], ['id' => 'ASC'], $limit, $offset);
foreach ($rows as $row) {
// türetilmiş değeri kaynağından yeniden hesapla
}
$this->em->flush();
$this->em->clear(); // ZORUNLU: uzun çalışma tüm tabloyu belleğe doldurmasın
return \count($rows); // ziyaret edilen satır, işe yaramayanlar dahil
}
}
Kurallar:
COUNT(*)yazma yolunda değil, burada yapılır. Yazı kaydedilirken sayaç için tabloyu saymayın; sayacı artırın/azaltın ve rebuilder'ı doğrulayıcı olarak kullanın.- Idempotent olun. İki kez çalıştırmak aynı sonucu vermeli.
- Her parti hızlı dönmeli (
getBatchSize()'ı küçük tutun). getTotal()ucuz olmalı; yalnızca yüzde çubuğu içindir.- Offset'e güvenin, durum tutmayın. Koşucu her istekte sıfırdan çağırır.
- Çeviri anahtarlarını modülün
messages+intl-icu.<dil>.yamldosyasına ekleyin.
Örnekler
| Modül | Rebuilder | Ne yeniden hesaplanır |
|---|---|---|
| Blog | blog.categories |
Her kategorideki yayınlanmış yazı sayısı |
| Forum | forum.topics, forum.sections, forum.user_stats, ACL temizliği |
Konu/mesaj sayaçları, bölüm sayaçları, üye istatistikleri |
| Belgeler | docs.render |
Her sayfanın kayıtlı HTML'i ve içindekiler listesi (Markdown kaynağından) |
| Core | core.caches |
Çekirdek önbellekleri |
Sonraki: Hook, cron, kuyruk.