Phalcon’da Neler Ters Gidiyor?
Ben de iki can sıkıcı sorunla karşılaştım:
- e_id Hatası:
note_id
gibi masum bir sütun adını sorguya yazdığında, Phalcon’un bununot e_id
gibi ayrıştırıp “Column ‘e_id’ doesn’t exist” hatası vermesi. - SoftDelete ile Kalıcı Silme Sorunu:
SoftDelete
davranışını kullanıyorsun, ama bazen kayıtları gerçekten veritabanından silmen gerekiyor. Phalcon, modeliinitialize
edip önbelleğe aldığı için bu davranışı çalışma anında atlamak neredeyse imkânsız.
Bu sorunlar seni de çıldırttı mı? Hadi, çözümleri konuşalım!
Neden Bu Kadar Sinir Bozucu?
e_id Hatası
Diyelim ki NotesTranslations
modelinde bir sorgu çalıştırıyorsun:
$translation = NotesTranslations::findFirst([
'conditions' => 'note_id = :noteId:',
'bind' => ['noteId' => 123]
]);
Ve BAM! Karşında şu hata:Column 'e_id' doesn't belong to any of the selected models
.
Neden? Çünkü Phalcon’un PHQL motoru, note_id
’yi ayrıştırırken not
ifadesini bir operatör sanıyor ve e_id
’yi bir sütun gibi algılıyor. Tabii ki veritabanında böyle bir sütun yok! Saatlerce debug yap, stack trace’leri tara, ama çözüm internette bile zor bulunuyor. Bu hata, özellikle sütun adlarında not
gibi kelimeler geçtiğinde seni çaresiz bırakabilir.
SoftDelete Sorunu
SoftDelete
davranışıyla çalışırken, is_deleted
gibi bir sütunu güncelleyerek kayıtları “silmiş” gibi yapıyorsun. Ama bazen, mesela bir test ortamında veya yasal bir gereklilik yüzünden, kayıtları gerçekten silmen gerekiyor. Phalcon’un modelsManager
’ı, modeli ilk sorguda initialize
edip önbelleğe alıyor. Bu yüzden SoftDelete
’i çalışma anında devre dışı bırakmak mümkün değil. Ne denesen olmuyor:
- Statik bir bayrak (
$disableSoftDelete
) ekliyorsun, ama model zaten önbelleğe alınmış. - Çocuk sınıf oluşturuyorsun, ama Phalcon yine ana sınıfı kullanıyor.
- PHQL ile ham sorgu yazıyorsun, ama yine modelin davranışları devreye giriyor.
Bu durum, projenin ortasında saatlerini yiyebilir ve seni “Neden Phalcon kullanıyorum ki?” diye sorgulamaya itebilir.
İşte Çözümler!
1. e_id Hatasını Çözme
e_id
hatasının çözümü basit ama kurnazca: PHQL sorgularında sütun adlarını köşeli parantez ([]
) ile sar! Bu, Phalcon’un sütun adını yanlış ayrıştırmasını önler. Örneğin:
$translation = NotesTranslations::findFirst([
'conditions' => '[note_id] = :noteId: AND [language_id] = :languageId:',
'bind' => [
'noteId' => 123,
'languageId' => 1
]
]);
Bu küçük değişiklik, Phalcon’un note_id
’yi not e_id
gibi görmesini engeller. Artık hata yok, sorgu düzgün çalışıyor! Ama dikkat: Bu sadece PHQL sorguları için geçerli. PDO ile ham SQL yazarsan, köşeli parantezlere gerek kalmaz.
İpucu: Eğer sütun adlarında not
gibi başka potansiyel tuzaklar varsa (örneğin, order_id
veya set_id
), her zaman [sütun_adı]
formatını kullan. Böylece Phalcon’un PHQL motorunu kandırmış olursun!
2. SoftDelete ile Kalıcı Silme
SoftDelete
davranışını atlayarak kalıcı silme yapmak için en kesin çözüm, Phalcon’un model katmanını tamamen bypass edip PDO ile ham SQL sorguları kullanmak. Neden? Çünkü PHQL, modeli initialize
eder ve SoftDelete
davranışını devre dışı bırakamazsın. İşte adım adım çözüm:
Adım 1: PDO ile Ham SQL
Notes
modelinde kalıcı silme için bir deletePermanently
metodu yazalım:
public function deletePermanently()
{
$messages = [];
$db = $this->getDI()->getDb(); // PDO bağlantısını al
try {
$sql = "DELETE FROM notes WHERE id = :id";
$stmt = $db->prepare($sql);
$stmt->execute(['id' => $this->id]);
error_log("Deleted {$stmt->rowCount()} rows from notes for id = {$this->id}");
return [true, $messages];
} catch (\PDOException $e) {
$messages[] = "Database error: {$e->getMessage()}";
error_log("Error in deletePermanently: {$e->getMessage()}");
return [false, $messages];
}
}
Adım 2: Controller’da Kullanım
NotesController
’da bu metodu çağıran bir action yazalım:
public function deletePermanentlyAction()
{
$json = $this->request->getJsonRawBody();
if (!isset($json->noteId)) {
return $this->response->setJsonContent([
'status' => 'error',
'success' => false,
'error' => 'Note ID is required',
'data' => []
]);
}
$note = Notes::findFirst([
'conditions' => '[id] = :id:',
'bind' => ['id' => (int)$json->noteId]
]);
if (!$note) {
return $this->response->setJsonContent([
'status' => 'error',
'success' => false,
'error' => 'Note not found',
'data' => []
]);
}
try {
[$success, $messages] = $note->deletePermanently();
if (!$success) {
return $this->response->setJsonContent([
'status' => 'error',
'success' => false,
'error' => $messages ?: ['Failed to delete permanently'],
'data' => []
]);
}
} catch (\Exception $e) {
return $this->response->setJsonContent([
'status' => 'error',
'success' => false,
'error' => $e->getMessage(),
'data' => []
]);
}
return $this->response->setJsonContent([
'status' => 'success',
'success' => true,
'error' => null,
'data' => []
]);
}
Adım 3: Hata Ayıklama
Eğer silme işlemi başarısız olursa, veritabanı kısıtlamalarını kontrol et. Örneğin:
SHOW CREATE TABLE notes_translations;
Foreign key varsa ve ON DELETE CASCADE
tanımlı değilse, yukarıdaki kod zaten ilişkili kayıtları önce siliyor.
İpucu: Loglama ekle! Her silme işlemi sonrası etkilenen satır sayısını ($stmt->rowCount()
) logla. Böylece hangi tablodan kaç kayıt silindiğini görebilirsin.
Son Söz
Phalcon güçlü bir framework, ama bu tür tuzaklar her geliştiricinin başına gelebilir. e_id
hatasını [note_id]
ile çözmek ve SoftDelete
’i PDO ile atlamak, saatlerce debug yapmaktan kurtarır. Umarım bu çözümler senin de projelerinde işini kolaylaştırır! Başka bir Phalcon maceranda takılırsan, bloguma göz at veya bana yaz, birlikte çözeriz!