You are not logged in.
Pages: 1
I think you need to report a bug to @ab
I think you need to write a mORMot client in PHP if the server has authentication.
If there is no authentication then you can use something like the following code.
Note : I don't have PHP now to test this code.
<?php
list($rseOleDB, $rseODBC, $rseOracle, $rseSQlite3, $rseJet, $rseMSSQL) = [0,1,2,3,4,5];
function _callFunction($funcName, $params){
$mServer = "http://www.your-server.com:888/root";
$opts = array(
'http' => array(
'method'=>"POST", 'header'=>"Content-Type: application/json; charset=UTF-8",
'content'=> json_encode($params)
)
);
$context = stream_context_create($opts);
$url = "$mServer/RemoteSQL/$funcName"; //Or $url = "$mServer/RemoteSQL.$funcName";
return @file_get_contents($url , false, $context);
}
function connect($engine, $aServerName, $aDatabaseName, $aUserID, $aPassWord){
return _callFunction("Connect", [$engine, $aServerName, $aDatabaseName, $aUserID, $aPassWord]);
}
function getTables(){
return _callFunction("GetTableNames", []);
}
function execute($aSQL, $aExpectResults, $aExpanded){
return _callFunction("Execute", [$aSQL, $aExpectResults, $aExpanded]);
}
?>
Hi mohsenti
In the help of the function it says :
note that any inherited classes will be serialized as the parent class
.....................................................
// - note that any inherited classes will be serialized as the parent class
// - this method is thread-safe, but should be called before any serialization
class procedure RegisterCustomSerializerFieldNames(aClass: TClass;
const aClassFields, aJsonFields: array of ShortString);
I think this mean that your last TJSONSerializer.RegisterCustomSerializerFieldNames only applied.
I noticed also that JsonString content in your example is not valid since you called RegisterCustomSerializerFieldNames
TJSONSerializer.RegisterCustomSerializerFieldNames(TClass1, ['type_'], ['type']);
TJSONSerializer.RegisterCustomSerializerFieldNames(TClass2, ['class_'], ['class']);
JsonString := '{"Count":2,"Object1":{"Name":"C1","type_":"TYPE"},"Object2":{"Name":"C2","class_":"CLASS"}}';
//It must be
TJSONSerializer.RegisterCustomSerializerFieldNames(TClass1, ['type_'], ['type']);
TJSONSerializer.RegisterCustomSerializerFieldNames(TClass2, ['class_'], ['class']);
JsonString := '{"Count":2,"Object1":{"Name":"C1","type":"TYPE"},"Object2":{"Name":"C2","class":"CLASS"}}';
I hope ab, can find some time to implement it.
You can't browse the server but you can emulate it. Get the directories list and send them to the browser, then the browser display them as a tree for the user to select a folder.
To get the directories tree in Windows you can use something like this :
Procedure GetDirTree(SearchDir:String; RList: TStrings; SubDir:Boolean = True; Lvl:Integer= 0 );
var
Path, Tmp :String ;
SearchRec: TSearchRec;
begin
Path := CheckPathEnd(SearchDir);
if FindFirst(Path + '*', faAnyFile, SearchRec)= 0 then begin
Tmp := StringOfChar(#9, Lvl);
repeat
if ( (SearchRec.Attr and faDirectory)= faDirectory ) and (SearchRec.Name[1] <> '.') then begin
RList.Add(Tmp + SearchRec.Name);
if SubDir then GetDirTree(Path + SearchRec.Name, RList, True, Lvl+1);
end;
until (FindNext(SearchRec) <> 0);
FindClose(SearchRec.FindHandle);
end;
end;
Hi ab,
I have abandoned using the Mustache template. I used TSQLRestServerDB.Services to get the output I want.
I uploaded a sample at gulf-soft.com/e/files/Mormot_Sample.zip
In this sample I included my thought about making it easier for JavaScript programmer for consuming my services. Beside other things like simple Http server and using MySql.
Now if I have Interface like this:
IClientRepository = interface(IBaseFactory)
['{31D143DB-9EED-4C00-940B-52C9BDB515D1}']
function GetClient(Id : TId; out aClient: TSQLClient) : Cardinal;
function SaveClient(var aClient: TSQLClient) : Cardinal ;
..............................
end;
In JavaScript I will use some code like this:
var clientRepository = new ClientRepository(_mc);
var r = clientRepository.GetClient(Id);
if(r.XHR.status == 200){
workClient = r.responce.result[0];
displayClent(workClient);
}
else
alert(r.XHR.responseText);
I hope this sample helps others and I get some comments to improve my knowledge in mORMot.
Hi ab,
For the output/results parameters in javascript, I guess the most obvious could be to return an object with the output fields: {Items:[...],Result:1234}
My last question was about the output of Mustache template not javascript.
I don't want the Delphi method parameters of kind output to be appear in Mustache template output.
For example if I have the following interface:
IAccountsChart = interface(IBaseFactory)
['{A35B2E70-C92D-4573-B46C-83F971B7E3DF}']
function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;
end;
And I use the following template fragment for output method's name and parameter
{{<method}}this.{{methodName}}=function({{#args}}{{^dirResult}}{{argName}}{{#commaArg}}, {{/commaArg}}{{/dirResult}}{{/args}}){
.......................................
}{{/method}}
Mustache template output is :
this.GetChartBranchData = function(Items, ItemId){
.......................................
}
But I want the template to output:
this.GetChartBranchData = function(ItemId){
.......................................
}
Is that possible ?
Hi ab
I am new to mORMot.
I would tend to use a mORMot-based service for this, with an in-memory cache of the js content.
Just re-use the content of procedure WrapperMethod() for your own method.
I didn't know what do you mean by "in-memory cache" and how to do that in mORMot, but I get that you advice me to save the content and reuse it. So I saved the js content to a file "Service.js". I did this at server start so I can get the file later when a client need it at anytime. I used something like this:
JsName := ExtractFileName(aJsFileName);
Content:= WrapperFromModel(aServer, StringFromFile(aMustacheTemplate), JsName , 888);
FileFromString(Content, aJsFileName);
If you call the method js(Ctxt), then you will be able to parse what is after the root/js/.... method name from the Ctxt.URIAfterRoot value.
I'm using something like sample 09 - HttpApi web server to access the file from Javascript like this:
<script src="http://localhost:888/root/js/Services.js"></script>
This is enough for my learning purpose right now, but it is still advisable to learn from you and other mORMot experts. I want to share a full working sample (Server, Delphi client, web client and MySql database). I hope this may save some time for other newbie like me. I know the rules No long code in the forum. Can I upload it to my website and put the download link here?
There is another thing I need to do and I need your help to point me to the right direction as usual.
Delphi :
function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;
Output Javascript :
function GetChartBranchData(Items, ItemId)
I want to remove the out parameter(s) Items in this case. I don't want to confuse the Javascript programmer.
I want it to be like this:
Delphi :
function GetChartBranchData(out Items: TAccChartItems; ItemId: TId ): UInt32;
Output Javascript:
function GetChartBranchData(ItemId)
Thanks ab
It works now after using
{{#commaArg}}, {{/commaArg}}
My template file name is "Js.pas.mustache" and I can call it from Javascript like this:
<script src='http://localhost:888/root/wrapper/Js/mORMotClient.pas.txt'></script>
But I want to call it like this
<script src='http://localhost:888/root/js/mORMotClient_Services.js'></script>
Or
<script src='http://localhost:888/root/js/Services.js'></script>
Can you please point me to a solution to change
wrapper/Js/mORMotClient.pas.txt
to
js/mORMotClient_Services.js
?
Thanks ab for your quick response and pointing me to Mustache template.
I used a Mustache template and I got some results very close to what I need.
My problem now is I want a comma (,) not semicolon (;) in function parameters like the following
function GetChartBranchData( Items; ItemId );
//I wanted it to be
//function GetChartBranchData( Items, ItemId );
Can I use something else instead of {{commaArg}} to produce a comma (,) not semicolon (;)?
This is the template :
{{<method}}function {{methodName}}({{#args}} {{^dirResult}} {{argName}}{{commaArg}}{{/dirResult}} {{/args}} );{{/method}}
{{<member}}this.on{{methodName}} = null;{{/member}}
{{#orm}}
{{^isInMormotPas}}
{{/isInMormotPas}}
{{/orm}}
{{#soa.services}}
/* Definition of {{interfaceURI}} Object */
// ------------------------------------
function {{interfaceURI}}(mORMotClient){
this.initialized=false;
this.mORMotClient=mORMotClient;
{{#methods}}
{{>member}}
{{/methods}}
var doCall = function(fnName, fnParam, callBack){
funcName = '{{interfaceURI}}.' + fnName;
funcParam = '[' + ((! fnParam) ? '' : JSON.stringify(fnParam)) + ']';
return mORMotClient.callFunc(funcName, funcParam, callBack, this);
}
this.Initialize = function(){
doCall('_contract_', null, this.onInitialize);
}
this.onInitialize = function(req){
var data = req.responce;
if(data.error.errorNo == 0)
req.owner.initialized = true;
}
{{#methods}}
{{>method}}
{{/methods}}
}
{{/soa.services}}
The result of this template is
/* Definition of AccountsChart Object */
// ------------------------------------
function AccountsChart(mORMotClient){
this.initialized=false;
this.mORMotClient=mORMotClient;
this.onExportJScript=null;
this.onFillDefaultChartData=null;
this.onGetChartData=null;
this.onGetChartBranchData=null;
this.onInsertChartItem=null;
this.onAddChartItem=null;
this.onDelChartItem=null;
this.onMoveChartItem=null;
this.onUpdateChartItem=null;
this.onGetChartItem=null;
this.onChangeChartItemKind=null;
var doCall = function(fnName, fnParam, callBack){
funcName = 'AccountsChart.' + fnName;
var fnParams = [];
for(var i=0; i < fnParam.length; i++) fnParams[i] = fnParam[i];
return mORMotClient.callFunc(funcName, JSON.stringify(fnParams), callBack, this);
}
this.Initialize = function(){
doCall('_contract_', null, this.onInitialize);
}
this.onInitialize = function(req){
var data = req.responce;
if(data.error.errorNo == 0)
req.owner.initialized = true;
}
this.ExportJScript= function ( ){
return doCall('ExportJScript', arguments, this.onExportJScript);
};
this.FillDefaultChartData= function ( Items; ChartType ){
return doCall('FillDefaultChartData', arguments, this.onFillDefaultChartData);
};
this.GetChartData= function ( Items ){
return doCall('GetChartData', arguments, this.onGetChartData);
};
this.GetChartBranchData= function ( Items; ItemId ){
return doCall('GetChartBranchData', arguments, this.onGetChartBranchData);
};
this.InsertChartItem= function ( Items; ParentId; Index ){
return doCall('InsertChartItem', arguments, this.onInsertChartItem);
};
this.AddChartItem= function ( Items; ParentId ){
return doCall('AddChartItem', arguments, this.onAddChartItem);
};
this.DelChartItem= function ( Items; ItemId ){
return doCall('DelChartItem', arguments, this.onDelChartItem);
};
this.MoveChartItem= function ( Items; ItemId; ParentId; Index ){
return doCall('MoveChartItem', arguments, this.onMoveChartItem);
};
this.UpdateChartItem= function ( Item ){
return doCall('UpdateChartItem', arguments, this.onUpdateChartItem);
};
this.GetChartItem= function ( Item; ItemId ){
return doCall('GetChartItem', arguments, this.onGetChartItem);
};
this.ChangeChartItemKind= function ( ItemId; ItemKind ){
return doCall('ChangeChartItemKind', arguments, this.onChangeChartItemKind);
};
}
Hi edwinsn,
I'm new to SQLite, but I know that you can't update any record inside the transaction.
But still that another user can save his modified version of record after the current user end his transaction.
I reuse some Javascript code from Javascript authentication . Thanks for Ab, esmondb and RangerX.
I added more functions to mORMotClient in order to consume Interface based services. I will share it when done. But I still have one point and I need some help.
For example if I have an interface like this
IAccountsChart = interface(IBaseFactory)
['{A35B2E70-C92D-4573-B46C-83F971B7E3DF}']
function GetChartData(out Items: TAccChartItems ): Integer;
function InsertChartItem(out Items: TAccChartItems; ParentId: TId; Index : Integer): Integer;
function DelChartItem(out Items: TAccChartItems; ItemId: TId): Integer;
function MoveChartItem(out Items: TAccChartItems; ItemId, ParentId : TId; Index : Integer=-1): Integer;
function UpdateChartItem(Item: TAccChartItemData): Integer;
end;
I want to produce the following Javascript code for this interface so I can reflect new added functions to Javascript.
function AccountsChart(mORMotClient){
this.onGetChartData= null;
this.onInsertChartItem= null;
this.onDelChartItem= null;
this.onMoveChartItem= null;
this.onUpdateChartItem= null;
........................
this.GetChartData = function(){
return doCall('GetChartData', null, this.onGetChartData);
}
this.InsertChartItem = function(Parent, Index){
return doCall('InsertChartItem', Parent, Index, this.onInsertChartItem);
}
this.DelChartItem = function(ItemId){
return doCall('DelChartItem', ItemId, this.onDelChartItem);
}
this.MoveChartItem = function(ItemId,Parent, Index){
return doCall('MoveChartItem', ItemId,Parent, Index, this.onMoveChartItem);
}
this.UpdateChartItem = function(Item){
return doCall('UpdateChartItem', Item, this.onUpdateChartItem);
}
}
can I generate that Javascript at my mORMot server?
I want to call it directly from the browser like that :
<script src="http://localhost:888/root/GetJScript/AccountsChart"></script>
<script>
......................
var accountsChart=New AccountsChart(mORMotClient);
var chartData = accountsChart.GetChartData();
......................
</script>
Thanks again ab not only for your response but also for sharing this great project.
My conclusion is to use any dll as service in mORMot is to make a unit contains interfaces that map interfaces inside dll. So no deal with RTTI inside dll.
Even if dll dose not have interfaces and only export functions I still have to make interfaces to map functions inside dll. So I can use the dll as it is.
And putting such logic within a dll sounds like a weird architecture choice to me.
This is an old project divided into some modules each of them in dll and I want to reuse them with minimum effort.
Thanks ab for your quick response. I tried it but it failed, I think due to RTTI may be.
I introduced a mapping unit to load the dll and call the function inside it
if my dll contains the following interface
IdllItnf = interface()
procedure DllProcA();
procedure DllProcB();
end;
then my server unit will contains the following code
IServiceItnf = interface(IInvokable)
['{CF3A7E2C-8189-43F7-AE34-35920D743ED3}']
procedure SrvcProcA();
procedure SrvcProcB();
end;
TMyService = class(TInterfacedObject, IServiceItnf)
private
FDllIntf : IdllItnf;
public
procedure SrvcProcA();
procedure SrvcProcB();
end;
...............
procedure TMyService.SrvcProcA();
begin
FDllIntf.DllProcA();
end;
Now I will use the introduced classes and interfaces as regular
Hi all,
I'm new-be to mORMot. My Question is it possible to have a service inside dll ?
My code in server will be something like :
var
sc : IMyContainer;
loder : IBluginLoader;
begin
......................
aServer := TSQLRestServerDB.Create(aModel,ChangeFileExt(paramstr(0),'.db'),true);
// aServer.ServiceDefine(TClientFactory,[IClientFactory],sicShared);
loder := TBluginLoader.Create('MyDll.dll', 'CreateModuleObject'); //Load dll
sc := IMyContainer(loder.GetBluginInterface()); // Run function "CreateModuleObject" and get result
sc.RegisterFactory(aServer);
.......................
end;
My code in dll will be something like :
{ TMyContainer }
function TMyContainer.RegisterFactory(const aServer: TSQLRestServerDB): boolean;
begin
aServer.ServiceDefine(TClientFactory,[IClientFactory],sicShared);
end;
initialization
TInterfaceFactory.RegisterInterfaces([TypeInfo(IClientFactory)]);
thanks
Pages: 1