Ads

Ads

Translate

Tuesday, 29 October 2013

MVC Dalam Delphi Programming II – Meniru Konsep CI


CATATAN: Jangan menggunakan variabel bertipe interface untuk menyimpan data bertipe TObject. Bikin Error!
CI atau Code Igniter mempunyai konsep mvc yang menarik. Dibanding Tulisan saya sebelumnya, model mvc yang ditawarkan oleh CIebih elegan. Dibandingkan konsep MVC yang saya gambarkan dulu, yang hanya memanggil/memanfaatkan prosedur konsep MVC CI memanfaatkan kelas. Dalam tutorial awal CI kita lihat contoh contoh kodingnya:
Controller:

View
Beberapa konsep yang perlu diperhatikan disini:
1. Kemunculan View diatur oleh controller
2. Apa (data apa) yang ditampilkan View  di-supply oleh controller. Dalam definisi lengkap MVC, controller mendapatkan data dari Model (dapat berupa perintah sql dalam database).
3. Data yang dipertukarkan antara View dengan controller mempunyai tipe data generik, dalam bentuk list.
Konsep ini dapat diterapkan diterjemahkan di dalam delphi sebagai berikut:
- Controller seharusnya berupa Class
- Data harus bertipe generik. Karena  Delphi strong type, hal tersebut dapat diakali dengan menggunakan data yang bertipe data objek, dan mempunyai property yang memungkinkan diakses dalam tipe data apapun.
Saya menerjemahkan model MVC code igniter tersebut di atas menjadi sebagai berikut:
unit con_canvaser;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Forms,
Dialogs, Controls, TypInfo, SDKHelper;
type
TErrMsg = string;
IMvcData = interface(IInterface)
['{7293B5D3-FC1F-4DB5-B764-3F94AD2427C8}']
procedure SetValueStr(const Name: string; const Value: string);
procedure SetValueInt(const Name: string; const Value: Integer);
procedure SetValueDouble(const Name: string; const Value: Double);
procedure SetValueCurrency(const Name: string; const Value: Currency);
procedure SetValueVar(const Name: string; const Value: Variant);
procedure SetValueDate(const Name: string; const Value: TDateTime);
procedure SetValueObj(const Name: string; const Value: TObject);
function GetValueStr(const Name: string): string;
function GetValueInt(const Name: string): Integer;
function GetValueDouble(const Name: string): Double;
function GetValueCurrency(const Name: string): Currency;
function GetValueVar(const Name: string): Variant;
function GetValueDate(const Name: string): TDateTime;
function GetValueObj(const Name: string): TObject;
property ValueStr[const Name: string]: string read GetValueStr Write SetValueStr;
property ValueInt[const Name: string]: Integer read GetValueInt Write SetValueInt;
property ValueDouble[const Name: string]: Double read GetValueDouble Write SetValueDouble;
property ValueCurrency[const Name: string]: Currency read GetValueCurrency Write SetValueCurrency;
property ValueVar[const Name: string]: Variant read GetValueVar Write SetValueVar;
property ValueDate[const Name: string]: TDateTime read GetValueDate Write SetValueDate;
property ValueObj[const Name: string]: TObject read GetValueObj Write SetValueObj;
end;
TDateTimeVar = class(TInterfacedObject,IInterface)
private
FData: TDateTime;
public
constructor Create(InitValue: TDateTime);
property Data: TDateTime read FData write FData;
end;
TMvcData = class(TInterfacedObject, IMvcData)
private
FList: TStringList;
public
constructor Create;
destructor Destroy; override;
procedure SetValueStr(const Name: string; const Value: string);
procedure SetValueInt(const Name: string; const Value: Integer);
procedure SetValueDouble(const Name: string; const Value: Double);
procedure SetValueCurrency(const Name: string; const Value: Currency);
procedure SetValueVar(const Name: string; const Value: Variant);
procedure SetValueDate(const Name: string; const Value: TDateTime);
procedure SetValueObj(const Name: string; const Value: TObject);
function GetValueStr(const Name: string): string;
function GetValueInt(const Name: string): Integer;
function GetValueDouble(const Name: string): Double;
function GetValueCurrency(const Name: string): Currency;
function GetValueVar(const Name: string): Variant;
function GetValueDate(const Name: string): TDateTime;
function GetValueObj(const Name: string): TObject;
property ValueStr[const Name: string]: string read GetValueStr Write SetValueStr;
property ValueInt[const Name: string]: Integer read GetValueInt Write SetValueInt;
property ValueDouble[const Name: string]: Double read GetValueDouble Write SetValueDouble;
property ValueCurrency[const Name: string]: Currency read GetValueCurrency Write SetValueCurrency;
property ValueVar[const Name: string]: Variant read GetValueVar Write SetValueVar;
property ValueDate[const Name: string]: TDateTime read GetValueDate Write SetValueDate;
property ValueObj[const Name: string]: TObject read GetValueObj Write SetValueObj;
end;
IView = interface(IInterface)
['{8318E550-2DC0-4A2A-B45C-C8A636D24702}']
procedure GetInitData(MvcData: IMvcData);
function GetOutputData: IMvcData;
end;
IController = interface
['{4F6CCA74-90BD-46EF-8507-26A1C9F1FDAF}']
procedure DoResponse;
function GetData: IMvcData;
procedure SetData(Data: IMvcData);
property Data: IMvcData read GetData write SetData;
end;
TController = class(TInterfacedObject, IController)
private
FMvcData: IMvcData;
public
procedure DoResponse;
function GetData: IMvcData;
procedure SetData(Data: IMvcData);
property Data: IMvcData read GetData write SetData;
constructor Create; virtual;
end;
{ Canvaser Controller
Dengan ini selurut tabel-tabel rujukan combobox diloag
}
TCanvaserController = class(TController)
{daftar yang diload di sini adalah untuk mengisi combo box,
cuma  ada dua field sebagai key dan lookup value saja}
Procedure ReloadDummy;
procedure ReloadDaftarKota;
procedure ReloadDaftarPropinsi;
procedure ReloadDaftarSales;
procedure ReloadDaftarStatus;
procedure ReloadDaftarJenisTransaksi;
constructor Create; override;  {reload All combo reference}
end;
TPenjualanController = class(TCanvaserController)
constructor Create; override;
end;
TMasterOutletController = class(TCanvaserController)
function IsOutletExist: Boolean;
function IsBlokir: Boolean;
function SetBlokir: TErrMsg;  //return ” if success, otherwise false!
function SetUnBlokir: TErrMsg;
function Delete: TErrMsg;
function PostUpdated: TErrMsg;
function PostInserted(var NewCustId: string): TErrMsg;
constructor Create; override;
end;
{
TMasterSalesController = class(TCanvaserController)
function IsOutletExist: Boolean;
function IsBlokir: Boolean;
function SetBlokir: TErrMsg;  //return ” if success, otherwise false!
function SetUnBlokir: TErrMsg;
function Delete: TErrMsg;
function PostUpdated: TErrMsg;
function PostInserted: TErrMsg;
constructor Create; override;
end;
}
//IDataset harus punya 2 field, satu bernama Key satu bernama Value , sementara ini berlaku untuk Key Integer dan Value String
procedure InitList(Source: IDataset; DestList: TStringList);
//mendapat index dari keyval list
function GetMvcListIndex(Items: TStrings; KeyVal: string): Integer;
//mem-free object-object List
procedure FreeOwnObjets(List: TStringList);
{General Dialogs}
function MsgDlgConfirm(Msg: string): Boolean;
procedure MsgDlgInformation(Msg: string);
procedure MsgDlgWarning(Msg: string);
procedure MsgDlgError(Msg: string);
{General View Fungtions}
procedure DisableControls(Controls: array of TControl);
procedure EnableControls(Controls: array of TControl);
{mencek apakah input terdapat karakter yang dilarang}
function Validate(Controls: array of TControl; PropName: string): Boolean;
implementation
uses mod_canvaser;
{ TMvcData }
constructor TMvcData.Create;
begin
FList:= TStringList.Create;
end;
destructor TMvcData.Destroy;
begin
FreeOwnObjets(FList);
FreeAndNil(FList);
inherited;
end;
function TMvcData.GetValueInt(const Name: string): Integer;
begin
if FList.Values[Name]<>” then
Result:= StrToInt(FList.Values[Name])
else
Result:= -1;
end;
function TMvcData.GetValueStr(const Name: string): string;
begin
Result:= FList.Values[Name];
end;
function TMvcData.GetValueObj(const Name: string): TObject;
var Index: Integer;
begin
Index:= ValueInt[Name+'INDEX'];
if Index>0 then begin
ShowMessage(‘[GET] Found Obj Name = ‘ + Name);
Result:= FList.Objects[Index];
end else begin
ShowMessage(‘[GET] NOT Found Obj Name = ‘ + Name);
Result:= nil;
end;
end;
function TMvcData.GetValueVar(const Name: string): Variant;
var Index: Integer;
begin
Result:= Null;
if FList.Find(Name,Index) then
Result:= FList.Values[Name];
end;
function TMvcData.GetValueCurrency(const Name: string): Currency;
begin
Result:=0.0;
if Trim(FList.Values[Name])<>” then
Result:= StrToCurr(FList.Values[Name]);
end;
function TMvcData.GetValueDate(const Name: string): TDateTime;
var
Index: Integer;
begin
if FList.Find(Name,Index) then begin
Result:= TDateTimeVar(FList.Objects[Index]).Data;
end;
end;
function TMvcData.GetValueDouble(const Name: string): Double;
var
Index: Integer;
Value: string;
begin
Result:= 0.0;
if FList.Find(Name,Index) then begin
Value:= FList.Values[Name];
if Trim(Value)<>” then
Result:= StrToFloat(Value);
end;
end;
procedure TMvcData.SetValueInt(const Name: string; const Value: Integer);
begin
FList.Values[Name]:= IntToStr(Value);
end;
procedure TMvcData.SetValueStr(const Name, Value: string);
begin
FList.Values[Name]:= Value;
end;
procedure TMvcData.SetValueObj(const Name: string; const Value: TObject);
var
Index: Integer;
begin
Index:= ValueInt[Name+'INDEX'];
if Index>0 then begin
ShowMessage(‘[SET] Found Obj Name = ‘ + Name);
FList.Objects[Index].Free;
FList.Objects[Index]:= Value;
end else begin
ShowMessage(‘[SET] NOT Found Obj Name = ‘ + Name);
ValueInt[Name+'INDEX']:=  FList.AddObject(Name, Value);
end;
end;
procedure TMvcData.SetValueVar(const Name: string; const Value: Variant);
begin
FList.Values[Name]:= VarToStr(Value);
end;
procedure TMvcData.SetValueCurrency(const Name: string; const Value: Currency);
begin
FList.Values[Name]:= CurrToStr(Value);
end;
procedure TMvcData.SetValueDate(const Name: string; const Value: TDateTime);
var
Index: Integer;
begin
if FList.Find(Name,Index) then
TDateTimeVar(FList.Objects[Index]).Data:= Value
else
FList.AddObject(Name,TDateTimeVar.Create(Value));
end;
procedure TMvcData.SetValueDouble(const Name: string; const Value: Double);
begin
FList.Values[Name]:= FloatToStr(Value);
end;
{ TController }
constructor TController.Create;
begin
FMvcData:= TMvcData.Create;
//ShowMessage(‘Tcontroller create’);
end;
procedure TController.DoResponse;
begin
end;
function TController.GetData: IMvcData;
begin
Result:= FMvcData;
end;
procedure TController.SetData(Data: IMvcData);
begin
FMvcData:= Data;
end;
{ TCanvaserController }
constructor TCanvaserController.Create;
begin
inherited;
//ShowMessage(‘TCanvaserController Create’);
OpenDatabaseConnection;
ReloadDummy; {
Sepertinya terdapat BUG pada TStringList Object,
yakni, object yang di-assign (melalui AddObject) yang pertama, tidak bisa diakses.
maka butuh dummy sebagai objek awal, agar objek berikutnya dapat diakses.
}
ReloadDaftarKota;
ReloadDaftarPropinsi;
ReloadDaftarSales;
//ReloadDaftarStatus;
//ReloadDaftarJenisTransaksi;
//ShowMessage(‘TCanvaserController Create – END’);
end;
procedure TCanvaserController.ReloadDaftarJenisTransaksi;
var
StrList: TStringList;
begin
StrList:= TStringList.Create;
InitList(QueryM_TRANSAKSI,StrList);
Data.ValueObj['ObjDaftarJenisTransaksi']:= StrList;
StrList:= nil;
end;
procedure TCanvaserController.ReloadDummy;
var
StrList: TStringList;
begin
StrList:= TStringList.Create;
Data.ValueObj['ObjDummy']:= StrList;
StrList:= nil;
end;
procedure TCanvaserController.ReloadDaftarKota;
var
StrList: TStringList;
begin
ShowMessage(‘reload daftar kota, Kode Propinsi = ‘ + Data.ValueStr['KodePropinsi']);
StrList:= TStringList.Create;
InitList(QueryM_KOTA(Data.ValueStr['KodePropinsi']),StrList);
//InitList(QueryM_KOTA,StrList);
Data.ValueObj['ObjDaftarKota']:= StrList;
StrList:= nil;
end;
procedure TCanvaserController.ReloadDaftarPropinsi;
var
StrList: TStringList;
begin
StrList:= TStringList.Create;
InitList(QueryM_PROPINSI,StrList);
Data.ValueObj['ObjDaftarPropinsi']:= StrList;
StrList:= nil;
end;
procedure TCanvaserController.ReloadDaftarSales;
var
StrList: TStringList;
begin
StrList:= TStringList.Create;
InitList(QuerySALES,StrList);
Data.ValueObj['ObjDaftarSales']:= StrList;
StrList:= nil;
end;
procedure TCanvaserController.ReloadDaftarStatus;
var
StrList: TStringList;
begin
StrList:= TStringList.Create;
InitList(QueryM_STATUS,StrList);
Data.ValueObj['ObjDaftarStatus']:= StrList;
StrList:= nil;
end;
{ TPenjualanController }
constructor TPenjualanController.Create;
var
JnsTransList, NoPakList, ProdukList: TStringList;
begin
inherited;
JnsTransList:= TStringList.Create;
NoPakList:= TStringList.Create;
ProdukList:= TStringList.Create;
//list item for ‘ListJnsTrans’
InitList(QueryM_TRANSAKSI,JnsTransList);
Data.ValueObj['ObjListJnsTrans']:= JnsTransList;
InitList(QueryM_TRANSAKSI,NoPakList);
Data.ValueObj['ObjListNoPak']:= NoPakList;
InitList(QueryM_TRANSAKSI,ProdukList);
Data.ValueObj['ObjListProduk']:= ProdukList;
Data.ValueDate['TglPenjualan']:= Now;
ProdukList:= nil;
NoPakList:= nil;
JnsTransList:= nil;
FreeAndNil(JnsTransList);
FreeAndNil(NoPakList);
FreeAndNil(ProdukList);
end;
{ TDateTimeVar }
constructor TDateTimeVar.Create(InitValue: TDateTime);
begin
Data:= InitValue;
end;
procedure InitList(Source: IDataset; DestList: TStringList);
var
ObjList: TMvcData;
begin
DestList.Clear;
with Source do begin
while not eof do  begin
ObjList:= TMvcData.Create;
ObjList.ValueStr['KeyVal']:= FieldByName(‘KeyVal’).AsString;
DestList.AddObject(FieldByName(‘LookUpVal’).AsString, ObjList);
Next;
end;
end;
ObjList:= nil;
end;
function GetMvcListIndex(Items: TStrings; KeyVal: string): Integer;
var
List: TStringList;
i: Integer;
begin
Result:= -1;
List:= TStringList(Items);
for i:= 0 to List.Count – 1 do
if TMvcData(List.Objects[i]).ValueStr['KeyVal'] = KeyVal then begin
Result:= i;
Break;
end;
end;
procedure FreeOwnObjets(List: TStringList);
var i: Integer;
begin
if List.Count<1 then exit;
for i:= 0 to List.Count – 1 do
if Assigned(List.Objects[i]) then begin
if List.Objects[i] is TStringList then
FreeOwnObjets(TStringList(List.Objects[i])); {recursive}
List.Objects[i].Free;
end;
end;
{General Dialogs}
function MsgDlgConfirm(Msg: string): Boolean;
begin
Result:= MessageDlg(Msg, mtConfirmation, mbOKCancel,0) = mrOk;
end;
procedure MsgDlgInformation(Msg: string);
begin
MessageDlg(Msg, mtInformation, [mbOK],0);
end;
procedure MsgDlgWarning(Msg: string);
begin
MessageDlg(Msg, mtWarning, [mbOK],0);
end;
procedure MsgDlgError(Msg: string);
begin
MessageDlg(Msg, mtError, [mbOK],0);
end;
{General View Fungtions}
procedure DisableControls(Controls: array of TControl);
var i: Integer;
begin
for i:= Low(Controls) to High(Controls) do
Controls[i].Enabled:= False;
end;
procedure EnableControls(Controls: array of TControl);
var i: Integer;
begin
for i:= Low(Controls) to High(Controls) do
Controls[i].Enabled:= True;
end;
{ TMasterOutletController }
function TMasterOutletController.IsBlokir: Boolean;
begin
Result:= Data.ValueStr['IsBlokir'] = ’1′;
end;
function TMasterOutletController.IsOutletExist: Boolean;
var
sDataset: IDataset;
begin
Result:= False;
sDataset:= QueryCustomer(Data.ValueStr['CustId']);
if not Assigned(sDataset) then exit;
Result:= sDataset.RecordCount>0;
Data.ValueStr['CustNama']:=SDataset.FindField(‘NAMA’).AsString;
Data.ValueStr['CustKontak']:=SDataset.FindField(‘KONTAK’).AsString;
Data.ValueStr['CustAlamat']:=SDataset.FindField(‘ALAMAT’).AsString;
Data.ValueStr['CustTelepon']:=SDataset.FindField(‘NO_TELPON’).AsString;
Data.ValueStr['CustRekening']:=SDataset.FindField(‘NO_REKENING’).AsString;
Data.ValueStr['KodePropinsi']:=SDataset.FindField(‘K_PROPINSI’).AsString;
Data.ValueStr['KodeKota']:=SDataset.FindField(‘K_KOTA’).AsString;
Data.ValueStr['IsBlokir']:=SDataset.FindField(‘IS_BLOKIR’).AsString;
Data.ValueStr['SalesId']:=SDataset.FindField(‘SALES_ID’).AsString;
end;
function TMasterOutletController.PostInserted(var NewCustId: string): TErrMsg;
var
CUST_ID, Err_Code, Err_msg: String;
begin
try
with Data do begin
{ CUST_ID GENERATE OTOMATIS
procedure OutletInsert(CUST_ID, NAMA, KONTAK, ALAMAT, NO_TELPON, K_KOTA, K_PROPINSI,
NO_REKENING, SALES_ID, IS_BLOKIR, USER_ID: string);}
OutletInsert(
ValueStr['CustNama'], ValueStr['CustKontak'], ValueStr['CustAlamat'],
ValueStr['CustTelepon'], ValueStr['KodeKota'], ValueStr['KodePropinsi'],
ValueStr['CustRekening'], ValueStr['SalesId'], ValueStr['IsBlokir'],
ValueStr['UserId'], CUST_ID, Err_Code, Err_msg
);
if Err_Code<>” then
Result:= Format(‘\n[INSERT ERROR]\n%s’ ,[Err_msg])
else
NewCustId:= CUST_ID;
end;
except
on E:Exception do Result:= Format(‘\n[INSERT ERROR]\n%s’ ,[E.Message]);
end;
end;
function TMasterOutletController.PostUpdated: TErrMsg;
begin
try
with Data do begin
{procedure OutletUpdate(CUST_ID, NAMA, KONTAK, ALAMAT, NO_TELPON, K_KOTA, K_PROPINSI,
NO_REKENING, SALES_ID, IS_BLOKIR, USER_ID: string);}
OutletUpdate(
ValueStr['CustId'], ValueStr['CustNama'], ValueStr['CustKontak'], ValueStr['CustAlamat'],
ValueStr['CustTelepon'], ValueStr['KodeKota'], ValueStr['KodePropinsi'],
ValueStr['CustRekening'], ValueStr['SalesId'], ValueStr['IsBlokir'],
ValueStr['UserId']
);
end;
except
on E:Exception do
Result:= Format(‘\n[UPDATE ERROR]\n%s’ ,[E.Message]);
end;
end;
function TMasterOutletController.SetBlokir: TErrMsg;
begin
with Data do begin
ValueStr['IsBlokir']:=’1′; //representasi kondisi saat ini
try
OutletSetBlokir(’1′,ValueStr['CustId'], ValueStr['UserId']);
except
on E:Exception do Result:= E.Message;
end;
end;
end;
function TMasterOutletController.SetUnBlokir: TErrMsg;
begin
with Data do begin
ValueStr['IsBlokir']:=’0′; //representasi kondisi saat ini
try
OutletSetBlokir(’0′,ValueStr['CustId'], ValueStr['UserId']);
except
on E:Exception do Result:= E.Message;
end;
end;
end;
constructor TMasterOutletController.Create;
begin
inherited;
//ShowMessage(‘MasterOutletController create’);
end;
function TMasterOutletController.Delete: TErrMsg;
begin
with Data do begin
try
OutletDelete(ValueStr['CustId'], ValueStr['UserId']);
except
on E:Exception do Result:= Format(‘[DELETE ERROR]\n%s’,[E.Message]);
end;
end;
end;
function Validate(Controls: array of TControl; PropName: string): Boolean;
var
i: Integer;
PropValue: string;
begin
Result:= True;
for i:= Low(Controls) to High(Controls) do begin
PropValue:= GetPropValue(Controls[i],PropName);
if Pos(””,PropValue)>0 then begin
Result:= False;
if Controls[i] is TWinControl then TWinControl(Controls[i]).SetFocus;
Break;
end;
end;
end;
end.


MVC Dalam Delphi Programming


Author : Muchammad Aly mBA, S.Kom      * Download (*.doc)
Dalam pembuatan aplikasi database dengan Delphi, umumnya kita menggunakan komponen-komponen database, baik berupa komponen koneksi (Misal: TAdoConnection, IBDatabase, dst),   turunan TDataset (Misal: TAdoTable,  TQuery, dst) atau kontrol databound (DBGrid, DBEdit, dst).
Dengan pendekatan pengembangan aplikasi seperti ini,  kita biasa menuliskan perintah sql, business logic, validasi input, pengaturan tampilan sekaligus dalam satu form (satu unit).
Pengembangan aplikasi ini mempunyai kelemahan dari satu sisi. Diantaranya:
  1. Sulit dikembangkan dalam suatu tim yang saling bekerja sama. Misalkan tim yang menangani desain tampilan, ketika menyisipkan/ mengedit kode-kode yang merubah tampilan sangat boleh jadi business logic menjadi ikut terpengaruh. Demikian juga ketika tim yang menangani  database, ketika dibutuhkan perubahan perintah sql, sangat boleh jadi tingkah laku form akan berubah.
  2. Sulit dimaintenance. Programmer yang meneruskan pengembangan aplikasi mau tidak mau harus memahami source code secara keseluruhan sebelum dapat ikut berpartisipasi. Hal ini disebabkan keterkaitan yang demikian erat logika pemrograman dalam satu form/satu unit. Satu perubahan yang kecil dapat mempengaruhi keseluruhan  tingkah laku form.
Untuk menghindari hal tersebut di atas dibutuhkan pemisahan penulisan source code dalam bagian-bagian tertentu. Salah satu metode pemisahan source code ini adalah dengan menggunakan paradigma MVC yang merupakan kependekan dari Model View Controller.

Pengertian MVC

Yaitu suatu istilah metode pengembangan / pembuatan aplikasi dengan memisahkan elemen-elemen penulisan source code menjadi tiga bagian, yaitu:

Model

Model di sini berperan sebagai representasi dari data yang terlibat dalam suatu proses transaksi. Setiap kali method / function dari suatu aplikasi butuh untuk melakukan akses ke dalam suatu data, maka function / method tersebut tidak langsung berinteaksi dengan sumber data tersebut melainkan harus melalui model terlebih dahulu. Secara praktis, dalam pemrograman database Delphi, model ini berwujud unit-unit yang berisi perintah SQL dan koneksi database.

View

View di sini berperan sebagai presentation layer atau pengatur user interface (tampilan) bagi user dari suatu aplikasi. Data yang dibutuhkan oleh user akan diformat sedemikian rupa agar dapat tampil dan dipresentasikan dengan format tampilan yang memang disesuaikan dengan kebutuhkan user, biasanya layer View juga bertugas untuk melakukan validasi data yang diinputkan user. Secara praktis, dalam pemrograman Delphi, view berwujud unit form  yang hanya berisi perintah-perintah yang berhubungan dengan efek tampilan dan bagaimana data itu ditampilkan.

Controller

Controller di sini berperan sebagai logic aspect dari suatu aplikasi / mengatur user flow. Controller lah yang akan menentukan bussiness process dari aplikasi yang dibangun. Controller akan merespon setiap inputan dari user dengan melakukan pemanggilan terhadap model dan view yang sesuai sehingga request / permintaan dari user tersebugt dapat terpenuhi dengan baik. Biasanya layer controller juga digunakan untuk mengatur ijin akses dan permission. Secara praktis, dalam pemrograman Delphi, controller dapat berupa unit yang berisi function / procedure yang berisi logika bisnis.

MVC dan MVP

MVP (Model View Presentation) adalah turunan dari MVC. Presentation mempunyai kesamaan fungsi dengan Controller. Perbedaan MVC dan MVP hanya terletak pada arah komunikasi  antar elemen. Pada MVC, Viewbisa langsung berkomunikasi dengan Model tanpa melalui Controller. Pada MVP, komunikasi View denganModel harus melalui Presentation.
Berikut ini ilustrasi yang menggambarkan perbedaan MVC dan MPV

Contoh PENERAPAN MVC dan MVP DALAM DELPHI PROGRAMMING

Pada contoh di atas, komunikasi antara View dan Model pada MVC  terjadi melalui penggunaan variabelSearchResult pada unit first_model.pas.
Pada contoh MVP di atas, komunikasi antara View ke Model terjadi melaui Presentation dengan kembalian nilai dari Presentation.
Karena perbedaan yang tipis antara MVP dan MVC, sebagian orang tetap menyebut MVP sebagai MVP. Untuk selanjutnya, pada tulisan ini, tidak dibedakan istilah antara MVC dan MVP

Penerapan dalam Source Code SMS Manager

Pada bagian ini saya memberikan salah satu penerapan paradigma MVC pada source code Project SMS Manager Power Logic sebagai contoh, dengan menggunakan:
  1. Satu Unit controller berlaku untuk seluruh unit view pada project, dengan nama con_SMSManager.pas
  2. Satu Unit Model berlaku dengan nama mod_SMSManager.pas.
Pada contoh kali ini source code yang akan terapkan paradigm MVC ada pada method :
procedure TfrmKirimSms.btnTampilkanClick(Sender: TObject);
pada unit ufrmKirimSms.pas  dengan source code sebagai berikut:
1     procedure TfrmKirimSms.btnTampilkanClick(Sender: TObject);
2     var
3       STampil,
4       qryWhere      : String;
5       sWaktuAwal,
6       sWaktuAkhir   : string;
7       TotalHalaman,
8       jmlData       : integer;
9     begin
10      if cbMarketing.ItemIndex=-1 then begin
11        MessageDlg(‘Isikan User ID dulu ..!’,mtWarning,[mbOK],0);
12        Exit;
13      end;
14
15      if edCustID1.Text <> ” then
16        qryWhere := ‘ and B.CUST_ID=’+quotedstr(Trim(edCustID1.Text))+”;
17
18      sWaktuAwal   := QuotedStr(FormatDateTime(‘yyyy-mm-dd hh:nn:ss’,dtTanggal1.DateTime));
19      sWaktuAkhir  := QuotedStr(FormatDateTime(‘yyyy-mm-dd hh:nn:ss’,dtTanggal2.DateTime));
20
21      //sudah digantikan model QueryCountLogSmsOut
22      if cbHalaman.Checked then
23      begin
24        SDataset := DBConn.NewDataset(‘select count(*) ‘+
25                           ’ from LOG_SMS_OUT A LEFT JOIN AKUN_CUST B on A.hp_tujuan=B.cust_hp where A.WAKTU_REQUEST between ‘+
26                           sWaktuAwal+’ and ‘+sWaktuAkhir+’ and A.USER_ID=’+
27                           quotedstr(cbMarketing.Items.Names[cbMarketing.ItemIndex])+’ ‘+qryWhere
28                           ,True);
29        try
30          JmlData := SDataset.Fields[0].AsInteger;
31        finally
32        end;
33      end;
34
35      TotalHalaman := Ceil(JmlData/PAGEVIEW);
36      lbJmlData.Caption :=’Jumlah Data : ‘+inttoStr(JmlData)+’ – Tampil halaman ‘+floattostr(edHal.Value)+
37                          ‘ dari total ‘+inttostr(TotalHalaman)+’ halaman’;
38
39      STampil := inttostr((ceil(edHal.Value)-1)*PAGEVIEW);
40
41      //telah digantikan dengan modul QueryViewLogSmsOut
42      DM.DoDataGrid(DBConn,’select first ‘+inttostr(PAGEVIEW)+’ SKIP ‘+STampil+
43                           ‘ A.URUT, A.WAKTU_REQUEST, A.HP_TUJUAN, B.CUST_ID, A.ISI_SMS ‘+
44                           ‘ from LOG_SMS_OUT A LEFT JOIN AKUN_CUST B on A.hp_tujuan=B.cust_hp where A.WAKTU_REQUEST between ‘+
45                           sWaktuAwal+’ and ‘+sWaktuAkhir+’ and A.USER_ID=’+
46                           quotedstr(cbMarketing.Items.Names[cbMarketing.ItemIndex])+’ ‘+qryWhere,
47                           sgrdLogSmsOut);
48    end;
Dari  potongan source code di atas, bisa kita simpulkan bahwa yang akan kita pisahkan menjadi
Controller dan Model ada pada source code nomor  24 – 27 dan 42 -  47. Sehingga source code untuk view menjadi seperti berikut:
1     procedure TfrmViewKirimSms.btnTampilkanClick(Sender: TObject);
2     var
3
4       TotalHalaman,
5       jmlData       : integer;
6       sDataset  : IDataset;
7     begin
8       if cbMarketing.ItemIndex=-1 then begin
9         MessageDlg(‘Isikan User ID dulu ..!’,mtWarning,[mbOK],0);
10        Exit;
11      end;
12
13
14      DoCountLogSmsOut(cbMarketing.Items.Names[cbMarketing.ItemIndex], edCustID1.Text,
15                          dtTanggal1.DateTime, dtTanggal2.DateTime, jmlData);
16
17      TotalHalaman := Ceil(JmlData/PAGEVIEW);
18      lbJmlData.Caption :=’Jumlah Data : ‘+inttoStr(JmlData)+’ – Tampil halaman ‘+floattostr(edHal.Value)+
19                          ‘ dari total ‘+inttostr(TotalHalaman)+’ halaman’;
20
21
22
23      DoViewLogSmsOut(cbMarketing.Items.Names[cbMarketing.ItemIndex], edCustID1.Text,
24            dtTanggal1.DateTime, dtTanggal2.DateTime,PAGEVIEW,(ceil(edHal.Value)), sDataset);
25
26      DM.DoDataGrid(sDataset,sgrdLogSmsOut);
27
28    end;
Procedure dengan awalan Do adalah controller. Pada contoh di atas, source code DoViewLogSmsOut adalah sebagai berikut:
1     procedure DoViewLogSmsOut(UserId, CustID: string; FromWhen, ToWhen: TDateTime;
2         NumDataPerPage, PageIndex: Integer; var Dataset: IDataset);
3     begin
4
5       Dataset:= QueryViewLogSmsOut(UserId,CustID,FromWhen,ToWhen,
6         NumDataPerPage,(PageIndex-1) * NumDataPerPage );
7
8     end;
Procedure dengan awalan Query adalah Model. Source Code untuk Model  QueryViewLogSmsOut adalah sebagai berikut:
1     function QueryViewLogSmsOut(UserId, CustID: string; FromWhen, ToWhen: TDateTime;
2         NumRecs, AfterRecIdx: Integer): IDataset;
3
4     var
5       sPeriod1, sPeriod2: string;
6     begin
7
8       sPeriod1:= QuotedStr(FormatDateTime(‘yyyy-mm-dd hh:nn:ss’, FromWhen));
9       sPeriod2:= QuotedStr(FormatDateTime(‘yyyy-mm-dd hh:nn:ss’, ToWhen));
10      LastExecuteQuery:=
11          ‘SELECT FIRST ‘+IntToStr(NumRecs)+’ SKIP ‘+ IntToStr( AfterRecIdx) +
12          ‘ A.URUT, A.WAKTU_REQUEST, A.HP_TUJUAN, B.CUST_ID, A.ISI_SMS ‘+
13          ‘ from LOG_SMS_OUT A LEFT JOIN AKUN_CUST B on A.hp_tujuan=B.cust_hp ‘ +
14          ‘ where A.WAKTU_REQUEST between ‘+
15          sPeriod1+’ and ‘+sPeriod2+’ and A.USER_ID=’+ QuotedStr(UserId);
16      if CustID<>” then
17        LastExecuteQuery:= LastExecuteQuery + ‘ and B.CUST_ID=’+quotedstr(CustID);
18      Result:= DBConn.NewDataset(LastExecuteQuery,True);
19    end;
Sumber :

Monday, 28 October 2013

Best and Free Delphi 7 Component


Download
XStringGrid.rar
6 minutes ago · Latest version by Fajar Priyadi

Sunday, 27 October 2013

Delphi for Android (alias Delphi XE5 alias RAD Studio XE5) telah muncul


Berikut adalah fitur-fitur baru yang ada di DelphiXE5 :

  • the REST client library, a new cross-platform framework for easy access of REST-based web services
  • REST debugger
  • the full integration of FireDAC
  • IDE support for MacinCloud
  • Extendible IDE mobile design devices
  • the awesome IDE Insight functionality (Ctrl+. or F6) is no longer a modal dialog but is now a search box
  • style support for the freshly released iOS 7
  • swipe to delete feature on mobile platforms
  • TListView search filtering support
  • the removal of the long defunct WebSnap and InternetExpress (with the suggestion to use IntraWeb and WebBroker instead for similar functionality)



The full Delphi target platform sekarang menjangkau:
  • 32-bit Windows
  • 64-bit Windows
  • 32-bit OS X
  • iOS Simulator (Intel)
  • iOS (ARM)
  • Android (ARM)

Mempunyai lumayan banyak compiler:

  • dcc32 – Embarcadero Delphi for Win32 compiler version 26.0 – your regular Win32 Delphi, the latest version updated over many versions since Delphi 2
  • dcc64 – Embarcadero Delphi for Win64 compiler version 26.0 – the 64-bit Windows targeting compiler
  • dccosx – Embarcadero Delphi for Mac OS X compiler version 26.0 – the Delphi compiler that generates 32-bit OS X apps
  • dccios32 – Embarcadero Delphi Next Generation for iPhone Simulator compiler version 26.0 – the NextGen Delphi compiler that builds Intel executables that run in the iOS simulator
  • dcciosarm - Embarcadero Delphi Next Generation for iPhone compiler version 26.0 – the NextGen Delphi compiler that builds ARM executables that run on iOS devices
  • dccaarm – Embarcadero Delphi for Android compiler version 26.0 – the NextGen Delphi compiler that builds ARM executables that run on Android emulators and devices


Persyaratan Android


Karena compiler Delphi menghasilkan instruksi mesin asli, output-nya adalah prosesor khusus. Dengan kata lain itu tidak menargetkan Dalvik Virtual Machine, di mana aplikasi Android biasa berada, yang pada dasarnya Java p-kode yang dieksekusi oleh varian dari Java VM. Sebaliknya menghasilkan kode mesin mentah, karena semua gelombang saat Delphi compiler lakukan (yang lama pergi Delphi untuk. NET adalah pengecualian untuk aturan umum). Jadi karena itu compiler menyusun instruksi mesin asli dukungan Android Delphi memiliki persyaratan sebagai berikut:


  • there must be a GPU
  • the CPU must be ARMv7 with NEON instruction support
  • the OS on the target device must be one of:
    • GingerBread: Android 2.3.3+ (MR1 or later), which is API level 10
    • Ice Cream Sandwich: Android 4.0.3+ (MR1 or later), which is API level 15
    • Jelly Bean: Android 4.1+ (release, MR1, MR2 or later), which are API levels 16, 17 and 18
  • you can run the app on an Android emulator if:
    • the emulator is set to use the host GPU
    • the emulator is running Ice Cream Sandwich (MR1 or later) or Jelly Bean (release or later)
    • the emulator is not running in a Virtual Machine

How do you find out if your device is supported? Well, the OS version you can find out in the Settings. The path and menu items may vary but goes roughly like this: Settings, About phone (or tablet), Software information, Android version.
To check the CPU details you’ll need to run one of the tools from the Android SDK against your connected device. Delphi installs the Android SDK and NDK if you don’t tell it you have it pre-installed. The Android SDK gets installed into a directory something like: C:\Users\Public\Documents\RAD Studio\12.0\PlatformSDKs\adt-bundle-windows-x86-20130522\sdk. In the platform-tools subdirectory from there is the Android Debug Bridge, adb.exe.
To run a command against your device it needs to be connected, typically by USB. This requires you to install an appropriate USB driver for your device as the ones located by Windows typically don’t do the job. Refer to the helpful The Delphi Geek blog post on the matter, XE5 and USB Drivers, for more information and links to drivers for the more common Android phone manufacturers.
When your phone is connected you’ll need to launch a command prompt and run an adbcommand. This may be easiest if you change directory to the platform-tools subdirectory (or Shift+right-click on the platform-tools folder in Windows Explorer and choose Open command window here). Firstly run the command:
adb devices
just to prove that your device can be seen by the Android tool chain. Assuming it can, run:
adb -d shell cat /proc/cpuinfo
This will show you CPU information something like this:
Processor       : ARMv7 Processor rev 0 (v7l)
processor       : 0
BogoMIPS        : 13.52

processor       : 1
BogoMIPS        : 13.52

processor       : 2
BogoMIPS        : 13.52

processor       : 3
BogoMIPS        : 13.52

Features        : swp half thumb fastmult vfp edsp thumbee neonvfpv3 tls vfpv4
CPU implementer : 0x51
CPU architecture: 7
CPU variant     : 0x1
CPU part        : 0x06f
CPU revision    : 0

Hardware        : UNKNOWN
Revision        : 0003
Serial          : 0000000000000000
Check the Processor line to ensure you are running ARMv7. In the Features line check that neon is included in the CPU feature list

DOWNLOAD DELPHIXE5 UPDATE1

DOWNLOAD OTHER DELPHI

Best Post This Year

Install Fortesreport community Delphi 7 dan RX Berlin

Download  Pertama2 kita harus punya file installernya terlebih dahulu, download  https://github.com/fortesinformatica/fortesrepo...

Total Pageviews

© 2014 Fajar Priyadi. WP themonic converted by Bloggertheme9. Published By Gooyaabi Templates | Powered By Blogger
TOP