ile

Hiç Bilmeyenler İçin Nesne Yönelimli Programlamaya Giriş-8 Web Arayüzü

Bu yazı Hiç Bilmeyenler İçin Nesne Yönelimli Programlamaya Giriş-7 — Sınıfları Kullanmak ve API meselesi yazısının devamıdır. Önce onu okumanızı öneririm.

View story at Medium.com

Bir önceki yazıda, API kavramını, kullanıcının uygulamaya hangi adresleri kullanarak erişebileceğini, bu adreslerin nasıl çalışacağını, yönlendirme kavramını ve arayüz mantığını anlatmıştım. Bu yazıda kullanıcının ilk olarak karşılacağı arayüzleri nasıl oluşturacağımızı, nasıl tasarlayacağımızı ve kullanacağımızı anlatacağım. Daha önce Projelerle PHP 7 adlı kitabımda HTML konusunu anlattığım için, html sayfaları yazmak konusunda detaya inmeyeceğim. Eğer konu ile ilgili eksiğiniz varsa benim kitabımdan veya internetteki kaynaklardan eksiğinizi giderebilirsiniz.

Web uygulamamızda, kullanıcıya bilgileri bir HTML sayfası aracılığı ile gösterecek, ondan bilgileri bir HTML formu aracılığı ile alacak ve işleyeceğiz. Ayrıca kullanıcıdan gelecek bilgilere neden güvenmememiz gerektiğini, kötü niyetli bir kullanıcının sistemimize ve programdaki diğer kullanıcılara nasıl zarar verebileceğini göreceğiz. Ayrıca bu yazıda ilk defa uygulamamızda veriyi nasıl kaydedeceğimize kısaca giriş yapacağız.

Kısaca programımızda 3 ekran olacak. Birinde hali hazırda yarattığımız sözlükleri ve başlık sayılarını görüntüleyeceğiz. İkincisinde, sözlüğü ve içindeki başlıkların listesini görecek, üçüncüsünde de bir başlığa tıkladığımızda açıklamaları göreceğiz.



Kısaca ekranlarımız

Ekranların kötü göründüğüne bakmayın. Sonuçta bize yol gösterecek olan prototipler yani tasarımlar. Siz de benzer tasarımları Mockup Designer ile yapabilirsiniz.

Genel olarak mobil ve web uygulamalarında tasarımlar aynı oluyor. Biz yine kısaca tasarımları içerdikleri elemanlara göre inceleyelim.

  1. Kaydettiğimiz verileri eklemize ve düzenlememize yarayan bir form bileşeni.
  2. Kaydettiğimiz verileri listelememize yarayan bir liste bileşeni.
  3. Kaydettiğimiz veriyi tek olarak görüntülememize yarayan bir diğer bileşen.

Biz bu bileşenleri şimdilik program kodu olmadan kullanıcının göreceği şekilde kodlayalım. Daha sonra bu düz HTML kodlarını bileşenlerine ayıracağız ve aynı kodları tekrar etmemize gerek kalmayacak.

Şimdi proje dizinimizde public adlı bir klasör oluşturalım. Genellikle bu public klasörlerinde js css ve img dizinleri bulunur. public klasörünün altında css adlı bir dizin oluşturalım ve içine şu adresteki kodu universal.css olarak kaydedelim.

Daha sonra public dizinine geri dönelim. index.html isminde bir dosya oluşturalım. İçine şu kodları ekleyelim:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sözlük Uygulaması</title>
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<link rel="stylesheet" href="css/universal.css">
</head>
<body>
<header>
<h1>Sözlük Uygulaması</h1>
<nav>
<ul class="list horizontal">
<li><a href="#">Hakkında</a></li>
<li><a href="#">Şartlar</a></li>
<li><a href="#">Gizlilik</a></li>
</ul>
</nav>
</header>
<main>
<aside>
<nav>
<ul class="list vertical">
<li><a href="#">Sözlüklerim</a></li>
</ul>
</nav>
</aside>
<section>
<h2>Sözlüklerim</h2>
<form>
<label for="title">Yeni Sözlük</label>
<input type="text" id="title" name="title" placeholder="Başlık">

<input type="submit" value="Yeni Sözlük Ekle">
</form>
<table>
<thead>
<th>id</th>
<th>Başlık</th>
<th>Girdi Sayısı</th>
<th>Düzenleme</th>
</thead>
<tbody>
<tr>
<td>14</td>
<td>Nesne Yönelimli Programlama Sözlüğü</td>
<td>24</td>
<td><a href="#">Düzenle </a>&nbsp;<a href="#">Sil </a></td>
</tr>
<tr>
<td>48</td>
<td>Bilişim Terimleri Sözlüğü</td>
<td>12</td>
<td><a href="#">Düzenle </a>&nbsp;<a href="#">Sil </a></td>
</tr>
<tr>
<td>41</td>
<td>Tıp Sözlüğü</td>
<td>250</td>
<td><a href="#">Düzenle </a>&nbsp;<a href="#">Sil </a></td>
</tr>
</tbody>
</table>
</section>
</main>
<footer>
<p>
Sözlük Uygulaması - Copyright - Midori Kocak - 2017
</p>
</footer>
<script src="js/main.js"></script>
</body>
</html>

Merak etmeyin bu HTML kodların tek tek uygulamamızla nasıl entegre olacağından bahsedeceğim.

web sunucumucdan index.html’yi çağırdığımızda şöyle bir görüntüyle karşılaşmamız gerekiyor:

Uygulama arayüzü

Genellikle bütün uygulama arayüzleri bu yapıyı kullanırlar. O yüzden başka bir uygulama yazarken siz de bu arayüz mantığını kullanabilirsiniz. Bunu tek tek örnekleriyle anlatacağım.Şimdi bu arayüzde hangi bileşen ne iş yapar onu görelim.

Header yani Üstbilgi

Üstteki siyah kısım. Kod bloğu içinde de header etiketi içinde yer alıyor. Uygulamalarda bu kısım, her sayfada aynı olan, sayfa değiştiğinde değişmeyen, logo, ana sayfa, hakkında, gizlilik vb. gibi linkleri, eğer kullanıcı yönetiyorsak, kullanıcı adını ve kendiyle ilgili işlemleri (login/logout gibi) yapmasını yarayan bir açılır menüyü, arama yapılabiliyorsa, arama formunu içerir.

Mesela, facebook, twitter ve linkedin uygulamalarında bu bölümler nasıl tasarlanmış bir göz atalım:

Twitter Üstbilgi:

Twitter Header

facebook Üstbilgi:

Facebook Header

Linkedin Üstbilgi:

Linkedin Header

Gördüğünüz gibi uygulamada header yapıları küçük değişikliklere rağmen aynı.

Aside yani Yanbilgi

Genel olarak, uygulamamızı kullanırken isteğe bağlı olarak ihtiyaç duyacağımız bilgileri içeren kısmı temsil eder. Bizim kodumuzda aside etiketiyle tanımlanmıştır.

Index.php dosyasını açtığımızda, sol tarafta bulunan üstüste linklerle oluşturduğumuz kısım. Burası genellikle uygulama içindeki farklı modüllere ilerlememizi sağlayan linkleri içerir. Biz uygulamamızda sadece sözlük tuttuğumuz için, Sözlüklerim adlı bir link var. Buradaki link sayesinde, programın herhangi bir yerinde istediğimiz zaman Modülün ana sayfasına dönüş yapabileceğiz. Sözlüklerim için, bütün sözlüklerimi listelediğim sayfa. Örneğin facebook’ta burada, Gruplar, Sayfalar, Etkinlikler gibi linkler bulunur. Görelim:

facebook Yanbilgi:

facebook aside

Twitter Yanbilgi:

Twitter Aside

Linkedin Yanbilgi:


Mesela linkedin ve twitter örneklerine baktığımızda, kendi profiliml ilgili bilgileri ve istatistikleri görmemi sağlayan bir profil bileşeni konmuş. Facebook örneğinde sadece kullanıcı adı ve kullanıcı resmi içeren minik bir link konmuş.

Main yani Asıl işi yaptığımız kısım

Bu kısım kaydettiğimiz varlığın, yani video, tweet, paylaşım gibi bilgilerin sırayla listelendiği kısım olacak. Bazen kullanıcı uygulamayı açtığında, dashboard yani gösterge paneli veya kontrol paneli dediğimiz, grafiklerle uygulama istatistiklerini gösteren bir kısımla da karşılaşabiliyor.

Gösterge Paneli

Ancak bizim şu an incelediğimiz, twitter, linkedin ve facebook örneklerinde sayfayı açtığımızda, uygulamamızda yönettiğimiz asıl varlığı eklememize yarayan minik bir form ve akış yani feed dediğimiz iki modül main yani ana ekranda bulunuyor. Örnekleri görelim:

Twitter:

Twitter Akış

Facebook:

Facebook Akış

Linkedin:

Linkedin Akış

Gördüğümüz gibi üç örnekte de, minik bir form ve varlıkları tek tek listeleyen akış dediğimiz bir kısım var.

Akış yani feedlerde lazy loading, yani tembel yükleme dediğimiz mantık işliyor. Yani binlerce, milyonlarca paylaşımı veya tweet’i bir anda göstermek yerine, örneğin ilk 10 tanesi yükleniyor, ve kullanıcı sayfayı aşağı kaydırdığında bir 10 tanesi daha yükleniyor. Başka bir yöntem de pagination ya da sayfalama.

Sayfalama

Sayfalama sayesinde takip ettiğimiz verilerin tamamını sayfaya indirip görüntülemek yerine, ilk 10 tanesini ilk sayfada görüntüleyecek ve kullanıcı eğer isterse sonraki sayfalara tıklayarak kalan varlıkları görüntüleyecek. Biz henüz javascript kısmına gelmediğimiz için uygulamamızda bu yöntemi kullanacağız.

PHP’de Görünümler yani View’lar

Yukarıda paylaştığım HTML örneği, son kullanıcının uygulamamızı açtığında, tarayıcısına gidecek olan HTML kodudur. Şimdi, kullanıcının bu kodu nasıl elde edeceğine, server yani sunucu tarafında bizim karar vermemiz gerekiyor. PHP’de bunu yapmanın birden fazla yolu var.

  1. Düz PHP dosyasında, PHP ve HTML kodlarını karıştırmak.
  2. Tema olarak kullanacağımız PHP dosyaları oluşturmak ve yine PHP ve HTML kodlarını karıştırmak.
  3. Nesne yönelimli olarak bir View yani Görünüm sınıfı oluşturmak ve bu sınıfı kullanmak. Hatta kullanıcıya göstereceğimiz form, liste gibi modüller için de ayrı sınıflar oluşturmak.

Bu konu aslında “separation of concerns” yani tam çevirmek gerekirse “ilgilerin birbirinden ayrılması” konusuna giriyor ve MVC yani model-view-controller kısmını anlattığımda detaylıca bahsedeceğim kısımla alakalı ancak, şimdilik o bölüme girmeden nesne yönelimli olarak kullanıcının görüntüleyeceği HTML kodunu yönetmenin dışına çıkmayacağız. Biz bu yazı serisinde Nesne Yönelimli Programlama ile ilgili olduğumuzdan, 3. yöntemle yani View sınıfları kullanarak bi işi halledeceğiz.

Piyasada örneğin Plates, Aura veya Blade gibi anlattığımız işleri gerçekleştiren kütüphaneler mevcut, ancak biz bu seride konuları temelinden aldığımız kendi sınıflarımızı kendimiz yazacağız. Daha sonra, profesyonel işlerimizde tabii ki, vakit kazanmak adına piyasadaki hazır kütüphane ve frameworkleri (uygulama çerçevelerini) kullanabiliriz. (Framework konusunu da serinin sonunda detaylıca anlatacağım.) Ancak şimdilik herşeyi kendimiz yapacağız ki, konuyu detayıyla kavrayabilelim.

Daha önce sınıflarımızın, bağımsız, kendi başına çalışabilen bir uygulama gibi olmaları gerektiğini, belli bir amaca ve tek bir sorumluluğa sahip olması gerektiğinden bahsetmiştik. Şimdi bu düşünceyi aklımızda tutarak View yani Görünüm sınıfımızı tasarlamaya başlayalım. Önce görünüm sınıfımızın ne yapması gerektiğine karar verelim ve son kullanıcının onu nasıl kullacağını gösterecek arayüzü oluşturalım. Peki View yani Görünüm sınıfımızın yapması gerekenler neler?

  1. Verdiğimiz veriyi, doğru dürüst bir şekilde, doğru biçim ile kullanıcıya sunmak.
  2. Gerekirse, aynı veriyi, başka biçimlerle kullanıcıya sunmak. (Örneğin JSON ya da desktop uygulamasının GUI yani grafik kullanıcı arayüzüne uyumlu olacak biçimde) (JSON konusunu daha sonra detaylı olarak anlatacağım.)
  3. Kullanıcının yaptığı işlemleri tespit edip ona göre kullanıcıyı yönlendirmek. Yani kullanıcı, programımızın diğer kısımları ile muhattap olmak yerine, sadece Görünüm yani View sınıfı ile muhattap olmalı.
  4. İstediğimizde aynı veriyi web üzerinde ya da terminal ekranında görüntülemek için aynı arayüzü kullanan farklı View sınıfları kullanabiliriz.
  5. Görünüm sınıfımızın veriyi sarmalamak için kullanacağı bir Template’si yani şablonu olmalı.

View yani Görünüm sınıfını daha da karmaşıklaştırabiliriz ancak şimdilik en basit özellik ve metodları düşünerek işe başlayalım. Entry yani Girdi sınıfımız için program dizinimiz içinde EntryView.php adında bir dosya oluşturalım ve içine şu kodları ekleyelim:

<?php

namespace
MidoriKocak;

class EntryView
{
private $entry;

public function __construct(EntryInterface $entry = null)
{
if ($entry !== null) {
$this->entry = $entry;
}
}

public function setEntry(EntryInterface $entry)
{
$this->entry = $entry;
}

public function render()
{
if (!isset($this->entry)) {
throw new Exception('Cannot render without entry');
}

$title = "<h3>" . $this->entry->getKey() . "</h3>";
$values = $this->entry->getValues();
$list = "";
foreach ($values as $value) {
$list .= "<li>" . $value . "</li>";
}

$result = "<p class='entry'>" . $title . "<ol class='values'>" . $list . "</ol>" . "</p>";

return $result;
}
}

Şu duruma dikkat edelim: EntryView sınıfımız, EntryInterface yani Girdi Arayüzü ile muhattap oluyor, ve Girdi sınıfını bu arayüze göre kullanıyor. Constructor yani sihirli yaratma metodumuzda paramtere EntryInterface $entry = null ifadesini kullandık. Buradaki = null ifadesi, $entry değişkeninin opsiyonel olduğunu belirtir. Yani istersek boş bir entry sınıfı oluşturabiliriz ve setEntry metodu ile istediğimiz girdiyi bu view yani görünüm sınıfı içerisine data yani veri olarak yerleştirebiliriz. Bu sayede her girdi için yeni bir görünüm sınıfı yaratmamıza gerek kalmaz.

Render yani sunum metodumuzda, constructor yani sihirli yaratma metodunda, $entry değişkenini opsiyonel olarak tanımladığımız için, hatalara karşı sınıf içindeki $this->entry değişkeninde tanımlı olan girdi verisini kontrol ettik ki, herhangi bir kişi, setEntry demeden veya constructor içinde girdiyi tanımlamadan render yani sunum metodunu çalıştırıp hataya yol açmasın. if (!isset($this->entry)) bloğu içinde bu kontrolü yapıyoruz.

Daha sonra, girdi sınıfından başlık ve değerler gibi verileri çekip, html kodu içinde sarmalıyoruz. Görünüm için başka bir sınıf oluşturup, asıl nesnenin verilerini bu şekilde sarıp sarmalamaya Decorator yani Dekoratör tasarım deseni deniyor. Tasarım desenleri kısmına geldiğimizde bu konuyu daha detaylıca anlatacağım.

Aslında PHP kodları içinde html etiketlerini karıştırıp kullanmayı sevmem. Bana spagetti kodu hatırlatıyor. Şimdilik kolay olması amacıyla bu şekilde anlatıyorum. Ancak daha sonra bir şablon dizini oluşturup, veriyi sarmalayacağımız HTML kodlarını ayrı ayrı php şablon dosyalarında tutacağız. View sınıfımız tema dosyasını açıp, sunumu o şekilde yapacak.

Şimdi Dictionary.php dosyası içinde yapmamız gereken küçük bir değişiklik var. Dictionary.php içindeki getEntries metodu bize metin dizisi döndürüyordu. Bunun yerinde EntryView sınıfını kullanacağımız için entry yani girdi dizisine ihtiyacımız var. Dosyadaki getEntries metodunun adını getEntriesAsArray olarak değiştirelim ve yeni yazacağımız getEntries metodunda doğrudan $this->entries içinde tanımlı olan girdi nesnelerinin dizisini döndürelim.

<?php

namespace
MidoriKocak;

class Dictionary implements DictionaryInterface
{
private $title;
private $entries;

public function __construct(string $title)
{
$this->setTitle($title);
$this->entries = [];
}

public function setTitle(string $title)
{
if (($title != "") && (strlen($title) <= 70)) {
$this->title = $title;
} else {
throw new InvalidArgumentException('Wrong title value.');
}
}

public function getTitle(): string
{
return $this->title;
}

public function getEntriesAsArray(): array
{
$entries = [];
/* @var $entry EntryInterface */
foreach ($this->entries as $entry) {
$entries[$entry->getKey()] = $entry->getValues();
}
return $entries;
}

public function getEntries(): array
{
return $this->entries;
}

Bu sayede app.php kodu içinde girdi nesnelerinin dizisine dışarıdan erişebileceğiz. app.php dosyamızı şu şekilde değiştirelim:

<?php

require_once 'DictionaryInterface.php'
;
require_once 'Dictionary.php';
require_once 'EntryInterface.php';
require_once 'Entry.php';
require_once 'EntryView.php';

try {
$dictionary = new MidoriKocakDictionary("Nesne Yönelimli Programlama Sözlüğü");

$nesne = new MidoriKocakEntry('nesne', 'aklımızın dışındaki herşey');

$nesne->addValue('harika bişi');
$nesne->addValue('ingilizce object');

$şey = new MidoriKocakEntry('şey', 'ismi olmayan nesne');

$dictionary->addEntry($nesne);
$dictionary->addEntry($şey);

$entries = $dictionary->getEntries();

foreach ($entries as $entry) {
$entryView = new MidoriKocakEntryView($entry);
echo $entryView->render();
}

} catch (Exception $e) {
echo 'Error on line ' . $e->getLine() . ' in ' . $e->getFile()
. ': <b>' . $e->getMessage();
}

Yeni oluşturduğumuz EntryView dosyasını “require_once ‘EntryView.php’;” ifadesiyle dosyamıza ekledik.

Yaptığımız tek değişiklik, printr($entries) ifadesinin yerine şu kodları yazmak oldu:

foreach ($entries as $entry) {
$entryView = new MidoriKocakEntryView($entry);
echo $entryView->render();
}

foreach ifadesi ile $entries değişkeni içindeki her bir girdi nesnesine eriştik, ve her biri için yeni bir EntryView yani Girdi Görünümü sınıfı (ya da dekoratörü) yarattık. Şimdi web sunucumuzdan app.php’yi açtığımızda şöyle bir görüntünün karşımıza gelmesi gerekiyor:

HTML oluşturan sınıf

Şimdi biraz daha HTML sayfasına benzemeye başladı. Sayfa kaynağına baktığımızda şu kodları görmeliyiz:

Sayfa Kaynağı

Gördüğümüz gibi, sınıfımız ham veriyi aldı ve bizim istediğimiz şekilde HTML kodlarının içine sardı. Şimdilik uygulamamız düzgün bir web sayfası gibi görünmemekle beraber, View yani görünüm sınıflarının ne işe yaradığını, dekoratör tasarım deseninin mantığını ve Ham verinin nasıl süsleneceğini iyice anladık. Bir sonraki yazıda sözlük için görünüm sınıfını oluşturacağız ve ufaktan sayfa şablonlarımızı yazmaya başlayacağız.

Bir sonraki yazıya şuradan ulaşabilirsiniz:

View story at Medium.com


Projelerle PHP 7

Ben Mutlu Koçak, Bilgisayar Mühendisiyim, ZCPE Sertifikasına sahibim ve “Hiç Bilmeyenler İçin İnternet Programlamaya Giriş — PHP 7” adlı kitabın yazarıyım. Kitabım: https://www.seckin.com.tr/kitap/911934237
Özgeçmişim:
http://represent.io/mtkocak.pdf 
Websitem:
http://mynameismidori.com

Yorumla

Yorum