Tag Archives: PHP

Programa Dilleri ve Çatıları

YII ile Basit Veritabanı İşlemleri

Aslında pek üstüne blog yazısı yazmaya deyecek bir konu olduğu söylenemez. :) Hem dağılan kafamızı biraz toparlayalım, hem de konuyu arayan birilerine Türkçe kaynak olsun. Hadi bakalım…

***

YII çatısı altında veritabanı uygulamaları geliştirirken dilerseniz DAO (Data Access Object), dilerseniz ORM (Object Relation Mapping) kullanarak veritabanına erişebilirsiniz.

1. DAO (Data Access Object) Kullanarak Veritabanı İşlemleri Gerçekleştirmek :

1. 1. Veritabanı Bağlantısı Oluşturmak

YII ile veritabanı bağlantısını isterseniz dilediğiniz herhangibir anda başlatıp sonlandırabilir veya doğrudan aplikasyon başladığı anda veritabanı bağlantısını başlatabilirsiniz. DAO nesnesi PDO dan türediği için sunucunuz tarafından desteklenen tüm PDO sürücülerini kullanabilir.

Aşağıdaki örnekte anlık veritabanı bağlantısının nasıl başlatılıp sonlandırıldığını görüyoruz.

$dsn = 'mysql:host=localhost;dbname=testdb';
$username = 'myuser';
$password = 'mypass';
$connection=new CDbConnection($dsn,$username,$password);
$connection->active=true; // veritabani baglantisini aciyoruz...
......
$connection->active=false;  // veritabani baglantisini kapatiyoruz...

Veritabanı bağlantısını uygulama ayağa kalktığında başlatmak için ise veritabanı erişim bilgilerini konfigürasyona yazmanız yeterli.
protected/config/main.php:

array(
    ......
    'components'=>array(
        ......
        'db'=>array(
            'class'=>'CDbConnection',
            'connectionString'=>'mysql:host=localhost;dbname=testdb',
            'username'=>'myusername',
            'password'=>'mypassword',
            'emulatePrepare'=>true,  // YII nin sitesinde bazi SQL sorgulari icin gerekli oldugundan bahsediyor. Muhtemelen parametre iceren SQL sorgularinin dogrudan calistirilmamasi icin kullanilmasi gereken bir parametre.
        ),
    ),
)

Veritabanı bağlantısını ugulama ayağa kalktığında başlattığınızda connection nesnesine aşağıdaki şekilde ulaşabilirsiniz:

$connection = Yii::app()->db;

1. 2. SQL sorgusu çalıştırmak

SQL sorguları, veritabanı bağlantısı üzerinden bir fabrika metodu ile command nesnesinin yaratılıp bu nesnenin execute() edilmesi suretiyle gerçekleştirilir. Aslında bu kullanım şekli, PDOşinas olan arkadaşlarımıza son derece tanıdık gelecektir.

Adi bir select sorgusunu aşağıdaki şekilde çaılştırabilirsiniz.

/* @var $connection CDbConnection */
$connection = Yii::app()->db;
$sqlQuery = 'SELECT `id`, `name`, `amount` FROM `mytable` WHERE `id`=23';
/* @var $command CDbCommand */
$command = $connection->createCommand($sqlQuery);
/* @var $reader CDbDataReader */
$reader = $command->query();
foreach($reader as $row) {
 ...
}

YII, bize bir veritabanı sorgusunu çalıştırabilmemiz için aşağıdaki metodları sunar.

$rowCount=$command->execute();
/*
Bu kullanim, genellikle sonuc beklentisi olmayan 
INSERT, UPDATE, DELETE sorgulari icindir. Calitirildiginda 
sorgu sonucunda etkilenen satir sayisini doner.
*/

$dataReader=$command->query();   
/*
Bu kullanım şeklinde sonuc traversable bir obje olan 
CDbDataReader tipinde döner. Sorgu sonuclari döngü 
ile fetch edilir.
*/

$rows=$command->queryAll();
/*
Bu kullanim seklinde sorgu once calistirilir sonra tum 
sonuclar fetch edilir.
*/

$row=$command->queryRow();
/*
Bu kullanim seklinde sorgu once calistirilir sonra 
sonuca ait ilk satir fetch edilir.
*/

$column=$command->queryColumn(); 
/*
Bu kullanım şeklinde sorgu calistirilir ve sonucun ilk kolonu doner.
*/

$value=$command->queryScalar();  
/*
Bu kullanim sekli sorguyu calistirir ve ilk satirin ilk kolonunu doner.
*/

1. 3. Sorgu sonuçlarının fetch edilmesi

CDbCommand::query() metodu çağırıldığında CDbDataReader tipinde bir örnek üretilir. Sorgu sonuçlarını almak istediğinizde ise döngü içerisinde CDbDataReader::read() metodu tekrarlı olarak çağırılır.

$reader = $command->query();
while($row = $reader->read() ) {...}
foreach($reader as $row) {...}
//Bu kullanim sekli sorgu sonucundaki tum satirlari alir.
$rows = $reader->readAll();

1. 4. Transaction Kullanımı

Üstüne söylenecek çok fazla birşey yok. Sorguları çalıştırmaya başlamadan önce transaction ı başlatır sorguları çalıştırdıktan sonra commit edersiniz. Buyrun kod örneği :

$queries = array();
$queries[] = 'INSERT INTO `mytable` (`id`, `name`, `amount`) VALUES(1, 'zeynep', 100);';
$queries[] = 'INSERT INTO `mytable` (`id`, `name`, `amount`) VALUES(2, 'ayşe', 250);';
$queries[] = 'INSERT INTO `mytable` (`id`, `name`, `amount`) VALUES(3, 'elif', 115);';

$success = true;
$transaction = $connection->beginTransaction();
foreach($queries as $sqlQuery) {
    try {
        $connection->createCommand($sqlQuery)->execute();
    } catch(Exception $e) {
        $transaction->rollback();
        $success = false;
    }
}

if( $success ) {
    $transaction->commit();
}

Bir sonraki yazıda YII ‘nin basit, şirin ORM kütüphanesi ActiveRecord u inceleyeceğiz.
Sevgi, selam ötesi hürmet..

Programa Dilleri ve Çatıları

Hadise var dediler, geldik!

HadiseHadise, çok ilkel (basit) bir olay güdümlü programlama kütüphanesidir. Mevcut PHP aplikasyonunuza basitce implemente ederek yazılımınızın akışını tetiklediğiniz olaylar doğrultusunda yönetebilirsiniz.

Hadise kütüphanesinin en güncel sürümünü aşağıdaki github reposunda bulabilirsiniz:
https://github.com/ibrahimgunduz34/hadise

Örneğin projenizin içindeki basit bir api implementasyonuna hadise kütüphanesini uyarlayalım.

Öncelikle olay dinleyecilerimizi kodlayalım.
İlk olarak istek göndermeden önce tetikleyeceğimiz olay dinleyicimizi ile başlayalım.

use \Hadise\IEventListener;
use \Hadise\Event;
class BeforeRequestListener implements IEventListener
{
  public function invoke(Event $event)
  {
    $logData = sprintf("Source:\n" .
                       "------------------\n" .
                       "%s\n" .
                       "Request:\n" .
                       "------------\n" .
                       "%s\n", get_class($event->getSource()),
                       var_export($event->getParameters(), true);
    file_put_contents('transaction_log', $logData, FILE_APPEND);
  }
}

Şimdi de istek gönderdikten sonra tetikleyeceğimiz olay dinleyicimizi kodlayalım.

use \Hadise\IEventListener;
use \Hadise\Event;
class AfterRequestListener implements IEventListener
{
  public function invoke(Event $event)
  {
    $logData = sprintf("Source:\n" .
                       "------------------\n" .
                       "%s\n" .
                       "Response:\n" .
                       "------------\n" .
                       "%s\n", get_class($event->getSource()),
                       var_export($event->getParameters(), true);
    file_put_contents('transaction_log', $logData, FILE_APPEND);
  }
}

Mevcut api implementasyonumuzda istek öncesi ve sonrasında olay dinleyicilerimizin tetiklenmesini sağlayalım.

class MyApiImpl implements MyApiImplInterface
{
  //...
  protected function __sendRequest($url, array $data)
  {
    $requestXML = http_build_query($data);
    EventManager::getManager('MyApiImpl')->riseEvent('beforeRequest', $this, array('data' => $requestXML));
        
    $ch = curl_init();
    //...
    $responseData = curl_exec($ch);
    //...
    EventManager::getManager('MyApiImpl')->riseEvent('afterRequest', $this, array('data' => $responseData));
  }
  //...
}

Son olarak olay dinleyicilerimizi olay yöneticimize iliştirelim.

EventManager::getManager('MyApiImpl')
            ->addListener('beforeRequest', new BeforeRequestListener());
EventManager::getManager('MyApiImpl')
            ->addListener('afterRequest', new AfterRequestListener());

Hepsi bu kadar. İyi eğlenceler :)

Yazılım ve Sistem Mühendisliği

Bi Fonksiyon Yazdım…

Bugün de yazılım dünyasının kanayan başka bir yarasına deyinelim dedim. :)

Kod tekrarının sıkca yapıldığı umumiyetle de OOP olmayan projelerde aynı işi farklı parametrelerle gerçekleştirip benzer çıktılar üreten fonksiyonlar görmeniz olasıdır. Genellikle bu tarz durumlarda tepesi atan bir geliştirici refactoring yapma aşkıyla sistemdeki benzer tüm fonksiyonları birleştirip leb demeden çerez tabağı üreten fonksiyonlar geliştirir.:) Bu yaklaşımın ne kadar yanlış olduğunu anlamak için öncelikle şu yazıyı incelemenizi öneririm.

Bugün de yine birlikte gerçek hayattan bir örnek inceleyeceğiz. Elektronik ticaret şirketleri, oto servisleri veya perakende ürün/hizmet satışı yapılan yerlerde müşteriye satılan bir ürün ve bu ürünün satışı ile ilgili değişik iş modelleri vardır. Partenere göre, satış kurallarına göre, kullanılan kupona göre indirim, vergi ve ürün fiyatı değişkenlik gösterebilir ve siz bu problemi “Bir tane fonksiyon yazdım…” yaklaşaımıyla çözemezsiniz. Peki bu problemin ilacı ne ola ?

Örnek olarak inceleyeceğimiz yapıda bir elektronik ticaret sitesinin sepet hesaplamasını konu alacağız. Satış modelimiz yüzdelikli ve sabit tutarlı kupon kullanımından ibaret olacak.

Sepet hesaaplaması yaparken sırasıyla aşağıdaki işlemleri yapmamız gerekiyor.

  • Kupon tipine göre indirim tutarını hesaplamak.
  • Ürün ve sepet bazında KDV tutarı hesaplamak.
  • Sepet toplamını hesaplamak.

Strategy design pattern İlk maddeyi ele alacak olursak kullanacağımız kuponun tipine bağlı olarak indirim tutarını farklı algoritmalarla hesaplamamız gerektiğinden burada kullanabileceğimiz en doğru tasarım kalıbı strateji tasarım desenidir. Strateji tasarım deseni, belirli bir işlemin farklı algoritmalarla gerçekleştirilmesi gerektiği durumlarda kullanılan oluşumsal bir tasarım desenidir. Daha fazla bilgi için bu yazıyı inceleyebilirsiniz.

Decorator Design Pattern Örneği genel olarak ele aldığımızda ise indirim, kdv ve sepet toplamı gibi hesaplamaların ayrı ayrı yapılarak siparişi güncellemesi gerektiğini görüyoruz. Bu durumda kullanabileceğimiz en doğru tasarım deseni ise dekoratör tasarım desenidir. Dekoratör tasarım deseni, bir nesnenin özelliklerinin dinamik olarak değiştirilmesi gerektiği durumlarda kullanılır. Daha fazla bilgi için bu yazıyı inceleyebilrsiniz.

Kodlama kısmı yazıyı biraz uzattığı için sizleri sıkmamak adına bu yazıda yalnızca kupon hesaplayıcıyı inceliyor olacağız.

Öncelikle sipariş ve siparişe bağlı ürün sınıflarımızı oluşturalım.

Kupon hesaplayıcılarımız aynı işi farklı algoritmalarla gerçekleştiren iki farklı sınıf olacağına göre belirli bir arayüze tabi olmaları gerekir.

interface ICouponCalculator
{
	const CALCULATOR_FIXED = 1;
	const CALCULATOR_PERCENT = 2;
	
	/**
	 * @param Product $product
	 * @return float
	 */
	public function calculate(Product $product);
}

İndirim miktarı sepete dağıtılacağından indirim miktarı (oran veya sabit tutar olarak) ve toplam tutar verilerini hesaplayıcı örneğini oluştururken daha sonra kullanmak üzere saklıyoruz. Bu işlemi soyut hesaplayıcı sınıfımızın __construct() metodu içerisinde gerçekleştireceğiz.

abstract class AbstractCouponCalculator
{
	/**
	 * @var float
	 */
	protected $_discount_amount;
	
	/**
	 * @var float
	 */
	protected $_total_amount;
	
	/**
	 * @var float
	 */
	protected $_rounding_errors;
	
	/**
	 * @param float $discountAmount
	 * @param float $totalAmount
	 */
	public function __construct($discountAmount, $totalAmount)
	{
		$this->_discount_amount = $discountAmount;
		$this->_total_amount = $totalAmount;
	}
}

Ön hazırlıklarımızı tamamladığımıza göre hesaplayıcılarımızı kodlamaya başlayabiliriz. İlk olarak sabit tutarlı hesaplayıcımızı kodlayarak başlayalım.

class FixedCouponCalculator extends AbstractCouponCalculator implements ICouponCalculator
{
	/**
	 * (non-PHPdoc)
	 * @see ICouponCalculator::calculate()
	 */
	public function calculate(Product $product)
	{
		$percentage = $product->netPrice / $this->_total_amount;
		$discountAmount = $this->_rounding_errors + ($this->_discount_amount * $percentage);
                //yuvarlamadan kaynaklanan hatalari ihmal etmiyoruz.
		$this->_rounding_errors = $discountAmount - round($discountAmount);
                return $discountAmount;
	}	
}

Şimdi de oransal kupon hesaplayıcımızı kodlayalım.

class PercentCouponCalculator extends AbstractCouponCalculator implements ICouponCalculator
{
	/**
	 * (non-PHPdoc)
	 * @see ICouponCalculator::calculate()
	 */
	public function calculate(Product $product)
	{
		$discountAmount = $product->netPrice * $this->_discount_amount;
		return $discountAmount;
	}
}

Geldik hesaplama stratejimizi belirlemeye. Şimdi de kupon tipine göre hesaplama yapacak strateji sınıfımızı kodlayalım.

class CouponCalculator implements ICouponCalculator
{
	/**
	 * @var ICouponCalculator
	 */
	private $_calculator;
	
	/**
	 * @param int $calculatorType
	 * @param float $discountAmount
	 * @param float $totalAmount
	 */
	public function __construct($calculatorType, $discountAmount, $totalAmount)
	{
		switch($calculatorType) {
			case ICouponCalculator::CALCULATOR_FIXED:
				$this->_calculator = new FixedCouponCalculator($discountAmount, $totalAmount);
				break;
			case ICouponCalculator::CALCULATOR_PERCENT:
				$this->_calculator = new PercentCouponCalculator($discountAmount, $totalAmount);
				break;
		}
	}
	
	/**
	 * (non-PHPdoc)
	 * @see ICouponCalculator::calculate()
	 */
	public function calculate(Product $product)
	{
		return $this->_calculator->calculate($product);
	}
} 

Bir sonraki yazıda dekoratör tasarım desenini kullanarak sizlerle birlikte sepet hesaplayıcısını kodlayacağız.

Yazılım ve Sistem Mühendisliği

Observer Tasarım Kalıbı ve Olay Güdümlü Programlama

Üzerinde çalıştığım bir projeye kısa bir çay molası vermişken sizlerle çok sevdiğim ve şu an üzerinde çalıştığım projede de kullandığım gözlemci (observer) tasarım kalıbı ve olay güdümlü programlama konularndan kısaca bahsetmek istiyorum.

87628254
Olay güdümlü programlama, iç veya dış etkenlerle meydana gelen olaylar doğrultusunda program akışının değiştirilmesi gerektiği durumlarda kullanılan bir tekniktir. Bir e-ticaret sitesinde ziyaretcinin herhangibir nedenle alışverişi tamamlayamaması durumunda belirli bir kullanıcı gurubunun haberdar edilmesi, herhangibir servisle iletişim sorunu olması durumunda aksiyon alınması gibi durumlar, olay güdümlü programlama gerektirir.

Observer
Observer tasarım kalıbı ise birbirleriyle bire-çok ilişki içindeki nesnelerden herhangibirinde değişiklik olması durumunda bir merkez üzerinden diğer nesnelerin haberdar edilmesi gerektiği durumlarda kullanılır ve olay güdümlü programlama için biçilmiş kaftandır :)

Dilerseniz gelin hemen birlikte gerçek hayattan bir örnek inceleylim.

Bir elektronik ticaret şirketinde çalışıyoruz. Saat başı zamanlanmış bir görevle gelen siparişleri lojistik şirketine iletiyoruz. Ancak siparişlerin herhangibir nedenle iletilememesi durumunda 1 dk bekleyip tekrar deneme gerçekleştirmek istiyoruz.

Kod örneğine geçmeden önce gözlemci tasarım kalıbı ve olay güdümlü programlama arasındaki ilişki konusunda kısa bir bilgi vermekte yarar var. Observer tasarım desenini kullanarak yazılımımızın akışıını olaylarla değiştirebilmek için olayın gerçekleştiği yeri merkez, olayı dinleyen bölümü observer olarak düşünmeliyiz.

Aşağıdaki gibi bir lojistik arayüzümüz var. Tüm lojistik implementasyonlarımız bu arayüzü implement eder.

interface ILogistic
{
	/**
	 * @param string $articleCode
	 * @param string $refNumber
	 * @return bool
	 */
	public function send($articleCode, $refNumber);
	
	/**
	 * @param string $refNum
	 * @return string
	 */
	public function getStatus($refNum);
}

Basit ve anlaşılır olması açısından herbir gözlemcinin tek bir olay içerdiğini varsayıyoruz. Aşağıda gözlemci sınıflarımızın implement edeceği arayüz kodu yeralıyor.

interface IObserver
{
	/**
	 * @param Event $event
	 */
	public function invoke(Event $event);
}

Olayın gerçekleşeceği bölümün implement edeceği IObservable arayüzünü kodlayalım.

interface IObservable
{
	/**
	 * @param IObserver $observer
	 * @param string $eventName
	 */
	public function attach(IObserver $observer, $eventName);
	
	/**
	 * @param Event $event
	 */
	public function fireEvent(Event $event);
}

Olay gerçekleştiğinde olayla ilgili bilgileri gözlemciye (observer) taşıyacak olay sınıfımızı kodlayalım.

class Event
{
	/**
	 * @var string
	 */
	private $_event_type;
	
	/**
	 * @var IObservable
	 */
	private $_source;
	
	/**
	 * @var string
	 */
	private $_last_called_method;
	
	/**
	 * @var array
	 */
	private $_arguments;
	
	/**
	 * @param string $eventName
	 * @param IObservable $source
	 * @param string $lastCalledMethod
	 * @param array $arguments
	 */
	public function __construct($eventName,  IObservable $source, $lastCalledMethod, array $arguments)
	{
		$this->_event_name = $eventName;
		$this->_source = $source;
		$this->_last_called_method = $lastCalledMethod;
		$this->_arguments = $arguments;
	}
	
	/**
	 * @return string
	 */
	public function getEventName()
	{
		return $this->_event_type;
	}
	
	/**
	 * @return IObservable
	 */
	public function getSource()
	{
		return $this->_source;
	}
	
	/**
	 * @return string
	 */
	public function getLastCalledMethod()
	{
		return $this->_last_called_method;
	}
	
	/**
	 * @return array
	 */
	public function getArguments()
	{
		return $this->_arguments;
	}
}

Lojistik implementasyonlarımızın devralacağı soyut sınıfımızı kodlayalım.

abstract class LogisticAbstract
{	
	/**
	 * @param string $articleCode
	 * @param string $refNum
	 * @return array
	 */
	abstract protected function _getSendRequest($articleCode, $refNum);
	
	/**
	 * @param string $refNum
	 * @return array
	 */
	abstract protected function _getStatusRequest($refNum);
	
	/**
	 * @param string $apiResponse
	 * @return bool
	 */
	abstract protected function _parseSendRequest($apiResponse);
	
	/**
	 * @param string $apiResponse
	 * @return string
	 */
	abstract protected function _parseStatusRequest($apiResponse);
	
	/**
	 * @param string $url
	 * @param array $data
	 * @throws Exception
	 * @return string
	 */
	protected function _sendRequest($url, array $data)
	{
		$postData = http_build_query($data);
		$ch = curl_init();
		$options = array(CURLOPT_URL => $url,
					    CURLOPT_RETURNTRANSFER => true,
					    CURLOPT_POST 	   => true,
					    CURLOPT_POSTFIELDS 	   => $postData);
		curl_setopt_array($ch, $options);
		$response = curl_exec($ch);
	    if($error = curl_errno($ch)) {
	    	throw new Exception('Error occurred while sending data to remote server. Detail:' . $error, '');
	    }
	    return $response;
	}
}

Lojistik şirketimizin adı örnek lojistik olsun.

class OrnekLojistik extends LogisticAbstract implements ILogistic, IObservable
{
	/**
	 * @var array
	 */
	private $_observers = array();
	
	/**
	 * @param string $articleCode
	 * @param string $refNumber
	 * @return array
	 */
	protected function _getSendRequest($articleCode, $refNumber)
	{
		$xml = "
				
				  
				  send
				  {$articleCode}
				  {$refNumber}
				  
				";
		return array('data' => $xml);
	}
	
	/**
	 * @param string $refNum
	 * @return array
	 */
	protected function _getStatusRequest($refNum)
	{
		//...
	}
	
	/**
	 * @param string $apiResponse
	 */
	protected function _parseSendRequest($apiResponse)
	{
		try {
			$xml = new SimpleXMLElement($xml);
			return $xml->Response->Status == 'OK';		
		} catch(Exception $e) {
			throw new Exception('Unexpected Response. Response message:' . $apiResponse);
		}
	}
	
	/**
	 * @param string $apiResponse
	*/
	protected function _parseStatusRequest($apiResponse)
	{
		//...
	}
	
	/**
	 * @param string $articleCode
	 * @param string $refNumber
	 */
	public function send($articleCode, $refNumber)
	{
		try {
			$request = $this->_getSendRequest($articleCode, $refNumber);
			$apiResponse = $this->_sendRequest('http://ws.orneklojistik.com/OrnekWS.php', $request);
			$response = $this->_parseSendRequest($apiResponse);
			if(! $response ) {
				$this->fireEvent(new Event('shipping_failed', $this, __METHOD__, func_get_args() ));
			}
			return $response;
		} catch(Exception $e) {
			$this->fireEvent(new Event('shipping_failed', $this, __METHOD__, func_get_args() ));
                        return false;
		}
	}
	
	/**
	 * @param string $refNum
	*/
	public function getStatus($refNum)
	{
		//...		
	}
	
	/**
	 * (non-PHPdoc)
	 * @see IObservable::attach()
	 */
	public function attach(IObserver $observer, $eventName)
	{
		if( ! isset( $this->_observers[$eventName] ) ) {
			$this->_observers[$eventName] = array();
		}
		$this->_observers[$eventName][] = $observer;
	}
	
	/**
	 * (non-PHPdoc)
	 * @see IObservable::fireEvent()
	 */
	public function fireEvent(Event $event)
	{
		if( isset( $this->_observers[$event->getEventName() ] ) ) {
			/* @var $event IObserver  */
			foreach ($this->_observers[$event->getEventName()] as $observer) {
				$observer->invoke($event);
			}
		}
	}
}

Lojistik şirketine gönderim sırasında sorun yaşamamız durumunda çalışacak gözlemci sınıfını kodlayalım.

class OrnekLojistik_Observer_OnFail implements IObserver
{
	/**
	 * @var bool
	 */
	private $_tried = false;

	/**
	 * (non-PHPdoc)
	 * @see IObserver::invoke()
	 */
	public function invoke(Event $event)
	{
		if( ! $this->_tried ) {
			sleep(60);
			call_user_method($event->getLastCalledMethod(), $event->getSource(), $event->getArguments());
		}	
	}
}

Geldik zamanlanmış görevimize. Buyrun size zamanlanmış görev…

class SendLogisticCommand implements ICommand
{
	/**
	 * @param array $args
	 */
	public function run($args)
	{
		$products = array('ABC123', 'DEF234', 'GHI123');
		
		$logistic = new OrnekLojistik();
		$observer = new OrnekLojistik_Observer_OnFail();
		$logistic->attach($observer, 'shipping_failed');
		
		foreach($products as $product) {
			$logistic->send($product, time() );
		}
	}
}

Biraz uzun oldu sanırım :) Hızlıca hazırladığım için ufak tefek hiyerarşi sıkıntıları olabilir ancak genel anlamda sizlere fikir verebileceğini ümit ediyorum.

Programa Dilleri ve Çatıları

Pratik Zend Config Kullanımı

Zend framework ile proje geliştirirken konfigürasyon dosyalarını okumak için sıklıkla kullandığım kütüphanemin kaynak kodlarını sizlerle paylaşmak istedim.

MyVendor/Config.php :

_config ) ) {
            $this->_config[$key] = $this->_getAdapter($fileName, $section);
        }

        return $this->_config[$key];
    }

    /**
     * returns file extension.
     * @param string $fileName
     * @return string
     */
    private function _getExtension($fileName)
    {
        $explodedFileName = array_reverse(explode('.', $fileName));
        $extension = reset($explodedFileName);
        return ucfirst($extension);
    }

    /**
     * returns reader adapter.
     * @param string $fileName
     * @param string $section
     * @throws MyVendor_Config_Exception
     * @return Zend_Config_Json|Zend_Config_Xml|Zend_Config_Ini|Zend_Config_Yaml
     */
    private function _getAdapter($fileName, $section = null)
    {
        $extension = $this->_getExtension($fileName);
        switch($extension) {
            case self::FILE_TYPE_JSON:
                return new Zend_Config_Json($fileName, $section);
            case self::FILE_TYPE_XML:
                return new Zend_Config_Xml($fileName, $section);
            case self::FILE_TYPE_INI:
                return new Zend_Config_Ini($fileName, $section);
            case self::FILE_TYPE_YAML:
                return new Zend_Config_Yaml($fileName, $section);
            default:
                throw new MyVendor_Config_Exception('Unknown file type:' . $extension, '');
        }
    }
}

MyVendor/Pattern/Singleton.php :

MyVendor/Config/Exception.php :

Örnek Kullanım:

loadFromFile($file, APPLICATION_ENV);
Programa Dilleri ve Çatıları

YII Framework Modülleri Arasında Model Erişimi

Hobi için uğraştığım proje anlaşılan bu ara epey blog yazısı yazmama vesile olacak.

YII framework de modüler bir proje geliştiriyorsanız projenin herhangibir yerinden modül içerisindeki bir modüle ulaşmak için aşağıdaki yolu izleyebilirsiniz.

1- Framework ün yardımcısını kullanarak veya manuel olarak aşağıdaki klasör yapısını oluşturmak suretiyle yeni bir modül oluşturun.

protected/
  modules/
    blog/
      components/
      models/
      views/
      controllers/

2- Güzel… Şimdi konfigürasyon dosyasına (protected/config/main.php) oluşturduğumuz modülü tanımlayalım.

  array('modules' => array(
    ---
    'blog'
  ));

3- Post isimli yeni bir model oluşturun ve bu modeli yeni oluşturduğunuz modülün model klasörüne (protected/modules/blog/model/) Post.php olarak kayıt edin.

class Post
{
  public function newPost()
  {
    ...
  }
}

4- Şimdi de modül sınıfımızı oluşturalım. Bu modülün içine ekleyeceğimiz getPost metodu az önce oluşturduğumuz modele başka modüllerden erişebilme imkanını sağlayacak. Bu sınıfı yeni oluşturduğunuz modül klasörüne BlogModule.php olarak kayıt edin.

class BlogModule extends CModule
{
  public function init()
  {
    $this->setImport(array('blog.models.*',
                           'blog.components.*'));
  }
  
  public function getPost()
  {
    return new Post();
  }
}

Oluşturduğumuz blog modülü dışında, projenin herhangibir yerinde Post modeline ulaşmamız gerektiğinde aşağıdaki şekilde ulaşabiliriz.

$post = Yii::app()->getModule('blog')->getPost();

Hepsi bu. İyi eğlenceler :) .