PHP

You are currently browsing articles tagged PHP.

Web hizmeti genel olarak “ağ üzerinden erişilebilen ve istenen hizmeti sunan makinede çalıştırılan bir API” olarak tanımlanabilir.

Web hizmetlerini kabaca ikiye ayırmak olası:

  1. Simple Object Access Protocol (SOAP) kullanan geleneksel yöntem.
  2. REpresentational State Transfer (REST) kullanan görece yeni yöntem.

RESTful web hizmetlerini başka bir yazıya bırakarak, bu yazıda SOAP kullanarak basit birer web hizmet sunucusu ve istemcisi geliştirmeyi inceleyeceğiz. Yapacağımız iş, sunucuya e-posta adresi gönderip, sunucudan o e-posta adresiyle kayıtlı kullanıcıyı almaktan ibaret.

SOAP bir çok PHP prorgramcısının “öcü” gibi gördüğü bir protokol. Öyle ki, pek çok deneyimli ve gözüpek programcının bile “SOAP” adını duyunca irkildiklerine, hatta iş uygulamaya geldiğinde bazı durumlarda düpedüz “beceremediklerine” çok tanık oldum. Gerçekten de, bazı gereksiz işletim sistemleri üstünde çalışan bazı web hizmetlerinden GNU/Linux – PHP ikilisiyle hizmet almak, WSDL dosyalarını düzgün oluşturmak her zaman o kadar kolay olmayabiliyor.

Ancak tüm bu dertler sizin için bu yazıyı okuduktan sonra geçmişte kalmış olacak, sayın okur!

Öncelikle buradan NuSOAP kütüphanesini indiriyoruz. NuSOAP, bizim için WSDL oluşturma dahil hemen her işi halledecek.

İndirdiğimiz zip dosyasından iki klasör çıkıyor: lib ve samples. Bizim samples’a ihtiyacımız olmayacak, ancak örnekleri incelemenizde fayda var. Basit uygulamamız için webrootumuz altına yeni bir dizin oluşturup (örneğin Ubuntu ile “/var/www/soapTest”) lib’i bu dizine kopyalıyoruz.

/var/www/soapTest dizini altında üç dosya oluşturacağız:

  1. config.php : ayar dosyası
  2. service.php: SOAP sunucusu
  3. client.php: SOAP istemcisi

Ayrıca uygulamamız büsbütün yavan olmasın diye bir de veri çekeceğimiz MySQL veritabanı bağlantımız olacak. Benim veritabanımın adı “yazboz” ve bu veritabanında “users” isimli örnek basit bir tablom var.

Yapı ve tek satırlık kullanıcı verisi şöyle:

1
2
3
4
5
6
7
8
9
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(100) COLLATE utf8_turkish_ci NOT NULL,
`name` varchar(100) COLLATE utf8_turkish_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci AUTO_INCREMENT=2 ;

INSERT INTO `users` (`id`, `email`, `name`) VALUES
(1, 'test@mailinator.com', 'Georges Moustaki');

Yukarıdaki kodu konsol ya da phpMyAdmin marifetiyle veritabanımıza aktardıktan sonra ayar dosyamızı oluşturalım ve “config.php” ismiyle kaydedelim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

class Config
{
    public $wwwroot , $host , $db , $username , $password;
   
    public function __construct()
    {
        //URL
        $this->wwwroot = 'http://localhost/nusoap';
       
        //MySQL sunucusu
        $this->host = 'localhost';
       
        //veritabanı
        $this->db = 'yazboz';
       
        //MySQL kullanıcı adı
        $this->username = 'root';
       
        //MySQL şifresi
        $this->password = 'sifre';
    }
}

Yeni bir dosya daha oluşturalım ve “service.php” adı ile config.php ile aynı dizine kaydedelim.
Sonra, yeni service.php dosyamızda config sınıfını çağırıp veritabanı bağlantısını yapalım:

1
2
3
4
5
6
<?php

require 'config.php';
$config = new Config();

$conn = new mysqli($config->host , $config->username , $config->password , $config->db);

Artık e-posta adresinden kullanıcı adını döndüren fonksiyonu yazabiliriz:

1
2
3
4
5
6
7
8
9
10
11
function getUserNameByEmail($email)
{
    global $conn;
    $userNameQuery = $conn->query("SELECT name
                                FROM users
                                WHERE `email` = '$email' LIMIT 1"
);

    $fetch = $userNameQuery->fetch_array();
    if(!is_array($fetch)) return 'böyle bir kullanıcı yok';
    return $fetch['name'];
}

Gördüğünüz gibi normalden farklı hiç bir şey yapmıyoruz. Sıradaki iş SOAP server’ı içeri alıp ilklendirmek. Bu da çok basit ve sıradan:

1
2
3
4
5
6
7
8
9
require('lib/nusoap.php');

$server = new soap_server();

//aşağıdaki iki satır Türkçe karakter için gerekli
$server->soap_defencoding = 'UTF-8';
$server->decode_utf8 = false;

$server->configureWSDL('testnamespace', 'urn:testnamespace');

Son olarak yukarıda tanımladığımız fonksiyonu sunucuya kaydedip sunucuyu çalıştıracağız:

1
2
3
4
5
6
7
8
9
10
11
//string olarak email gönderip, sonucu yine string döndüreceğiz.
$server->register("getUserNameByEmail",
                array('email' => 'xsd:string'),
                array('return' => 'xsd:string'),
                'urn:testnamespace',
                'urn:testnamespace#getUserNameByEmail');

// aşağıdaki satır $HTTP_RAW_POST_DATA verisi ile aynı işi görür
$postData = file_get_contents("php://input");

$server->service($postData);

Sunucuyu kodlamayı bitirdik bile!
Sunucu kodumuzun tamamı:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php

require 'config.php';
$config = new Config();

$conn = new mysqli($config->host , $config->username , $config->password , $config->db);

function getUserNameByEmail($email)
{
    global $conn;
    $userNameQuery = $conn->query("SELECT name
                                FROM users
                                WHERE `email` = '$email' LIMIT 1"
);

    $fetch = $userNameQuery->fetch_array();
    if(!is_array($fetch)) return 'böyle bir kullanıcı yok';
    return $fetch['name'];
   
}

require('lib/nusoap.php');

$server = new soap_server();

//aşağıdaki iki satır Türkçe karakter için gerekli
$server->soap_defencoding = 'UTF-8';
$server->decode_utf8 = false;

$server->configureWSDL('testnamespace', 'urn:testnamespace');

//string olarak email gönderip, sonucu yine string döndüreceğiz.
$server->register("getUserNameByEmail",
                array('email' => 'xsd:string'),
                array('return' => 'xsd:string'),
                'urn:testnamespace',
                'urn:testnamespace#getUserNameByEmail');

// aşağıdaki satır $HTTP_RAW_POST_DATA verisi ile aynı işi görür
$postData = file_get_contents("php://input");

$server->service($postData);

Hepsi bu kadar. service.php dosyasını çağırdığınızda (örneğimizde http://localhost/nusoap/service.php) sizin için küçük bir belgelendirmeyi bile otomatik olarak oluşturduğunu göreceksiniz.
Kodu http://localhost/nusoap/service.php?wsdl şeklinde çağırdığınızda da WSDL dosyanız hazır!

Tamam, sunucuyu kodlamak gerçekten kolaymış. İstemci kısmı nasıl olacak pekiyi? Çok daha kısa ve basit olacak!
Boş bir dosya daha açalım ve onu da “client.php” ismiyle, aynı dizine kaydedelim. Ardından sunucu için yaptığımız şekilde config dosyasını çağırıp config nesnesini ilklendirelim:

1
2
3
4
ini_set("soap.wsdl_cache_enabled", "0"); //WSDL cache devre dışı kalsın
require_once 'lib/nusoap.php';
require 'config.php';
$config = new Config();

Bundan sonra yapmamız gereken tek şey, SOAP sınıfını ilklendirip, service.php’de tanımladığımız metodu çağırmak:

1
2
3
4
5
6
$soapClient = new SoapClient($config->wwwroot . '/service.php?wsdl' , array(
    "trace"      => 1,
    "exceptions" => 0));

$name = $soapClient->getUserNameByEmail('test@mailinator.com');
echo $name;

Hepsi bu! İstemci kodunun tamamı:

1
2
3
4
5
6
7
8
9
10
11
<?php
ini_set("soap.wsdl_cache_enabled", "0"); //WSDL cache devre dışı kalsın
require_once 'lib/nusoap.php';
require 'config.php';
$config = new Config();
$soapClient = new SoapClient($config->wwwroot . '/service.php?wsdl' , array(
    "trace"      => 1,
    "exceptions" => 0));

$name = $soapClient->getUserNameByEmail('test@mailinator.com');
echo $name;

http://localhost/nusoap/client.php kodunu çağırdığımızda “Georges Moustaki” yazısını görüyorsak işimiz bitmiş demektir.

Böylece NuSOAP kullanarak bir SOAP sunucusu ve bir de SOAP istemcisi yazmış olduk.
Kolay gelsin!

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , ,

VBulletin en çok beğenilen ve kullanılan forum yazılımlarından biri olma özelliğinin yanında, veri madencilerini de oldukça fazla uğraştıran bir forum olmasıyla da biliniyor.

Bu makalede LF’in cURL tabanlı NetClient kütüphanesini kullanarak VBulletin forumlarından veri çekmeyi inceleyeceğiz.

Not1: NetClient kütüphanesinin çalışabilmesi için sisteminizde php-curl eklentisinin kurulu olması gerekir. Çok kullanılan bir eklenti olduğundan genellikle kuruludur.

Not2: Siz kodun içinde görmeyecek olsanız da, cookie kullanacağımız için LF kurulum ana dizinine apache kullanıcısının yazma izni olmalı.

Örneğimizde VB Forumundan bir alt-forum sayfası içeriğini okumayı amaçlıyoruz. Akış diagramımız kabaca aşağıdaki gibi olacak:

  1. VB forumuna kullanıcı adı ve şifre ile giriş yap
  2. VB security token’ı al.
  3. VB sub-forum sayfasını çağır

Önce Controllerımızı oluşturalım, kullanacağımız private değişkenleri deklare edelim. Daha sonra constructor’ımızda NetClient kütüphanesini yükleyelim ve forum kullanıcı adı, şifre ve  sayfa içeriğini edinmek istediğimiz alt-forum ID’sini belirlediğimiz bir ayar metodu yazalım.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Vbulletin extends LogikitController
{
    private $_forum , $_username , $_password , $_loginUrl , $_loginPageContent , $_securityToken , $_subForumId;
   
    public function __construct()
    {
        parent::__construct();
       
        //NetClient kütüphanesini yükle
        $this->load->systemLibrary('NetClient');
       
        //ayarları yükle
        $this->_config();
       
        //VBulletin forumları için login sayfası
        $this->_loginPage = 'login.php?do=login';
    }
   
   
    private function _config()
    {
        $this->_forum = 'http://www.vbforumumuz.org/'; //hedef forum. sondaki bölü işaretini unutmayalım.
        $this->_username = 'kullaniciAdi'; //forum kullanıcı adı
        $this->_password = 'kullaniciSifresi'; // şifre
        $this->_subForumId = 22; //post listesini almak istediğimiz sub-forumun ID'si
    }
   
}

Yukarıdaki kodu application/controller altına Vbulletin.php adıyla kaydedelim.
Ardından, login işlemini gerçekleştirerek loginden sonra yönlendirileceğimiz sayfanın içeriğini alan private metodu yazalım:

1
2
3
4
5
    private function _doLogin()
    {
        $this->_loginPageContent = $this->NetClient->fetchUrl($this->_forum . $this->_loginUrl , "vb_login_username=" . $this->_username . "&vb_login_password=" . $this->_password . "&s=&do=login&vb_login_md5password=" . $passwordMD5 . "&vb_login_md5password_utf=" . $passwordMD5);
        sleep(1);
    }

Şimdi $this->_loginPageContent içinde login işleminden sonra yönlendirildiğimiz ana sayfanın HTML içeriği var.
Dikkatinizi çekmiştir; işlemden sonra bir saniye bekliyoruz. Bunu yapmadığımız zaman Vbulletin sorun çıkarabiliyor.
Artık Vbulletin forumunda yapacağımız tüm işlemler için bize gerekecek olan security token’ı, anasayfa içeriğindeki
var SECURITYTOKEN = “timestamp-md5token”;
biçiminde bulunan javascriptten çekebiliriz. Bunun için regEx kullanacağız. Yeri gelmişken belirtmekte fayda var: regEx bilmeden olmuyor. Ya iyice regEx öğrenin, ya da benim gibi sürekli cheatsheetlerden kopya çekin!

1
2
3
4
5
    private function _getSecurityToken($content)
    {
        preg_match('%(?:var\sSECURITYTOKEN\s\=\s\")(.*?)(\";)%', $content , $result , PREG_OFFSET_CAPTURE , 3);
        $this->_securityToken = $result[1][0];
    }

Böylece ana sayfa HTML kodundan
var SECURITYTOKEN = ”
ile başlayıp
“;
ile biten kısımda bulacağımız security token’ı da elde etmiş olduk.

Kullanacağımız son araç alt-forum sayfasının içeriğini alan metod olacak:

1
2
3
4
5
    private function _getSubForumContent($subForumId , $page = 1)
    {
        $subForumUrl = $this->_forum . "forumdisplay.php?f=$subForumId&order=desc&page=$page";
        return $this->NetClient->fetchUrl($subForumUrl , 'securitytoken=' . $this->_securityToken);
    }

Artık ana metodumuzu yazabilir ve kodumuzu hazır hale getirebiliriz:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    public function scrapeVBCategory()
    {

        //login işlemini yap ve login sayfası içeriğini $this->__loginPageContent stringine at
        $this->_doLogin();
       
        //security token'ı al
        $this->_getSecurityToken($this->_loginPageContent);
       
        //seçtiğimiz alt forumun birinci sayfasını yükle.
        $subForumPage = $this->_getSubForumContent($this->_subForumId);

        echo $subForumPage;

        //template ve view yüklemeden çık.
        exit;
    }

Gördüğünüz gibi oldukça derli-toplu ve gerçekten çok basit. Kodumuzun tamamlanmış hali:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?php

/**
 * Logikit::Framework
 *
 * Open source development framework for PHP 5
 *
 * @package     Logikit Framework
 * @author      Can Ince
 * @copyright           Copyright (c) 2010, Logikit / Can Ince.
 * @license     http://www.opensource.org/licenses/mit-license.php

 * @link        http://framework.logikit.net
 */


class Vbulletin extends LogikitController
{
    private $_forum , $_username , $_password , $_loginUrl , $_loginPageContent , $_securityToken , $_subForumId;
   
    public function __construct()
    {
        parent::__construct();
       
        //NetClient kütüphanesini yükle
        $this->load->systemLibrary('NetClient');
       
        //ayarları yükle
        $this->_config();
       
        //VBulletin forumları için login sayfası
        $this->_loginPage = 'login.php?do=login';
    }
   
   
    private function _config()
    {
        $this->_forum = 'http://www.vbforumumuz.org/'; //hedef forum. sondaki bölü işaretini unutmayalım.
        $this->_username = 'kullaniciAdi'; //forum kullanıcı adı
        $this->_password = 'kullaniciSifresi'; // şifre
        $this->_subForumId = 22; //post listesini almak istediğimiz sub-forumun ID'si
    }

    public function index()
    {
        //scrapeVBCategory metoduna yönlen.
        $this->scrapeVBCategory();
    }
   
    public function scrapeVBCategory()
    {

        //login işlemini yap ve login sayfası içeriğini $this->__loginPageContent stringine at
        $this->_doLogin();
       
        //security token'ı al
        $this->_getSecurityToken($this->_loginPageContent);
       
        //seçtiğimiz alt forumun birinci sayfasını yükle.
        $subForumPage = $this->_getSubForumContent($this->_subForumId);

        echo $subForumPage;

        //template ve view yüklemeden çık.
        exit;
    }
   
    private function _doLogin()
    {
        //ilk parametre URL, ikinci parametre POST verisi
        $this->_loginPageContent = $this->NetClient->fetchUrl($this->_forum . $this->_loginUrl , "vb_login_username=" . $this->_username . "&vb_login_password=" . $this->_password . "&s=&do=login&vb_login_md5password=" . $passwordMD5 . "&vb_login_md5password_utf=" . $passwordMD5);
        sleep(1);
    }
   
    private function _getSecurityToken($content)
    {
        preg_match('%(?:var\sSECURITYTOKEN\s\=\s\")(.*?)(\";)%', $content , $result , PREG_OFFSET_CAPTURE , 3);
        $this->_securityToken = $result[1][0];
    }
   
    private function _getSubForumContent($subForumId , $page = 1)
    {
        $subForumUrl = $this->_forum . "forumdisplay.php?f=$subForumId&order=desc&page=$page";
        return $this->NetClient->fetchUrl($subForumUrl , 'securitytoken=' . $this->_securityToken);
    }
   
}

// END Vbulletin class

/* End of file Vbulletin.php
   Location: ./system/application/controller/Vbulletin.php */

Kodun tamamlanmış hali yorumlar ve boş satırlar hariç 40-45 satır civarında.
NetClient kütüphanesi, bizim için gerekli cURL ayarlarını yaptı. HTTP yönlendirmelerini takip etti, cookie oluşturdu ve bize yalnız “git şu adrese, şunları post et ve gelen veriyi al” demek kaldı.

Veri madencisi arkadaşların işine yaraması dileğiyle.

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , , , , ,

Logikit::Framework yazılarımı LF blogunda yayınlıyorum ancak Türkçe belgelendirmeye de gereksinim duyuluyor. Bu nedenle LF’le ilgili Türkçe makaleleri bu blogda yayınlıyorum.

Bu makalede “Selectbox bileşen seçeneklerini veritabanından gelen veriyle doldurmak” üstüne çalışacağız.
LF ve MVC örüntüsü üstüne deneyimli kişiler için “Özet” bölümü yeterli olmakla birlikte, “yeni ısınan” arkadaşlar için ayrıntılı açıklamaları da bulacaksınız.

Özet:
Aşağıdaki metodu Controller’ımıza ekliyoruz. Çağırılan model, form ve view ile kullanılan veritabanı tablo yapısını “Ayrıntılar” kısmında bulabilirsiniz.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public function mySelectBoxTest()
{
//formu ilklendir
$this-&gt;load-&gt;form('MySelectBoxTestForm');

//modeli ilklendir
$this-&gt;load-&gt;model('TestModel');

//modelden kategorileri id =&gt; name yapısında bir array olarak al
$categoryNames = $this-&gt;UploaderModel-&gt;getCategories();

//formda category ismiyle tanımlanmış selectbox'ın içini veriyle doldur
foreach($categoryNames as $key =&gt; $val)
{
$optArray = array($key =&gt; $val);
$this-&gt;CategorySelectForm-&gt;addOption('category' , $optArray);
}

//id'si 1 olan kategoriyi seçili getir
$this-&gt;CategorySelectForm-&gt;setSelected('category' , '1');

//formu oluştur
$viewData['formItems'] = $this-&gt;MySelectBoxTestForm-&gt;renderAll();

// form verisini view'a geç ve view'u çağır
$viewData = array();
$this-&gt;load-&gt;view('categoryselect' , $viewData);
}

Ayrıntılar:

MySQL kullandığımızı varsayarak veritabanı yapımız:

1
2
3
4
CREATE TABLE `categories` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 100 ) NOT NULL
) ENGINE = MYISAM ;

Controller’ımızın adı “Test” olsun:

1
2
3
4
5
6
7
8
class Test extends LogikitController
{
public function __construct()
{
parent::__construct();
}

}

Yukarıdaki kodu application/controller altına “Test.php” adıyla kaydedelim.

Sırasıyla modelimizi ve formumuzu oluşturalım.

1
2
3
4
5
6
7
class TestModel extends LogikitModel
{
public function __contruct()
{
parent::__contruct();
}
}

Bu modelimiz. Yukarıdaki kodu /application/model altına “TestModel.php” adıyla kaydedelim ve formumuza geçelim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MySelectBoxTestForm extends LogikitForm
{
public function __construct()
{

$this-&gt;addItem(array(
'name' =&gt; 'category' ,
'type' =&gt; 'selectBox' ,
'value' =&gt; NULL ,
'validation' =&gt; array('notNull') ,
'properties' =&gt; ''));

$this-&gt;addItem(array(
'name' =&gt; 'Go' ,
'type' =&gt; 'submit' ,
'value' =&gt; 'Gönder' ,
'validation' =&gt; NULL ,
'properties' =&gt; 'class="submit1"'));
}
}

Böylece bir selectbox ve bir submit butonundan oluşan formumuzu tanımlamış olduk. Yukarıdaki kodu da application/form/Test altında “MySelectBoxTestForm.php” adıyla kaydedelim.
Böylece view hariç, gerekli dosya ve nesnelerin tamamını hazırlamış olduk.

Bir sonraki adımda, controller’ımıza dönelim (application/controllers/Test.php) ve kullanacağımız metodu yazalım:

1
2
3
4
public function mySelectBoxTest()
{

}

Şimdi de yukarıda oluşturduğumuz form ve modelimizi yükleyelim:

1
2
3
4
5
6
public function mySelectBoxTest()
{
$this-&gt;load-&gt;form('MySelectBoxTestForm');

$this-&gt;load-&gt;model('TestModel');
}

Bu andan itibaren form ve model nesneleri ile bu nesnelere bağlı metodlar, controller’ımız içinden $this->TestModel->method() ve $this->MySelectBoxTestForm->method() şeklinde çağırılabilir durumda.

Modelimize (application/model/TestModel.php) geri dönelim ve selectbox’ımızı doldurmak için gerekli veriyi array olarak veritabanından çeken metodu yazalım:

1
2
3
4
public function getCategories()
{
return $this-&gt;result("SELECT id , name FROM categories");
}

Controller’ımızdaki mySelectBoxTest() metoduna dönelim ve selectbox’ı veriyle dolduran kodu ekleyelim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public function mySelectBoxTest()
{
$this-&gt;load-&gt;form('MySelectBoxTestForm');

$this-&gt;load-&gt;model('TestModel');

$categoryNames = $this-&gt;UploaderModel-&gt;getCategories();
foreach($categoryNames as $key =&gt; $val)
{
$optArray = array($key =&gt; $val);
$this-&gt;CategorySelectForm-&gt;addOption('category' , $optArray);
}

//id'si 1 olan kategoriyi seçili getir
$this-&gt;CategorySelectForm-&gt;setSelected('category' , '1');
}

Contoller’daki son işimiz, form verisini view’a aktarmak olacak ve bu işlemden sonra controller’ın son hali aşağıdaki gibi olmalı:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function mySelectBoxTest()
{
$this-&gt;load-&gt;form('MySelectBoxTestForm');

$this-&gt;load-&gt;model('TestModel');

$categoryNames = $this-&gt;UploaderModel-&gt;getCategories();
foreach($categoryNames as $key =&gt; $val)
{
$optArray = array($key =&gt; $val);
$this-&gt;CategorySelectForm-&gt;addOption('category' , $optArray);
}

//id'si 1 olan kategoriyi seçili getir
$this-&gt;CategorySelectForm-&gt;setSelected('category' , '1');

//formu oluştur
$viewData['formItems'] = $this-&gt;MySelectBoxTestForm-&gt;renderAll();

// form verisini view'a geç ve view'u çağır
$viewData = array();
$this-&gt;load-&gt;view('categories' , $viewData);
}

ve son olarak view dosyasını oluşturarak işimizi bitirelim:

1
2
3
4
5
6
<div id="formDiv" style="display: none;">echo formOpenMultipart('form1' , siteUri(getController() . '/formIslemeMetodu') , 'POST', 'onsubmit="return false;"');
echo $secondFormItems['category'] . "
"
;
echo $secondFormItems['Go'] . "
"
;
formClose();</div>

Bu dosyayı da application/view/categories.php adıyla kaydedince işimiz bitmiş oluyor.

Artık kodu çalıştırabiliriz:

http://www.testsunucunuz.com/LFDizini/Test/mySelectBoxTest

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , , ,

PostgreSQL ile bir gece

Bir kaç ay önce, ailedeki yazılımcı sayısının artmasıyla “Artık şirketi kuralım!” dedik ve Logikit‘i kurduk. Kendimizi tanıtmakla geçen, programcı olarak bana boş vakit tanıyan sürede de Logikit::Framework‘ü (LF) kodladım ve bir kaç ay boyunca LF üstünde küçük ve orta ölçekli bir kaç proje geliştirerek frameworkü geliştirme ve olgunlaştırma olanağı da buldum. Buraya kadar iyi…

Bu ay (Mart 2010) başlarında oldukça büyük ölçekli bir projeye başladım. Usecase’ler yazılıp çizilip tartışıldı, entity relationship diagramlar yapıldı, veritabanı mimarisi oturdu. Projede veritabanı performansı çok önemli ve PostgreSQL kullanıyoruz.

LF’i kodlarken “database abstraction’ı da aradan çıkarıverelim!” diye uyanıklık edip PDO kullandım. Bir sürü RDMBS için sürücüsü var ya, rahatım!

LF’te model için yazdığım abstract class PDO’dan türüyor ve kullanıcı modelleri de bu abstract class’tan. Basit bir active record uygulaması. Kullanıcı (LF kullanan programcı) controller’ında record set için bir array oluşturuyor, bu array’i bizim modele veriyor ve model de duruma göre (“id” alanı varsa) INSERT ya da (“id” alanı yoksa) UPDATE sorgusu oluşturuyor. Tablo adını biliyoruz ama tablo alan adlarını bilmiyoruz.

Daha önce LF üstünde geliştirdiğim projelerin hepsi MySQL kullanıyordu ve benim aklıma da “yazdığım kod başka RDMBS üstünde çalışır mı, çalışmaz mı, çatlar-patlar mı?” soruları gelmedi. “En fazla bir-iki yeri düzeltmek gerekir.” dedim ve geçip gittim.

Projenin planlama aşaması bitip, PostgreSQL tablolar oluşturulup ilk controllerı yazmaya sıra geldiğinde gidip ayarlarımdan sürücüyü (büyük bir güvenle!) “mysql”den “pgsql”e değiştirdim ve safça çalışmasını umuyorum! Çalışmadı tabii…

Bir-iki yeri basitçe fiksledim; her şey normal görünüyor. Array doğru geliyor, tablo adı doğru, velhasıl her şey doğru.
Debug sürecinde daralta daralta çalışmayan yeri buldum: Tablodaki alan adları düzgün gelmiyordu!

MySQL ile kullandığım model asbtract’ında ilgili metod şöyleydi:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Return list of columns
*
* @access   public
* @param        string  tableName
* @return   array
*/


public function columns($tableName)
{
$tableName = strtolower($tableName);

$arrFields = array();
$colQuery = $this-&gt;query("SHOW COLUMNS FROM $tableName");
while($col = $colQuery-&gt;fetch_array())
{
$arrFields[$col['Field']] = $col;
}

return $arrFields;
}

Şöyle bir durup kafamı kaşıdım: On yıldır yaşamımı yazılımcı olarak kazandığımı anımsadım.
Buna rağmen en son iki yıl kadar önce PostgreSQL ile bir proje geliştirmiştim ve hiç bir durumda tablo alan adlarını öğrenmeye ihtiyaç duymamıştım; zaten o adları hep ben vermiştim!
Doğal olarak LIMIT 1 ile bir sorgu yapıp bu adları öğrenebilirdim ancak hem performanstan yemek gibi bir lüksüm yoktu, hem de bu tür işi kendime yakıştıramadım. Tamam, PostgreSQL uzmanı olmadığımı biliyordum ancak PostgreSQL kullanarak en az 10-12 proje geliştirmiş bir kişi evladı olarak büsbütün cahil olduğumu da ummuyordum.
Biraz deştikten sonra, hayret verici şekilde, aşağıdaki kodun LIMIT 1 sorgusuna göre daha verimli olduğunu gördüm:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Return list of columns
*
* @access   public
* @param        string  tableName
* @return   array
*/


public function columns($tableName)
{
$tableName = strtolower($tableName);

$arrFields = array();

foreach($this-&gt;query("SELECT
a.attname as \"Column\",
pg_catalog.format_type(a.atttypid, a.atttypmod) as \"Datatype\"
FROM
pg_catalog.pg_attribute a
WHERE
a.attnum &gt; 0
AND NOT a.attisdropped
AND a.attrelid = (
SELECT c.oid
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname ~ '^($tableName)$'
AND pg_catalog.pg_table_is_visible(c.oid)
)
;"
) as $col)

{
$arrFields[] = $col[0];
}

return $arrFields;
}

Bu durumda görünen o ki, LF’ün yeni sürümünde en az iki ayrı abstract model olacak.
Başıma yine gelirse anımsamak için bir not…

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , , , ,

Newer entries »