Drupal – Veriye Sahip Bir Alanın Güncellenmesi (Hook Update)

Drupal 8.9.x sürümünde denenmiştir. modulname_update_8900 bir kez çalışacaktır. Sonraki kullanımda modulname_update_8901… (+1) olarak güncellemeniz gerekmektedir.

function modulename_update_8900() {

$database = \Drupal::database();

$entityType = 'node';
$fieldName = 'field_yourfield';
$table = $entityType . '__' . $fieldName;

$currentRows = NULL;
$newFieldsList = [];
$fieldStorage = FieldStorageConfig::loadByName($entityType, $fieldName);

if (is_null($fieldStorage)) {
	return;
}

// Get all current data from DB.
if ($database->schema()->tableExists($table)) {
  
	// The table data to restore after the update is completed.
    $currentRows = $database->select($table, 'n')
    ->fields('n')
    ->execute()
    ->fetchAll();
}

// Use existing field config for new field.
foreach ($fieldStorage->getBundles() as $bundle => $label) {
    $field = FieldConfig::loadByName($entityType, $bundle, $fieldName);
    $newField = $field->toArray();
    $newField['field_type'] = 'text_long';
    $newField['settings'] = [];
    $newFieldsList[] = $newField;
}

$newFieldStorage = $fieldStorage->toArray();
$newFieldStorage['type'] = 'text_long';
$newFieldStorage['settings'] = [];

// Deleting field storage which will also delete bundles(fields).
$fieldStorage->delete();

// Purge field data now to allow new field and field_storage with same name
// to be created.
field_purge_batch(40);

// Create new field storage.
$newFieldStorage = FieldStorageConfig::create($newFieldStorage);
$newFieldStorage->save();

// Create new fields.
foreach ($newFieldsList as $nfield) {
    $nfieldConfig = FieldConfig::create($nfield);
    $nfieldConfig->save();
}

// Restore existing data in new table.
if (!is_null($currentRows)) {
  foreach ($currentRows as $row) {
      $database->insert($table)
      ->fields((array) $row)
      ->execute();
  }
}
  
}

Drupal 8’den Drupal 9’a Yükseltme

Bağımlılıkların yönetiminde ortaya çıkması muhtemel “Tavuk/Yumurta” sorununu önlemek adına –no-update seçeneğini kullanmalıyız:

composer require 'drupal/core-recommended:^9' 
'drupal/core-composer-scaffold:^9' 
'drupal/core-project-message:^9' 
--update-with-dependencies --no-update

Sistemde drupal/core mevcutsa güncellenmelidir:

composer require 'drupal/core-dev:^9' --dev 
--update-with-dependencies --no-update

Drupal 9’a ait core gereksinimleri composer.json dosyasına eklendikten sonra güncellemeyi başlatabiliriz:

composer update

Güncelleme sonrasında ilk iş olarak önbellek rebuild edilmelidir. Bu esnada, giderilmesi gereken deprecated hataları gözlemlenir.

drush cr

admin/reports/status ekranından INCOMPATIBLE MODULES (Drupal 9 ile uyumsuz olan modüller) görüntülenir. Modüller Drupal 9 ile uyumlu hale getirilmelidir.

İlk olarak, modüle ait .info dosyasına:

  • core_version_requirement: '^8 || ^9' eklenmelidir.
  • core: 8.x gibi bir ifade varsa kaldırılmalıdır.

Deprecated Düzeltmeleri

The ::getCurrentUserId method is deprecated

Hata mesajı alınan modüle ait config (yaml) dosyası içerisindeki default_value_callback değeri:
default_value_callback: ‘Drupal\node\Entity\Node::getCurrentUserId’ yerine,
default_value_callback: ‘Drupal\node\Entity\Node::getDefaultEntityOwner’ olarak değiştirilmelidir.

php 7.3 üzerinde Drupal 9 uyumsuzluk çözümü

Drupal 9, en düşük PHP sürümü olarak 8 ve üzerini önermektedir. 7.3 ile birlikte kullanımında, bazı paketlerin downgrade edilmesi gerekmektedir. Bu durum stabiliteyi bozmaktadır. Mecbur kalınması durumunda geçici olarak bu yöntem kullanılabilir.

Drupal 9.3.7 sürümü için aşağıdaki paketler php 7.3 sürümünü desteklemektedir. composer.json dosyasında belirtildiği takdirde php 7.3 çalıştıran sunucuya Drupal 9 kurulumu sağlanacaktır.

"laminas/laminas-servicemanager": "v3.7.0",
"mglaman/phpstan-drupal": "v1.1.4",
"friends-of-behat/mink-browserkit-driver": "v1.5.0",
"laminas/laminas-zendframework-bridge": "v1.4.1"

Drupal – Hata Gösterimi

Ayrıntılı sistem hatalarını ekranda göstermek için settings.php dosyanızın sonuna ekleyin.

//append to settings.php
$config['system.logging']['error_level'] = 'verbose';

Sadece notice, warning ve deprecated hataları dışındakilerin gösterilmesini isterseniz, ekrana basılacak uyarıları filtreleyebilirsiniz. Yine settings.php dosyanızın sonuna aşağıdaki satırı ekleyin.

error_reporting( E_ALL ^ ( E_NOTICE | E_WARNING | E_DEPRECATED ) );

Drupal – SQL Sorguları

SQL sorguları, Drupal 8 ve 9 yapısına uygun olarak hazırlanmıştır. Views ya da modül oluşturmadan, sorgulardan hızlıca yararlanabiliriz.

İçerik Tipleri (Content Types)

İçerik Tiplerinin Listelenmesi:

select distinct type from node_field_data;

İçerik Tipine Göre Toplam İçerik Sayısı:

select count (nid) from node_field_data where type = 'content_type_name';

İçerik Tipine Göre İçeriklerin Listelenmesi:

select title from node_field_data where type = 'content_type_name';

Toplam İçerik Sayısı:

select count (nid) from node_field_data;

Tablo Birleştirme

select n.title                   as title,
       sd.field_start_date_value as start_date,
       ed.field_end_date_value   as end_date,


from node_field_data n
       left join node__field_start_date sd on sd.entity_id = n.nid
       left join node__field_end_date ed on ed.entity_id = n.nid


where type = 'content_type';

Kullanıcılar

Kullanıcıların Listelenmesi:

select uid, name, mail,login from users_field_data;

Kullanıcıya Ait İçeriklerin Listelenmesi:

select * from node_field_data n
left join users_field_data u ON u.uid = n.uid
where u.name = 'username';

Flood Tablosu

5 kez hatalı login-attemp sebebiyle kullanıcılar 6 saatliğine bloklanarak flood tablosuna eklenmektedir.

Flood tablosunu boşaltmak için:

delete from flood;

Tablo index değerini sıfırlayarak flood tablosunu boşaltmak için:

truncate flood;

Watchdog Sorguları

Watchdog Tablolarının Kapladığı Alanları MB Cinsinden Gösteren Sorgu:

SELECT
    table_schema as `Database`,
    table_name AS `Table`,
    round(((data_length + index_length) / 1024 / 1024), 2) `Size in MB`
FROM information_schema.TABLES
where TABLE_NAME = 'watchdog'
ORDER BY (data_length + index_length) DESC;

Drupal – DBlog (Watchdog)

Database Logging modülü, CMS’teki etkinlikleri veritabanına kaydeder. Watchdog ismi ile de tanınmaktadır. Verilerin kaydedildiği tablonun adı da watchdog’dur. Drupal’in core modüllerinden biri olup kurulumda aktif olarak gelmektedir.

Watchdog Kayıt Türleri

  • Kullanıcı eylemlerini (giriş, çıkış, yeni kullanıcı vs)
  • Node (içerik, dosya) ekleme, silme ve değişik bilgilerini (kullanıcı bilgisiyle)
  • Hata ve uyarıları (php, form, image not found, access denied, modül ekleme)
  • Cron gibi operasyonel bilgileri
  • Modül spesifik ve custom modül loglarını kaydetmektedir.

Kayıtları Görüntülemek

/admin/reports/dblog (Recent Log Messages) ekranından görüntüleyip filtreleme yapabiliriz.

Ayarlar

/admin/config/development/logging ekranından;

  • Kaydedilecek log döngü adedi (All, 100, 1000, 10000, 100000, 1000000) seçimi,
  • Görüntülenecek mesaj seçimi,
  • syslog ayarları yapılmaktadır.

Log sayısı FIFO yapısında rotate olmaktadır. İlk kayıttan sona doğru kayıtlar silinmektedir.
Silme işlemi dblog_cron tarafından yapılır ve her cron çalıştığında gerçekleşir.

Drupal Cron Logları

Drupal cron çalıştığında, tüm drupal core cronları ve custom modüller içerisinde yer alan cron hookları çalıştırılmaktadır. Her cron fonksiyonu için watchdog tablosuna kayıt eklenir. Bu, hangi cronların çalıştığını görmek açısından yararlı olabilir ancak db’de ekstra yer kaplayacaktır.

Detaylı cron loglamayı kapatmak için /admin/config/system/cron ekranından gereken ayarlamayı yapabilirsiniz. Bu sayede tüm cronların bilgisini tek satırlık kayda düşürebilirsiniz.

Drupal Cron, her 3 saatte bir kez çalışır. Bu görevi 6 saat, 12 saat, 1 gün, 1 hafta gibi daha geniş bir zamana yayabilirsiniz. Bu işlem sayesinde otomatik bakım daha az sıklıkla yapılacak ve cron logları veritabanını daha uzun sürede dolduracaktır.

Boyutlar (Yaklaşık)

Log kayıtları sınırsız (All) yapılmamalıdır. Bu şekilde unutulursa, diskte, bizden habersiz onlarca GB yer tutabilir.

  • 1000 kayıt ~3 ile 5 MB,
  • 3000 kayıt ~10-15 MB,
  • 10000 kayıt ~25-50 MB,
  • 30000 kayıt ~200-250 MB
  • 100000 kayıt ~1 GB yer kaplamaktadır.

Her üç saatte bir cron çalışan bir sistemde;
*Günde ortalama 10 kullanıcı giriş çıkış yaparsa 20 satır kayıt oluşur.
*Günde ortalama 10 içerik eklenir ya da güncellenirsa 10 satır kayıt oluşur.
*Detaylı cron açıksa günde 8 kez çalışır ve 96 satır kayıt oluşur.
Toplamda günlük ortalama 130-150 kayıt gözlemlenebilir ve 1000’lik döngü 1 hafta içerisinde yenilenir.

Diğer hata ve uyarılar, custom modüllere özel loglar hesaplama dışında tutulmuştur.

DBlog vs SysLog

DBlog, hemen hemen tüm olayları db’ye yazdığı için yüksek trafikli sistemlerde, sistemi yavaşlatabilir.
Bu durumda, DBlog modülü inaktif duruma getirip Syslog modülünü kurarak, sistem olaylarını sunucunuzun işletim sisteminde loglayabilirsiniz.

https://www.drupal.org/docs/8/core/modules/syslog/overview

Drupal – Cache Mekanizması

Drupal, varsayılan olarak Internal Page Cache ve Internal Dynamic Page Cache isimlerinde iki adet cache modülü ile gelmektedir.

Drupal önbelleği, metadata olarak veritabanında ve _cache prefix’ine sahip tablolarda saklanmaktadır. Cache mekanizmasının dışına çıkılarak, önbelleğin manuel olarak temizlenmesi gerektiği durumlarda:

  1. Drupal arayüzünden “Flush All Caches”
  2. Komut satırı arayüzünden “drush cr”

yapılarak önbellek anlık olarak sıfırlanabilir.

Internal Page Cache

Internal Page Cache, sayfaları anonim ziyaretçiler için önbellekte saklar.
Başka bir deyişle, siteyi ziyaret eden kullanıcı, oturum açmamışsa dahi tüm sayfa bilgileri saklanır.

Gelecekteki anonim ziyaretçiler, sayfa sıfırdan oluşturulmadığı için aynı içeriğin son derece hızlı
yüklendiğini göreceklerdir.

* Düzenli olarak güncellenen bir site için kullanılması tavsiye edilmez. Genellikle statik verilere sahip, one-page sitelerde tercih edilmesi uygundur.

Internal Dynamic Page Cache

Oturum açmış ya da açmamış olsun, tüm kullanıcılar için her sayfanın küçük bölümlerini önbelleğe almak
için tasarlanmıştır. Sayfanın her nesnesi meta veriler içerir ve bu meta veri parçası, Internal Dynamic Page Cache modülüne sayfayı önbelleğe alması gerekip gerekmediğini söyler.


Cache API (Önbelleklenebilir Metadata)

Önbelleğe alınabilir meta verileri üç özellikten oluşur:

  1. Cache Tags
  2. Cache Context
  3. Cache Max-Age

Cache Tags

Entities ve configurations gibi Drupal tarafından yönetilen nesnelere olan bağımlılıktır. Başka bir deyişle, önbelleğin hangi nesneye bağımlı olduğunu tanımlar.

Drupal; node’lar, block’lar, yapılandırma (configuration) ayarları, menüler gibi; her türlü önbellek senaryosunu açıklamak için
birden çok cache tag içerir.

Cache Tags, sitedeki bir şey değiştirildiğinde cache girdilerini otomatik olarak geçersiz kılar. Süreye bağlı değildir.
Örneğin; Node:5 cache tag’i, id’si 5 olan içeriğin her değiştirilmesinde kendisine ait önbelleğin geçersiz kılınacağını bildirir.

Cache Context

Context’ler, Tag’lerden oldukça farklıdır. Cache context’leri, cache girdilerinin yanında, içeriğin koşullara göre değişecek şekilde önbelleğe alınmasını sağlar.

Örneğin, birkaç farklı rolde kullanıcılarınız var ve rol için içeriğin farklı şekilde önbelleğe alınması gerekiyor… Bu durumda, Cache Tags tek başına yeterli olmayacaktır. “User Permissions” bağlamına sahip cache context tanımlanmalıdır.

return [
  '#data' => $data,
  '#cache' => [
      'tags' => $tags,
      'context' => ['user']
   ]
];

Cache Max-Age

Önbelleği ne kadar süre ile geçerli kılmak istediğinizi ayarlayabilirsiniz.
max-age: 3600 olarak ayarlarsanız, cache 1 saate kadar geçerli olur. Süre dolduğunda önbellek geçersiz olur.
Bir sonraki kişi sayfayı ziyaret ettiğinde önbellek güncellenerek, yeniden 1 saat süreyle geçerli hale gelir. Hiç önbelleğe almak istemiyorsak max-age: 0 olmalıdır.

Tüm özellikleri (Cache Tags, Cache Context, Cache Max-Age) içeren örnek bir kullanım:

'#cache' => [
   'contexts' => ['languages', 'timezone'],
   'tags' => ['node:5', 'user:3'],
   'max-age' => Cache::PERMANENT,
 ]

REST View Modülünde Önbellek Kullanımı

Drupal REST Views API cache’leri ilk kez oluşturulurken, gelen request parametresi hatalı ise hatalı dönen response önbelleğe alınır.

Caching yöntemi TAG-BASED ise ilgili içerik güncellenene kadar cache invalidate olmaz. (Hatalı ise hatalı olarak kalır.)
Caching yöntemi TIME-BASED ise geçerlilik süresince cache invalidate olmaz. (Hatalı ise süre bitene kadar hatalı olarak kalır.)

Hatalı önbellek durumlarında “Flush All Caches” yapılarak cache rebuild edilmelidir.
Caching yöntemleri, REST Export ekranındaki ADVANCED alanında belirlenmektedir.

Hata Oluşmasının Önüne Geçmek

Gelen isteklerin, request parametrelerinin hatalı olmamasına dikkat edilmelidir.
Hatalı istekler Reports > Recent log messages ekranında filtrelenebilir. Örnek: Illegal choice zh-Hant in locale element. (zh-hant olmalı)
TIME-BASED caching yöntemine geçilerek cache’lerin süreye bağlı olarak invalidate edilmesi tercih edilirse gözden kaçan hatalar kendiliğinden düzeltilebilir.


Drupal Cache ve Memcache Birlikte Kullanımı

Drupal Cache, veritabanında saklanırken; Memcache kullanarak, RAM aracılığı ile daha performanslı bir cache sistemi sunabiliriz. İkisi de farklı katmanlardadır ve birlikte kullanılabilir.

Birlikte kullanım senaryolarında, Drupal cache invalidate ve Memcache lifetime vade süreleri iyi kurgulanmalıdır.

Memcache Kurulumu

  1. Sunucuya Memcache kurulmalıdır.
  2. Memcach contrib modülü CMS’e eklenmeli ve aktif hale getirilmelidir.
  3. settings.php içerisinde memcache konfigürasyonu yapılmalıdır:
$settings['memcache']['servers'] = ['127.0.0.1:11211' => 'default'];
$settings['memcache']['bins'] = ['default' => 'default'];
$settings['memcache']['key_prefix'] = '';
$settings['cache']['default'] = 'cache.backend.memcache';
$settings['cache']['bins']['render'] = 'cache.backend.memcache';

Aynı sunucuda birden fazla CMS varsa her settings.php için key_prefix belirtilmelidir.

Drupal – Log ekleme (Watchdog)

Drupal 8.9.x sürümünde denenmiştir. Kayıtlar, database log olarak watchdog tablosuna kaydedilmektedir. Log kayıtları, CMS arayüzündeki Recent Log Messages ekranından ve watchdog tablosundan görüntülenmektedir.

drush watchdog-show (son 10 mesaj)
drush watchdog-show --count=50 (son 50 mesaj)
\Drupal::logger('log_adi')
                ->notice('New translation has been created<br>
                          Langcode: @langcode <br>
                          Key: @key <br>
                          Value: @value
                         ',
                  [
                    '@langcode' => $langCode,
                    '@key' => $property->key,
                    '@value' => $alternative->value__value
                  ]);

Drupal – Veritabanına Yeni Tablo Ekleme (Hook Update)

Drupal 8.9.x sürümünde denenmiştir. modulname_update_8900 bir kez çalışacaktır. Sonraki kullanımda modulname_update_8901… (+1) olarak güncellemeniz gerekmektedir.

<?php


function modulname_update_8900()
{
  
   $ozellikler = [
    'description' => 'Tabloya ait açıklama',
    'fields' => [
      'alan_1' => [
        'description' => 'alan_1 açıklama',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
        'default' => '',
      ],
      'alan_2' => [
        'description' => 'alan_2 açıklama',
        'type' => 'text',
        'not null' => TRUE,
      ],
    ],
    'primary key' => ['alan_1'],
  ]; 


  \Drupal::database()->schema()
    ->createTable('tablo_adi', $ozellikler);

}

Drupal – Veritabanı Tablosuna Yeni Alan Ekleme (Hook Update)

Drupal 8.9.x sürümünde denenmiştir. modulname_update_8900 bir kez çalışacaktır. Sonraki kullanımda modulname_update_8901… (+1) olarak güncellemeniz gerekmektedir.

<?php


function modulname_update_8900()
{
  $ozellikler = array(
    'type' => 'varchar',
    'description' => "Yeni alana ait açıklama",
    'length' => 20,
    'not null' => FALSE,
  );

  \Drupal::database()->schema()
    ->addField('tablo_adi', 'yeni_alan_adi', $ozellikler);

}

Drush ile Modül Yönetimi

Modüller; core, custom, contrib olarak birbirlerinden ayrılır. Core modüller, drupal içerisinde gelen modüllerdir. Contrib modüller; topluluk tarafından katkıda bulunmak amacıyla yayımlanmış, sisteme dışarıdan dahil edilen modüllerdir. Custom modüller ise kendi geliştirdiğimiz modüllerdir.

pm: package manager

pm:list – Geçerli composer paketlerini (modüller ve temalar) listeler.

drush pm:list  
drush pm:list --help  

pm:enable – Bir veya daha fazla modülü aktif hale getirir.

drush pm:enable content_sync  
drush pm:enable content_sync color_field

pm:uninstall – Bir veya daha fazla modülü kaldırır.

drush pm:uninstall content_sync  
drush pm:uninstall content_sync color_field

pm:security – Composer paketleri için bekleyen güvenlik güncellemelerinin olup olmadığını denetler.

drush pm:security  
drush pm:security --format=json