Monthly Archives: Ekim 2015

Programa Dilleri ve Çatıları

JMS Serializer Kullanarak Serialization İşlemi Gerçekleştirme

Paranoia’nın ilk sürümlerinde bankalara gönderilecek XML datasını üretmek için PHP dizilerini XML’e dönüştüren açık kaynaklı bir kütüphane kullamıştım. Pratikti ve her halukarda PHP sınıfının içine apaçık XML yazmaktan çok daha temiz bir yoldu. Ancak yine de hala entegrasyon sınıflarını açtığınızda koca koca dizileri görmek hem çirkin, hem de okunabilirlik açısından çok hoş değil. Projenin daha başından sağolsun Osman Üngür pek çok yapısal öneride bulunmuştu. JMS Serializer da bu önerilerden biriydi.

Serialization nedir ?

Kabaca programatik bir varlığın saklanmak veya aktarılmak maksadıyla yeniden dönüştürülebilir bir formata çevirilmesi işlemidir.

JMS Serializer Kullanılarak Serialization Nasıl Gerçekleştirilir ?

Örneğin NestPay altyapısı üzerinde çalışan bir bankanın ödeme için kullandığı XML datasını üreteceğimiiz varsayalım. Üreteceğimiz XML aşağıdaki gibi olacaktır.

<?xml version="1.0" encoding="ISO-8859-1"?>
<CC5Request>
    <Name> </Name>
    <Password> </Password>
    <ClientId> </ClientId>
    <Mode>P</Mode>
    <OrderId> </OrderId>
    <Type>Auth</Type>
    <Number> </Number>
    <Expires> </Expires>
    <Cvv2Val> </Cvv2Val>
    <Total> </Total>
    <Taksit> </Taksit>
    <Currency>949</Currency>
    <UserId></UserId>
</CC5Request>

Öncelikle JMSSerializer paketinin kurulumunu gerçekleştirelim.

$ composer require jms/serializer "1.1.0"

Eğer JMS Serializer kütüphanesini Symfony2 çatısı altında kullanmıyorsanız, kütüphanenin doctrine annotation kütüpahnesiyle olan bağımlılığı nedeniyle mapping sınıflarında kullanacağımız annotationları otomatik olarak yükleyebilmek için öncelikle Annotation otomatik yükleyicisini ayaklandırmamız gerekmektedir.

require_once(__DIR__ . "/vendor/autoload.php");

\Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
    'JMS\Serializer\Annotation', __DIR__.'/vendor/jms/serializer/src'
);

Şimdi de XML formatına dönüştürülecek PHP Sınıfını oluşturalım.

class CC5Request
{
	private $name;
	private $password;
	private $clientId;
	private $mode;
	private $orderId;
	private $type;
	private $number;
	private $expires;
	private $cvv2val;
	private $total;
	private $taksit;
	private $currency;
	private $userId;
}

JMS Serializer’ın, yukarıdaki sınıf için serialization işlemi gerçekleştirdiğinde hangi alanın ne şekilde XML şemasında tanımlanacağını anlayabilmesi için , sınıfı aşağıdaki gibi gerekli annotation larla donatalım.

use JMS\Serializer\Annotation\XmlElement;
use JMS\Serializer\Annotation\XmlRoot;
use JMS\Serializer\Annotation\Type;
use JMS\Serializer\Annotation\SerializedName;

/**
 * @XmlRoot("CC5Request")
 */
class CC5Request
{
    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("Name")
     */
    private $name;

    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("Password")
     */
    private $password;

    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("ClientId")
     */
    private $clientId;

    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("Mode")
     */
    private $mode;

    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("OrderId")
     */
    private $orderId;

    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("Type")
     */
    private $type;

    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("Number")
     */
    private $number;

    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("Expires")
     */
    private $expires;

    /**
     * @XmlElement(cdata=false)
     * @Type("integer")
     * @SerializedName("Cvv2Val")
     */
    private $cvv2val;

    /**
     * @XmlElement(cdata=false)
     * @Type("double")
     * @SerializedName("Total")
     */
    private $total;

    /**
     * @XmlElement(cdata=false)
     * @Type("integer")
     * @SerializedName("Taksit")
     */
    private $taksit;

    /**
     * @XmlElement(cdata=false)
     * @Type("integer")
     * @SerializedName("Currency")
     */
    private $currency;

    /**
     * @XmlElement(cdata=false)
     * @Type("string")
     * @SerializedName("UserId")
     */
    private $userId;

    /**
     * @param mixed $clientId
     */
    public function setClientId($clientId)
    {
        $this->clientId = $clientId;
    }

    /**
     * @return mixed
     */
    public function getClientId()
    {
        return $this->clientId;
    }

    /**
     * @param mixed $currency
     */
    public function setCurrency($currency)
    {
        $this->currency = $currency;
    }

    /**
     * @return mixed
     */
    public function getCurrency()
    {
        return $this->currency;
    }

    /**
     * @param mixed $cvv2val
     */
    public function setCvv2val($cvv2val)
    {
        $this->cvv2val = $cvv2val;
    }

    /**
     * @return mixed
     */
    public function getCvv2val()
    {
        return $this->cvv2val;
    }

    /**
     * @param mixed $expires
     */
    public function setExpires($expires)
    {
        $this->expires = $expires;
    }

    /**
     * @return mixed
     */
    public function getExpires()
    {
        return $this->expires;
    }

    /**
     * @param mixed $mode
     */
    public function setMode($mode)
    {
        $this->mode = $mode;
    }

    /**
     * @return mixed
     */
    public function getMode()
    {
        return $this->mode;
    }

    /**
     * @param mixed $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param mixed $number
     */
    public function setNumber($number)
    {
        $this->number = $number;
    }

    /**
     * @return mixed
     */
    public function getNumber()
    {
        return $this->number;
    }

    /**
     * @param mixed $orderId
     */
    public function setOrderId($orderId)
    {
        $this->orderId = $orderId;
    }

    /**
     * @return mixed
     */
    public function getOrderId()
    {
        return $this->orderId;
    }

    /**
     * @param mixed $password
     */
    public function setPassword($password)
    {
        $this->password = $password;
    }

    /**
     * @return mixed
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * @param mixed $taksit
     */
    public function setTaksit($taksit)
    {
        $this->taksit = $taksit;
    }

    /**
     * @return mixed
     */
    public function getTaksit()
    {
        return $this->taksit;
    }

    /**
     * @param mixed $total
     */
    public function setTotal($total)
    {
        $this->total = $total;
    }

    /**
     * @return mixed
     */
    public function getTotal()
    {
        return $this->total;
    }

    /**
     * @param mixed $type
     */
    public function setType($type)
    {
        $this->type = $type;
    }

    /**
     * @return mixed
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * @param mixed $userId
     */
    public function setUserId($userId)
    {
        $this->userId = $userId;
    }

    /**
     * @return mixed
     */
    public function getUserId()
    {
        return $this->userId;
    }
}

Normal şartlarda JMSSerilizer biz, bu annotationları kullanmıyor olsak da halihazırda tanımlanan sınıf ve attribute isimlendirmelerine göre serialization işlemini gerçekleştirebiliyor. Ancak örnek XML deki isimleindirmelerin farklı ve PHP için genel geçer isimlendirme standarlarının dışnda olması nedeniyle annotation lar vasıtasıyla sınıfımızın serialization çıktısını dekore ediyoruz.

Dilerseniz birlikte kısaca kullanıdğımız annotation ları tanıyalım.

XmlRoot: Serialiation sonrasında oluşacak XML kök bölümünün isimlendirmesi için kullanılır.

XmlElement: Bulunduğu alanın serialize edilmesi ile ilgili çeşitli özelliklerinin düzenlenmesi için kullanılır.

Type: Bulunduğu alanın veri tipinin belirtilmesini sağlar.

SerializedName: İlgili alanın serialization sırasında nasıl isimlendirilecğeini tanımlamak için kullanılır.

JMS Serializer tarafından desteklenen diğer annotation’lar için bu dökümanı inceleyebilirsiniz.

Artık serialization işlemine hazır olduğumuza göre oluşturduğumuz sınıfdan bir örnek oluşturalım ve test verisiyle dolduralım.

$obj = new CC5Request();
$obj->setClientId("006641");
$obj->setOrderId('000000000001');
$obj->setNumber('5105105105105100');
$obj->setExpires('12/18');
$obj->setCvv2Val('000');
$obj->setCurrency(949);
$obj->setTotal(55.41);
$obj->setUserId(1);
$obj->setMode('P');
$obj->setName('TESTUSER');
$obj->setPassword('123qwe123');
$obj->setType('Auth');

Serialize edelim.

$serializer = JMS\Serializer\SerializerBuilder::create()->build();
echo $serializer->serialize($obj, 'xml');

**Çıktı:**

<?xml version="1.0" encoding="UTF-8"?>
<CC5Request>
  <Name>TESTUSER</Name>
  <Password>123qwe123</Password>
  <ClientId>006641</ClientId>
  <Mode>P</Mode>
  <OrderId>000000000001</OrderId>
  <Type>Auth</Type>
  <Number>5105105105105100</Number>
  <Expires>12/18</Expires>
  <Cvv2Val>000</Cvv2Val>
  <Total>55.41</Total>
  <Currency>949</Currency>
  <UserId>1</UserId>
</CC5Request>