Yii2: Publish Asset Tanpa Hash Folder

Tags

,

Secara default, Yii2 akan mempublis asset-asset ke folder @web dengan menghash(mengencript) nama foldernya. Kita bisa mengubah behavior ini yaitu mempertahankan nama asli dari folder asset sebelum dipublis. Caranya dengan mengcustom fungsi hash bawaan assetManager.
Berikut caranya. Kita buat class behavior, lalu kita attach ke komponen assetManager

<?php
namespace app\classes;
use Yii;
use yii\base\Behavior;
use yii\web\AssetManager;
/**
* Description of AssetPublishBehavior
*
* @author Misbahul D Munir <[email protected]>
* @since 1.0
*/
class AssetPublishBehavior extends Behavior
{
/**
* sesuaikan kebutuhan
*/
public $maps = [
'@node_modules' => 'nm',
'@vendor' => 'v',
'@bower' => 'b',
'@npm' => 'nm',
'@app' => '',
];
protected $mapDirs = [];
public function init()
{
foreach ($this->maps as $path => $to) {
$path = rtrim(Yii::getAlias($path), '/') . '/';
$this->mapDirs[$path] = trim($to, '/');
}
krsort($this->mapDirs);
}
/**
*
* @param AssetManager $owner
*/
public function attach($owner)
{
parent::attach($owner);
$owner->hashCallback = [$this, 'hash'];
}
public function hash($path)
{
foreach ($this->mapDirs as $key => $to) {
if (strpos($path, $key) === 0) {
$subpath = substr($path, strlen($key));
return $to ? "$to/$subpath" : $subpath;
}
}
return ltrim($path, '/');
}
}
return [
'components' => [
'assetManager' => [
'as publish' => 'app\classes\AssetPublishBehavior'
]
],
];
view raw config.php hosted with ❤ by GitHub

Yii2: Update Baru Yii2-Autonumber

Mulai versi 1.5, extension yii2-autonumber memperkenalkan sintak baru untuk format number. Beberapa peningkatan pada versi yang sekarang antara lain:

  • Evaluasi date format secara langsung.
    Di versi sebelumnya, untuk menyisipkan tanggal harus dibuat diluar format number. Semua nilai di dalam {} akan dievaluasi sebagai date.
// versi < 1.5
['number', 'autonumber', 'format' => function(){
    $date = date('Y/m');
    return "INV/$date/?";
}],

// versi 1.5
['number', 'autonumber', 'format' => 'INV/{Y/m}/?']
  • Jumlah digit diwakili oleh banyaknya karakter ?.
    Di versi sebelumnya jumlah digit dalam autonumber ditentukan oleh property digit. Versi sekarang jumlah digit adalah banyaknya ? dalam format. Jadi jika ingin membuat 4 digit autonumber, maka harus pakai 4 ?.
// versi < 1.5
['number', 'autonumber', 'format' => function(){
    $date = date('Y/m');
    return "INV/$date/?";
}, 'digit' => 4],

// versi 1.5
['number', 'autonumber', 'format' => 'INV/{Y/m}/?-???']
// akan menggenerate nilai INV/2019/10/0-001

Kita juga bisa menyisipkan karakter lain di antara ?. Misal jika formatnya adalah ?-??-??? maka angka yg terbentuk adalah 0-00-001.

  • Bisa generate alfanumerik.
    Alfanumerik adalah angka dengan basis bilangan 36. Jadi setelah nilai 9 bukannya 10 tetapi A, B .. Z baru kemudian `10′.

  • Class Autonumber bisa dipakai langsung tanpa validator atau behavior. Kita bisa menggunakan Autonumber secara langsung di controller.

public function actionCreate()
{
    $model = new Invoice();
    $model->load(Yii::$app->request->post());
    $model->number = Autonumber::generate('INV/{Y/m}/?-???');
    ...
}

Yii2: Membuat Aplikasi Scheduler

Tags

, , , ,

Secara tradisional, untuk membuat aplikasi skeduler, kita mungkin harus membuat cron untuk setiap task yang akan kita jalankan. Ini bisa jadi sangat menyusahkan karena kita tidak lagi memiliki kontrol terhadap dan juga kita harus konek SSH ke server untuk menambah atau mengubah cron kita.

Di Yii2 kita bisa memanage aplikasi skeduler dengan sedikit lebih mudah. Caranya

Install deesoft/yii2-console.

Tambahkan di composer.json

"deesoft/yii2-console": "~1.0"

atau dari command line

composer require deesoft/yii2-console

Konfigurasi aplikasi console

Di config untuk aplikasi console, tambahkan

'controllerMap' => [
    'scheduler' => [
        'class' => 'dee\console\SchedulerController',
        'commands' => [
            // berisi entri task skeduler
            // 'my-command/task' => '@daily',
        ]
    ]
]

Menambahkan command scheduler ke cron.

Tambahkan entri berikut ke cron

* * * * * php /path/to/aplikasi/yii scheduler >> /dev/null 2>&1

Entri ini akan dieksekusi tiap menit yang akan memanage skeduler kita.

Membuat taks

Membuat taks adalah sama seperti membuat aplikasi console biasa. Kita buat controller yang diturunkan dari yii\console\Controller lalu definisikan action-nya. Selanjutnya adalah mendaftarkan task tersebut ke daftar commands dari scheduler.

        'commands' => [
            'command1/task' => '*/5 * * * *', // tiap 5 menit
            'command2/task' => '0 0 * * 0', // tiap 1 minggu sekali
            'command3/task' => '0 0,12 * * *', // sehari 2 kali
            // dan seterusnya
        ]

Awesome Yii2: Memanfaatkan ORM Yii Pada Aplikasi CI

Tags

, , ,

Lanjutan dari tulisan sebelumnya Use Yii as Library. Selain sebagai framework, Yii juga bisa dimanfaatkan sebagai library yaitu dengan memanfaatkan sebagian saja fitur-fitur Yii pada aplikasi atau framework lain.

CodeIgniter adalah framework PHP yang didesain untuk memiliki ukuran yang kecil. CI dibuat untuk para developer yang membutuhkan tool yang sederhana serta elegan. Tidak seperti framework-framework terbaru yang hadir dengan fitur ORM (Active Record), CI absen dalam fitur ini. Karena itu jika ingin memanfaatkan ORM, kita perlu mengambilnya dari library lain.

Sebenarnya, selain Yii, ada beberapa library ORM lain yang lebih terkenal seperti doctrine dan eloquent. Tetapi kita gunakan Yii karena Fiturnya yang lengkap dan performanya yang bagus. Berikut langkah-langkahnya.

Install Yii.

Ada 2 cara untuk install Yii, yaitu dengan composer atau download archive. Untuk install lewat composer, cukup tambahkan required yiisoft/yii2 do composer.json lalu composer update. Untuk install dari archive, silakan download Yii dari https://github.com/yiisoft/yii2-framework/archive/2.0.10.zip.
Continue reading

Awesome Yii2: Use Framework as Library

Tags

, ,

Kita semua mungkin mengenal Yii sebagai framework yang canggih, lengkap dan menganut pola MVC. Tetapi tahukah Anda bahwa Yii2 sebenarnya bisa dipakai tanpa harus mengikuti pola MVC-nya. Yups, kita bisa memakai Yii2, memanfaatkan fitur-fiturnya tanpa harus membuat controller view khusus untuk itu. Kita bisa menggunakan cache, AR, DB conncetion, validator dan lain-lain dalam kodingan yang sudah ada atau bersama framework lain sebagai library.

Cara melakukannya juga sangat mudah. Kita hanya perlu meng-include satu file yaitu Yii.php. Setelah itu kita bebas memanfaatkan fitur-fitur Yii yang ada.
Code berikut adalah contohnya.

require 'yii2/Yii.php';

$db = new yii\db\Connection([
    'dsn' => 'sqlite:' . __DIR__ . '/data.sqlite',
    ]);

// create table if not exists
if ($db->getTableSchema('test') === null) {
    $db->createCommand()->createTable('test', [
        'id' => 'pk',
        'text' => 'string(100)'
    ])->execute();
    echo "Created test table...\n\n";
}

// insert data
$db->createCommand()->batchInsert('test', ['text'], [
    ['value1'],
    ['value2'],
    ['value3'],
])->execute();
echo "Insert 3 rows to table test...\n\n";

// querying data
$rows = (new yii\db\Query())
    ->from('test')
    ->all($db);

\yii\helpers\VarDumper::dump($rows);
echo "\n";

PS: Karena kita tidak meng-instansiasi class Application, maka kita tidak bisa memanggil property Yii::$app. Beberapa component harus dibuat manual.

screenshot-from-2016-11-09-13-09-27

Yii2: Contoh Membuat Command Sederhana

Tags

, , ,

Kali ini kita akan iseng-iseng membuat command sederhana. Berikut codenya

namespace app\commands;

use yii\helpers\Console;

/**
 * Description of InspireController
 *
 * @author Misbahul D Munir <[email protected]>
 * @since 1.0
 */
class InspireController extends \yii\console\Controller
{
    protected $quotes = [
        'When there is no desire, all things are at peace. - Laozi',
        'Simplicity is the ultimate sophistication. - Leonardo da Vinci',
        'Simplicity is the essence of happiness. - Cedric Bledsoe',
        'Smile, breathe, and go slowly. - Thich Nhat Hanh',
        'Simplicity is an acquired taste. - Katharine Gerould',
        'Well begun is half done. - Aristotle',
        'He who is contented is rich. - Laozi',
        'Very little is needed to make a happy life. - Marcus Antoninus',
    ];

    public function actionIndex()
    {
        $quote = $this->quotes[array_rand($this->quotes)];
        $this->stdout("\n$quote\n\n", Console::FG_YELLOW, Console::BOLD);
    }
}

Simpan dengan nama file InspireController.php. Ubah folder dan namespace sesuai dengan struktur aplikasi. Untuk template basic, namespacenya adalah app\commands. Untuk template advanced, namespacenya adalah console\controllers.

Cara menjalankan command tersebut adalah, dari command line

$ php yii inspire

PHP String

Tags

,

Sekali-kali kita bahas sesuatu yang lebih sederhana, lebih basik 😀

String adalah rangkaian dari karakter di mana karakter yang dimaksud adalah satu byte. Ini berarti string hanya merupakan himpunan dari 256 set karakter, karena secara default, PHP tidak mendukung unicode. Panjang string yang diizinkan di PHP dapat mencapai 2GB (2147483647 bytes maximum).

Ada 4 cara dalam mendefinisikan string di PHP, yaitu

Single Quote

Ini adalah cara paling sederhana. String didefinisikan dengan mengapit serangkaian karakter dalam single quote (‘). Contoh:

$str1 = 'd426 m8647';
$str2 = '$\anb
\n $str1 ';

Dengan single quote, string akan disimpan apa adanya tanpa di-expand lebih dahulu. Termasuk di antaranya escape caracter dan variabel.

$str1 = 'abcde';
$str2 = '$str1 \n tidak dikonversi jadi newline';//$str1 \n tidak dikonversi jadi newline
$str3 = 'untuk petik tunggal \' harus pake backslash';

Terkecuali petik tunggal (‘), untuk menyimpan ' maka harus didahului dengan .

Double Quote.

Berbeda dengan single quote. Kalau double quote, nilai string akan di-expand terlebih dahulu sebelum disimpan. Ini artinya jika ada escape caracther, akan dievaluasi lebih dahulu. Termasuk juga jika ada variabel di dalamnya

$str1 = "abcd"; // abcd
$str2 = "$str1, \n dan \t akan diexpand"; // abcd, {NEWLINE} dan {TAB} akan diexpand
$str3 = "\$str1 dan $str1"; // $str1 dan abcd

Agar variabel ditampilkan apa adanya, maka sebelum $ harus ditambahkan karakter backslash.

Heredoc syntax

Baca lanjutannya sendiri di sini, lagi males ngetik :D.

Yii2: Database View Emulator

Tags

, , ,

Secara gampangnya, view adalah query yang disimpan di database. Querynya bisa berupa query dari beberapa tabel atau yang mengandung fungsi agregat. Nantinya view ini akan dapat kita akses seolah-olah sebagai sebuah tabel sungguhan. Termasuk juga membuat ActiveRecord dari view tersebut.

Di sini kita tidak sedang membuat view di database. Tetapi kita akan membuat emulasinya di Yii sebagai ActiveRecord. Nantinya AR tersebut dapat kita relasikan dengan AR sungguhan. Berikut adalah kelas dasarnya.
Continue reading

Yii2: Facade Emulator

Tags

, ,

Sudah lama gak bikin artikel. Kali ini kita coba sesuatu yang ringan.

Kita akan memcoba membuat sintak yang ringkas untuk memanggil komponen-komponen punyanya aplikasi. Langsung saja kita buat base class-nya


<?php
namespace app\classes;
/**
* Description of Db
*
* @author Misbahul D Munir <[email protected]>
* @since 1.0
*/
class Db extends Facade
{
}

view raw

Db.php

hosted with ❤ by GitHub


<?php
namespace app\classes;
use yii\helpers\StringHelper;
/**
* Description of Facade
*
* @author Misbahul D Munir <[email protected]>
* @since 1.0
*/
class Facade
{
private static $_providers = [];
/**
* @return \yii\base\Object
*/
protected static function provider()
{
return \Yii::$app->get(lcfirst(StringHelper::basename(get_called_class())));
}
public static function __callStatic($name, $arguments)
{
$instance = static::instance();
return call_user_func_array([$instance, $name], $arguments);
}
public static function instance()
{
$class = get_called_class();
if (isset(self::$_providers[$class])) {
return self::$_providers[$class];
} else {
return self::$_providers[$class] = static::provider();
}
}
}

view raw

Facade.php

hosted with ❤ by GitHub

Untuk penggunaannya

use app\classes\Db;

Db::createCommand($sql)->execute();
// sama seperti Yii::$app->db->createCommand($sql)->execute();

Untuk komponen yang lain, kita buat dengan cara yg sama

namespace app\classes;

class Cache extends Facade
{

}

Cara menggunakannya,

use app\classes\Cache;


if(($value = Cache::get($key)) === false){
    $value = getSomethingValue();
    Cache::set($key, $value);
}

Semoga bermanfaat.

PS: Sintak ini punya satu kekurangan fatal. No autocompletion :D.

Yii2: Mencegah Dobel Login

Berikut ini adalah cara mudah untuk mencegah user login lebih dari sekali. Kita akan membuatnya sebagai behavior sehinggah bisa dipakai di banyak aplikasi. Sebelum kita mulai, ada beberapa prasarat yang harus dipenuhi.
1. Komponen session harus diset ke custom storage. Salah satu contohnya adalah DbSession.
2. Komponen cache juga harus aktif dan persisten. Untuk alasan kemudahan aja sih. Jadi kita simpan session id dari user di cache.

Jika kedua syarat tersebut sudah terpenuhi. Kita melangkah ke tahap berikutnya yaitu membuat behaviornya. Berikut adalah source-nya


<?php
namespace app\classes;
use Yii;
use yii\base\Behavior;
use yii\web\User;
use yii\web\UserEvent;
use yii\di\Instance;
use yii\caching\Cache;
use yii\base\NotSupportedException;
use yii\web\ForbiddenHttpException;
use yii\web\Cookie;
/**
* Description of LoginOnce
*
* @property User $owner
*
* @author Misbahul D Munir <[email protected]>
* @since 1.0
*/
class LoginOnce extends Behavior
{
/**
*
* @var Cache
*/
public $cache = 'cache';
/**
*
* @var boolean
*/
public $throwExeption = true;
/**
*
* @var string
*/
public $cookieKey = '_d_sessid';
/**
*
* @var boolean
*/
public $kickLogedUser = false;
/**
* @inheritdoc
*/
public function init()
{
$this->cache = Instance::ensure($this->cache, Cache::className());
}
/**
* @inheritdoc
*/
public function events()
{
return[
User::EVENT_BEFORE_LOGIN => 'beforeLogin',
User::EVENT_AFTER_LOGIN => 'afterLogin',
];
}
/**
*
* @param UserEvent $event
*/
public function beforeLogin($event)
{
$user_id = $event->identity->getId();
if (($sess_id = $this->cache->get([__CLASS__, $user_id])) !== false) {
if (Yii::$app->getRequest()->getCookies()->getValue($this->cookieKey) == $sess_id) {
// kalau dari browser yang sama, langsung login
return;
}
$session = Yii::$app->getSession();
if ($this->kickLogedUser) {
$session->destroySession($sess_id);
} elseif ($session->getUseCustomStorage() && $session->readSession($sess_id)) {
if ($this->throwExeption && !$event->cookieBased) {
throw new ForbiddenHttpException('Not allowed login more than one');
} else {
$event->isValid = false;
}
} elseif (!$session->getUseCustomStorage()) {
throw new NotSupportedException('Session not supported');
}
}
}
/**
*
* @param UserEvent $event
*/
public function afterLogin($event)
{
$user_id = $event->identity->getId();
$sess_id = Yii::$app->getSession()->getId();
$this->cache->set([__CLASS__, $user_id], $sess_id);
Yii::$app->getResponse()->getCookies()->add(new Cookie([
'name' => $this->cookieKey,
'value' => $sess_id,
'expire' => time() + 24 * 3600,
]));
}
}

view raw

LoginOnce.php

hosted with ❤ by GitHub

Jika sudah, maka berikutnya kita mengattach behavior tersebut ke komponen user. Kita set di konfig

    'components' => [
        'user' => [
            'identityClass' => 'app\models\ar\User',
            'loginUrl' => ['user/login'],
            'enableAutoLogin' => true,
            'as loginOnce' => [  // <- bagian ini yg penting
                'class' => 'app\classes\LoginOnce', 
            ]
        ],

Selesai.
User kita tidak akan diperbolehkan lagi login dua kali dari browser yang berbeda.

Catatan: Menutup browser tidak serta merta dianggap sebagai logout. Logout hanya dikira ketika session sudah timeout atau ketika kita mengklik tombol logout.

Untuk demonya silakan login di http://goo.gl/1u0nZ0. Jika belum punya user, silakan lakukan sign up lebih dahulu.

Design a site like this with WordPress.com
Get started