Composer adalah sebuah dependecy manager khusus untuk bahasa pemrograman PHP. Pengertian dan kegunaan dari composer sudah banyak dibahas oleh web lain, oleh karena itu fokus kita kali ini adalah membuat sebuah composer package yang akan mengambil data dari web lain (scraping dan parsing) dengan bantuan library GuzzleHTTP.

TLDR;

Hasil akhir package telah dipublikasikan pada https://github.com/omkoding/cot-report-parser dan sudah mengalami penambahan fungsi.

Jalankan composer require omkoding/cot untuk menambahkan sebagai dependasi composer anda.

Perhatian! Artikel ini ditulis dengan asumsi OS yang digunakan adalah Linux based (Ubuntu). Untuk OS lainnya silahkan disesuaikan.

Struktur Direktori Package

Anggaplah anda mempunyai direktori kerja (workspace) dengan path ~/dev, maka buatlah folder cot-report-parser untuk menaruh semua file package anda, maka workspace anda sekarang adalah ~/dev/cot-report-parser.

Kemudian buatlah folder src di dalam workspace tersebut yang digunakan untuk menyimpan script inti yang menjalankan fungsi-fungsi dari package anda. Maka sekarang workspace anda memiliki struktur sebagai berikut.

~/dev/cot-report-parser
~/dev/cot-report-parser/src

Membuat File composer.json

Pada workspace anda, buatlah sebuah file composer.json menggunakan teks editor anda dan salin kode berikut kedalamnya. Disini saya menggunakan omkoding sebagai nama vendor dan cot-report-parser sebagai nama package.

{
    "name": "omkoding/cot",
    "type": "library",
    "require": {
        "php": "^7.1.3"
    },
    "autoload": {
        "psr-4": {
            "OmKoding\\Cot\\": "src/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
}
  • name. Berisi nama vendor dan nama package anda.
  • type. Jenis dari package ini, normalnya ada library.
  • require. Isikan dengan requirement yang harus dipenuhi untuk menjalankan package.
  • autoload. Gunakan psr-4 sebagai standard autoload. Isi namespace yang merujuk ke folder src
  • minimum-stability. Pembatasan terhadap versi package lain yang menjadi dependasinya.
  • prefer-stable. Pembatasan untuk selalu menggunakan versi stabil dari package lain.

Anda bisa saja menambahkan description, keyword, dan skema lainnya bila dirasa perlu. Untuk struktur lengkapnya anda dapat melihat di laman schema.md

Catatan untuk penggunaan nama vendor. Anggaplah nama vendor sebagai ID anda sebagai penulis sehingga haruslah unik tidak boleh sama dengan orang lain. Untuk mengecek apakah nama anda masih tersedia bisa dengan menggunakan menu search pada laman https://packagist.org. Apabila hasilnya package not found ataupun yang keluar tidak mengandung query anda, maka anda bisa menggunakannya.

Nama vendor pada composer package harus unik

Menambahkan GuzzleHTTP Sebagai Dependency

GuzzleHTTP adalah sebuah library yang membantu kita dalam berinteraksi dengan HTTP Request. Misalnya membuka laman URL tertentu. Kita bisa saja memakai cURL langsung, tapi kita harus repot untuk membuat error handler dan fallback ketika cURL library belum terinstall di server kita.

Buka terminal dan arahkan pada workspace anda di ~/dev/cot-parser-report. Kita akan menambahkan sebagai dependasi dari package kita. Jalankan perintah berikut.

composer require guzzlehttp/guzzle
composer require guzzlehttp

Setelah proses selesai, maka pada bagian require file composer.json terdapat tambahan sebagai berikut.

{
    "name": "omkoding/cot",
    "type": "library",
    "require": {
        "php": "^7.1.3",
+	     "guzzlehttp/guzzle": "^6.3"
    },
    "autoload": {
        "psr-4": {
            "OmKoding\\Cot\\": "src/"
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true
}

Scraping dan Parsing Data dari URL Web

Fungsi utama dari package ini adalah mengambil data COT Report yang dirilis oleh cftc.gov setiap minggunya. Data yang diambil kemudian diproses dengan output array sehingga menjadi lebih user-friendly untuk dimasukkan ke dalam database ataupun sebagai JSON response.

Data yang akan kita ekstrak adalah sebagai berikut:

  1. Nama item yang diperdagangkan
  2. Tanggal laporan
  3. Posisi terkini dari Non Commercial dan Commercial
  4. Open Interest total
  5. Open Interest Changes dari Non Commercial dan Commercial
  6. Open Interest percentage dari Non Commercial dan Commercial

Laman yang akan kita olah ada 2 tipe yaitu:

  1. Laporan terakhir / terkini pada laman https://www.cftc.gov/dea/futures/deacmesf.htm
  2. Histori Laporan dengan struktur laman https://www.cftc.gov/sites/default/files/files/dea/cotarchives/[4 DIGIT YEAR]/futures/deacmesf[2 DIGIT MONTH][2 DIGIT DAY][2 DIGIT YEAR].htm. Contohnya https://www.cftc.gov/sites/default/files/files/dea/cotarchives/2017/futures/deacmesf011717.htm

Buatlah file Report.php di dalam folder src. Salin kode berikut.

<?php

namespace OmKoding\Cot;

use GuzzleHttp\Client;

class Report
{
	/**
	 * @var \GuzzleHttp\Client
	 */
	protected $client;

	/**
	 * Initiate class
	 */
	public function __construct()
	{
		$this->client = new Client([
			'http_errors' => false,
		]);
	}
}
  1. Deklarasi namespace sesuai dengan konfigurasi autoload psr-4 pada file composer.json
  2. Import GuzzleHttp
  3. Pada __construct() kita deklarasi GuzzleHttp yang nantinya dipanggil via $this->client.

Sekarang kita akan membuat metode untuk scraping laporan terakhir dulu. Tambahkan kode berikut ini.

<?php

namespace OmKoding\Cot;

use GuzzleHttp\Client;

class Report
{
	/**
	 * @var \GuzzleHttp\Client
	 */
	protected $client;

	/**
	 * Initiate class
	 */
	public function __construct()
	{
		$this->client = new Client([
			'http_errors' => false,
		]);
	}
+
+	/**
+	 * Get latest COT Report
+	 * 
+	 * @return array
+	 */
+	public function latest()
+	{
+		$url = 'https://www.cftc.gov/dea/futures/deacmesf.htm';
+
+		$response = $this->client->get($url);
+
+		$lines = explode(PHP_EOL, (string) $response->getBody());
+
+		$result = [];
+
+		foreach ($lines as $index => $line) {
+			// 
+		}
+
+		return $result;
+	}
}
  1. Panggil laman tersebut dengan metode GET.
  2. Pisahkan hasil HTML tiap baris
  3. Pada bagian foreach nantinya kita akan mengolah baris per baris agar dapat data yang kita inginkan

Sekarang kita amati dulu struktur data yang akan kita ambil. Kita buka laman di atas via browser dan view-source (Ctrl + U pada Chrome), kita bisa melihat bahwa data disajikan dalam bentuk table mentah (tanpa HTML Tabel) yang dimasukkan dalam kode <pre></pre>.

struktur data cot report via view-source pada chrome

Dalam laporan tersebut terdiri dari berbagai macam item yang diperdagangkan seperti BUTTER (CASH SETTLED) dan MILK, Class III. Disini terlihat polanya adalah nama item berada di awal data tabel dan selalu diakhiri dengan - CHICAGO MERCANTILE EXCHANGE.

Baris yang berisi nama item akan kita jadikan index untuk menentukan posisi data pada baris lainnya sebagai berikut:

  1. Nama item pada posisi index
  2. Tanggal laporan pada posisi index + 1
  3. Open Interest total pada posisi index + 7
  4. Posisi terkini pada posisi index + 9
  5. Open Interest total changes pada posisi index + 11
  6. Perubahan posisi dibandingkan minggu lalu pada posisi index + 12
  7. Open Interest percentage pada posisi index + 15

Data pada setiap baris dipisahkan oleh spasi, jadi selain index baris, kita juga akan mengambil data per index column. Berdasarkan analisa diatas, maka berikut kode yang akan implementasikan untuk mengekstrak datanya.

<?php

namespace OmKoding\Cot;

use GuzzleHttp\Client;

class Report
{
	/**
	 * @var \GuzzleHttp\Client
	 */
	protected $client;

	/**
	 * Initiate class
	 */
	public function __construct()
	{
		$this->client = new Client([
			'http_errors' => false,
		]);
	}

	/**
	 * Get latest COT Report
	 * 
	 * @return array
	 */
	public function latest()
	{
		$url = 'https://www.cftc.gov/dea/futures/deacmesf.htm';

		$response = $this->client->get($url);

		$lines = explode(PHP_EOL, (string) $response->getBody());

		$result = [];

		foreach ($lines as $index => $line) {
+			// cari baris yang mengandung nama item
+			if (stripos($line, ' - CHICAGO MERCANTILE EXCHANGE') !== false) {
+				// ambil nama item sebelum string berikut
+				$nameLine = explode(' - CHICAGO MERCANTILE EXCHANGE', $line);
+
+				$name = $nameLine[0];
+
+				// ambil tanggal pada baris index + 1 dan pisahkan berdasarkan spasi
+				$dateLine = preg_split('/\s+/', trim($lines[$index + 1]));
+
+				$date = $date[5];
+
+				// ambil Open Interest pada baris index + 7 dan pisahkan berdasarkan spasi
+				$openInterestLine = preg_split('/\s+/', trim($lines[$index + 7]));
+
+				// ambil index column terakhir
+				$openInterest = end($openInterestLine);
+
+				// ambil Open Interest Total Change pada baris index + 11 dan pisahkan
+				$openInterestChangeLine = preg_split('/\s+/', trim($lines[$index + 7]));
+
+				//  ambil index column terakhir dan hilangkan akhiran ")"
+				$openInterestChange = rtrim(end($openInterestChangeLine), ')');
+
+				// ambil posisi terkini pada baris index + 9 dan pisahkan berdasarkan spasi
+				$current = preg_split('/\s+/', trim($lines[$index + 9]));
+
+				// ambil perubahan dari minggu lalu pada baris index + 12 dan pisahkan berdasarkan spasi
+				$changes = preg_split('/\s+/', trim($lines[$index + 12]));
+
+				// ambil Open Interest Percent Changes pada baris index + 15 dan pisahkan berdasarkan spasi
+				$percent = preg_split('/\s+/', trim($lines[$index + 15]));
+
+				$result[$name] = [
+					'name' => $name,
+					'date' => $date,
+					'current' => [
+						'non-commercial' => [
+							'long' => $current[0],
+							'short' => $current[1],
+							'spreads' => $current[2],
+						],
+						'commercial' => [
+							'long' => $current[3],
+							'short' => $current[4],
+						],
+					],
+					'changes' => [
+						'non-commercial' => [
+							'long' => $changes[0],
+							'short' => $changes[1],
+							'spreads' => $changes[2],
+						],
+						'commercial' => [
+							'long' => $changes[3],
+							'short' => $changes[4],
+						],
+					],
+					'open-interest' => [
+						'current' => $openInterest,
+						'change' => $openInterestChange,
+						'non-commercial' => [
+							'long' => $percent[0],
+							'short' => $percent[1],
+							'spreads' => $percent[2],
+						],
+						'commercial' => [
+							'long' => $percent[3],
+							'short' => $percent[4],
+						],
+					],
+				];
+			}
		}

		return $result;
	}
}

Untuk menjalankan kode tersebut maka kita cukup memanggilnya dengan kode berikut

<?php

// load composer bootstrap for autoload
require '../vendor/autoload.php';

use OmKoding\Cot\Report;

$reports = (new Report)->latest();

Karena laporan terakhir dan histori laporan mempunyai struktur data yang sama, maka ada baiknya baris yang berisi ekstraksi data kita pisahkan menjadi metode terpisah sehingga bisa dipanggil berulang kali tanpa harus menulis ulang. Ubah kode menjadi berikut.

<?php

namespace OmKoding\Cot;

use GuzzleHttp\Client;

class Report
{
	/**
	 * @var \GuzzleHttp\Client
	 */
	protected $client;

	/**
	 * Initiate class
	 */
	public function __construct()
	{
		$this->client = new Client([
			'http_errors' => false,
		]);
	}

	/**
	 * Get latest COT Report
	 * 
	 * @return array
	 */
	public function latest()
	{
		$url = 'https://www.cftc.gov/dea/futures/deacmesf.htm';

		$response = $this->client->get($url);

+		return $this->parse((string) $response->getBody());
	}

+	/**
+	 * Parsing HTML response and get data
+	 *
+	 * @param string HTML Response from GuzzleHTTP
+	 * @return array
+	 */
+	protected function parse(string $html)
+	{
+		$lines = explode(PHP_EOL, $html);
+
+		$result = [];
+
+		foreach ($lines as $index => $line) {
+			// cari baris yang mengandung nama item
+			if (stripos($line, ' - CHICAGO MERCANTILE EXCHANGE') !== false) {
+				// ambil nama item sebelum string berikut
+				$nameLine = explode(' - CHICAGO MERCANTILE EXCHANGE', $line);
+
+				$name = $nameLine[0];
+
+				// ambil tanggal pada baris index + 1 dan pisahkan berdasarkan spasi
+				$dateLine = preg_split('/\s+/', trim($lines[$index + 1]));
+
+				$date = $date[5];
+
+				// ambil Open Interest pada baris index + 7 dan pisahkan berdasarkan spasi
+				$openInterestLine = preg_split('/\s+/', trim($lines[$index + 7]));
+
+				// ambil index column terakhir
+				$openInterest = end($openInterestLine);
+
+				// ambil Open Interest Total Change pada baris index + 11 dan pisahkan
+				$openInterestChangeLine = preg_split('/\s+/', trim($lines[$index + 7]));
+
+				//  ambil index column terakhir dan hilangkan akhiran ")"
+				$openInterestChange = rtrim(end($openInterestChangeLine), ')');
+
+				// ambil posisi terkini pada baris index + 9 dan pisahkan berdasarkan spasi
+				$current = preg_split('/\s+/', trim($lines[$index + 9]));
+
+				// ambil perubahan dari minggu lalu pada baris index + 12 dan pisahkan berdasarkan spasi
+				$changes = preg_split('/\s+/', trim($lines[$index + 12]));
+
+				// ambil Open Interest Percent Changes pada baris index + 15 dan pisahkan berdasarkan spasi
+				$percent = preg_split('/\s+/', trim($lines[$index + 15]));
+
+				$result[$name] = [
+					'name' => $name,
+					'date' => $date,
+					'current' => [
+						'non-commercial' => [
+							'long' => $current[0],
+							'short' => $current[1],
+							'spreads' => $current[2],
+						],
+						'commercial' => [
+							'long' => $current[3],
+							'short' => $current[4],
+						],
+					],
+					'changes' => [
+						'non-commercial' => [
+							'long' => $changes[0],
+							'short' => $changes[1],
+							'spreads' => $changes[2],
+						],
+						'commercial' => [
+							'long' => $changes[3],
+							'short' => $changes[4],
+						],
+					],
+					'open-interest' => [
+						'current' => $openInterest,
+						'change' => $openInterestChange,
+						'non-commercial' => [
+							'long' => $percent[0],
+							'short' => $percent[1],
+							'spreads' => $percent[2],
+						],
+						'commercial' => [
+							'long' => $percent[3],
+							'short' => $percent[4],
+						],
+					],
+				];
+			}
+		}
+
+		return $result;
+	}
}

Sekarang kita akan membuat metode untuk mengambil histori laporan dengan endpoint URL yang berbeda. Metode ini menerima argumen yaitu tanggal laporan dalam format m/d/y. Tambahkan kode berikut setelah metode latest().

<?php

namespace OmKoding\Cot;

use GuzzleHttp\Client;

class Report
{
	/**
	 * @var \GuzzleHttp\Client
	 */
	protected $client;

	/**
	 * Initiate class
	 */
	public function __construct()
	{
		$this->client = new Client([
			'http_errors' => false,
		]);
	}

	/**
	 * Get latest COT Report
	 * 
	 * @return array
	 */
	public function latest()
	{
		$url = 'https://www.cftc.gov/dea/futures/deacmesf.htm';

		$response = $this->client->get($url);

		return $this->parse((string) $response->getBody());
	}

+	/**
+	 * Get COT Report by date
+	 * 
+	 * @param string Date of report in m/d/y format
+	 * @return array
+	 */
+	public function byDate($date)
+	{
+		// ekstrak month, day, and year
+		list($month, $day, $year) = explode('/', $date);
+
+		$url = sprintf(
+           'https://www.cftc.gov/sites/default/files/files/dea/cotarchives/%s/futures/deacmesf%s%s%s.htm',
+           date('Y', strtotime($date)), // konversi menjadi tahun 4 digit
+           $month,
+           $day,
+           $year
+       );
+
+           $response = $this->client->get($url);
+
+		return $this->parse((string) $response->getBody());
+	}

	/**
	 * Parsing HTML response and get data
	 *
	 * @param string HTML Response from GuzzleHTTP
	 * @return array
	 */
	protected function parse(string $html)
	{
		$lines = explode(PHP_EOL, $html);

		$result = [];

		foreach ($lines as $index => $line) {
			// cari baris yang mengandung nama item
			if (stripos($line, ' - CHICAGO MERCANTILE EXCHANGE') !== false) {
				// ambil nama item sebelum string berikut
				$nameLine = explode(' - CHICAGO MERCANTILE EXCHANGE', $line);

				$name = $nameLine[0];

				// ambil tanggal pada baris index + 1 dan pisahkan berdasarkan spasi
				$dateLine = preg_split('/\s+/', trim($lines[$index + 1]));

				$date = $date[5];

				// ambil Open Interest pada baris index + 7 dan pisahkan berdasarkan spasi
				$openInterestLine = preg_split('/\s+/', trim($lines[$index + 7]));

				// ambil index column terakhir
				$openInterest = end($openInterestLine);

				// ambil Open Interest Total Change pada baris index + 11 dan pisahkan
				$openInterestChangeLine = preg_split('/\s+/', trim($lines[$index + 7]));

				//  ambil index column terakhir dan hilangkan akhiran ")"
				$openInterestChange = rtrim(end($openInterestChangeLine), ')');

				// ambil posisi terkini pada baris index + 9 dan pisahkan berdasarkan spasi
				$current = preg_split('/\s+/', trim($lines[$index + 9]));

				// ambil perubahan dari minggu lalu pada baris index + 12 dan pisahkan berdasarkan spasi
				$changes = preg_split('/\s+/', trim($lines[$index + 12]));

				// ambil Open Interest Percent Changes pada baris index + 15 dan pisahkan berdasarkan spasi
				$percent = preg_split('/\s+/', trim($lines[$index + 15]));

				$result[$name] = [
					'name' => $name,
					'date' => $date,
					'current' => [
						'non-commercial' => [
							'long' => $current[0],
							'short' => $current[1],
							'spreads' => $current[2],
						],
						'commercial' => [
							'long' => $current[3],
							'short' => $current[4],
						],
					],
					'changes' => [
						'non-commercial' => [
							'long' => $changes[0],
							'short' => $changes[1],
							'spreads' => $changes[2],
						],
						'commercial' => [
							'long' => $changes[3],
							'short' => $changes[4],
						],
					],
					'open-interest' => [
						'current' => $openInterest,
						'change' => $openInterestChange,
						'non-commercial' => [
							'long' => $percent[0],
							'short' => $percent[1],
							'spreads' => $percent[2],
						],
						'commercial' => [
							'long' => $percent[3],
							'short' => $percent[4],
						],
					],
				];
			}
		}

		return $result;
	}
}

Sekarang class kita telah memiliki 2 metode publik yang bisa dipanggil dari file lain atau proyek PHP lainnya.

<?php

// load composer bootstrap for autoload
require '../vendor/autoload.php';

use OmKoding\Cot\Report;

// get latest report
$reports = (new Report)->latest();

//  get report by specific date
$reports = (new Report)->byDate('01/17/17');

Kode di atas tentu saja masih jauh dari sempurna, masih banyak hal yang dapat kita tambahkan agar dapat lebih baik lagi, misalkan:

  • menambahkan error handler pada saat melakukan membuka laman report
  • validasi apabila user memberikan format tanggal yang salah
  • mengambil report berdasarkan nama item tertentu
  • membuat class yang berisi daftar nama item

Berikut adalah full file hasil akhir kita sebagai referensi.

<?php
namespace OmKoding\Cot;
use GuzzleHttp\Client;
class Report
{
/**
* @var \GuzzleHttp\Client
*/
protected $client;
/**
* Initiate class
*/
public function __construct()
{
$this->client = new Client([
'http_errors' => false,
]);
}
/**
* Get latest COT Report
*
* @return array
*/
public function latest()
{
$url = 'https://www.cftc.gov/dea/futures/deacmesf.htm';
$response = $this->client->get($url);
return $this->parse((string) $response->getBody());
}
/**
* Get COT Report by date
*
* @param string Date of report in m/d/y format
* @return array
*/
public function byDate($date)
{
// ekstrak month, day, and year
list($month, $day, $year) = explode('/', $date);
$url = sprintf(
'https://www.cftc.gov/sites/default/files/files/dea/cotarchives/%s/futures/deacmesf%s%s%s.htm',
date('Y', strtotime($date)), // konversi menjadi tahun 4 digit
$month,
$day,
$year
);
$response = $this->client->get($url);
return $this->parse((string) $response->getBody());
}
/**
* Parsing HTML response and get data
*
* @param string HTML Response from GuzzleHTTP
* @return array
*/
protected function parse(string $html)
{
$lines = explode(PHP_EOL, $html);
$result = [];
foreach ($lines as $index => $line) {
// cari baris yang mengandung nama item
if (stripos($line, ' - CHICAGO MERCANTILE EXCHANGE') !== false) {
// ambil nama item sebelum string berikut
$nameLine = explode(' - CHICAGO MERCANTILE EXCHANGE', $line);
$name = $nameLine[0];
// ambil tanggal pada baris index + 1 dan pisahkan berdasarkan spasi
$dateLine = preg_split('/\s+/', trim($lines[$index + 1]));
$date = $date[5];
// ambil Open Interest pada baris index + 7 dan pisahkan berdasarkan spasi
$openInterestLine = preg_split('/\s+/', trim($lines[$index + 7]));
// ambil index column terakhir
$openInterest = end($openInterestLine);
// ambil Open Interest Total Change pada baris index + 11 dan pisahkan
$openInterestChangeLine = preg_split('/\s+/', trim($lines[$index + 7]));
// ambil index column terakhir dan hilangkan akhiran ")"
$openInterestChange = rtrim(end($openInterestChangeLine), ')');
// ambil posisi terkini pada baris index + 9 dan pisahkan berdasarkan spasi
$current = preg_split('/\s+/', trim($lines[$index + 9]));
// ambil perubahan dari minggu lalu pada baris index + 12 dan pisahkan berdasarkan spasi
$changes = preg_split('/\s+/', trim($lines[$index + 12]));
// ambil Open Interest Percent Changes pada baris index + 15 dan pisahkan berdasarkan spasi
$percent = preg_split('/\s+/', trim($lines[$index + 15]));
$result[$name] = [
'name' => $name,
'date' => $date,
'current' => [
'non-commercial' => [
'long' => $current[0],
'short' => $current[1],
'spreads' => $current[2],
],
'commercial' => [
'long' => $current[3],
'short' => $current[4],
],
],
'changes' => [
'non-commercial' => [
'long' => $changes[0],
'short' => $changes[1],
'spreads' => $changes[2],
],
'commercial' => [
'long' => $changes[3],
'short' => $changes[4],
],
],
'open-interest' => [
'current' => $openInterest,
'change' => $openInterestChange,
'non-commercial' => [
'long' => $percent[0],
'short' => $percent[1],
'spreads' => $percent[2],
],
'commercial' => [
'long' => $percent[3],
'short' => $percent[4],
],
],
];
}
}
return $result;
}
}
view raw Report.php hosted with ❤ by GitHub

Membuat PHPUnit Test

Keuntungan membuat unit test pada package anda adalah memastikan bahwa fungsi yang ada dapat berjalan sesuai harapan. Pada konsep Continuous Integration / Continuous Delivery, peran unit test menjadi sangat penting, karena tahapan ini yang menjaga aplikasi kita dapat berjalan sebagaimana mestinya ketika dilakukan perubahan kode.

Dengan adanya unit test juga membuat developer lain merasa percaya diri untuk menggunakan package anda sehingga jumlah instalasi akan bertambah.

Sekarang kita akan menambahkan library phpunit/phpunit sebagai dependasi tapi hanya ketika dalam environment dev. Dengan kata lain ketika pada environment production, maka jangan install library ini. Jalankan perintah berikut pada terminal direktori workspace (perhatikan flag --dev).

cd ~/dev/cot-report-parser
composer require --dev phpunit/phpunit

Mulailah dengan membuat folder tests pada workspace. Maka susunan folder workspace kita sekarang sebagai berikut.

~/dev/cot-report-parser
~/dev/cot-report-parser/src
~/dev/cot-report-parser/tests

Buat file CotTest.php pada folder tests tersebut. Metode yang ingin kita test adalah latest() dan byDate(). Secara sederhana kita hanya ingin mengecek bahwa hasil metode tersebut bukanlah null. Salin kode berikut ke dalam file yang baru kita buat.

<?php

namespace OmKoding\Cot\Tests;

use OmKoding\Cot\Report;
use PHPUnit\Framework\TestCase;

class CotTest extends TestCase
{
	public function testReportByDate(): void
	{
		$reports = (new Report)->byDate('01/17/17');

		$this->assertNotNull($reports);
	}

	public function testReportLatest(): void
	{
		$reports = (new Report)->latest();

		$this->assertNotNull($reports);
	}
}

Lalu buatlah file phpunit.xml pada folder workspace dan salin kode berikut. File ini adalah konfigurasi untuk memberi tahu phpunit file mana yang harus dijalankan ketika test berlangsung.

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests</directory>
        </testsuite>
    </testsuites>
</phpunit>

Langkah terakhir adalah jalankan perintah berikut dari terminal workspace. Pastikan hasilnya adalah OK dan hijau semua seperti berikut.

./vendor/bin/phpunit
phpunit untuk testing composer package

Publikasi Package ke github.com

Kode anda harus dipublikasikan via github agar nantinya dapat dibaca langsung oleh packagist. Penggunaan github untuk tracking perubahan kode anda juga sangat direkomendasikan. Apabila belum mempunyai akun github silahkan mendaftar terlebih dahulu.

Buatlah repositori baru melalui menu + di kanan atas atau buka laman https://github.com/new

buat repositori baru pada github.com

Lalu isi nama repositori sesuai keinginan anda dan klik tombol hijau bertuliskan Create Repository.

isi nama repositori github

Selanjutnya ikuti perintah untuk menginisiasi git pada direktori workspace anda. Jalankan perintah sesuai pada halaman github anda.

setup git pada direktori workspace

Setelah proses selesai, maka pada terminal akan muncul pesan kurang lebih sebagai berikut.

$ git push -u origin master
Username for 'https://github.com': omkoding
Password for 'https://[email protected]': 
Counting objects: 27, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (23/23), done.
Writing objects: 100% (27/27), 5.94 KiB | 2.97 MiB/s, done.
Total 27 (delta 10), reused 0 (delta 0)
remote: Resolving deltas: 100% (10/10), completed with 9 local objects.
To https://github.com/omkoding/cot-report.git
   4ec2af6..fe987a4  HEAD -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

Selanjutnya adalah proses tagging menjadi v1.0 sebagai langkah terakhir. Fungsi tagging ini adalah untuk memberitahu composer bahwa package anda mempunyai stable version. Jalankan perintah berikut dari terminal direktori workspace anda.

git tag -a v1.0 -m "Bump version to v1.0"
git push -u origin v1.0

Publikasi Package ke packagist.org

Agar composer dapat mengenali package anda maka anda harus mempublikasikan via packagist.org. Buatlah akun terlebih dahulu (direkomendasikan login via Github) kemudian klik menu Submit di atas atau via laman https://packagist.org/packages/submit

submit github repository ke packagist.org

Masukkan URL repositori Github anda, klik Check dan ikuti proses hingga selesai. Proses ini akan memakan waktu kurang dari 5 menit hingga composer dapat mengenali package anda.

Setelah proses selesai maka anda dapat menggunakannya via composer dengan cara menjalankan perintah berikut

composer require omkoding/cot

Contoh Penggunaan Package

Package ini telah digunakan juga sebagai dependasi plugin wordpress dimana hasilnya dapat dilihat langsung pada laman Analisa Cot Report.

Referensi:
github.com/omkoding/cot-report-parser
www.cftc.gov/dea/futures/deacmesf.htm