Added ToMVCList to wrap any object and try to use as list

This commit is contained in:
Daniele Teti 2019-10-10 20:16:20 +02:00
parent b0ccc9a974
commit 6bdf5547bc
9 changed files with 460 additions and 87 deletions

View File

@ -74,8 +74,9 @@ Congratulations to Daniele Teti and all the staff for the excellent work!" -- Ma
> WARNING! Considering the huge amount of features added in 3.1.1-beryllium during its RC phase, the dmvcframework-3.1.1-beryllium has been renamed to dmvcframework-3.2.0-boron
- New! Added Swagger support (thanks to [João Antônio Duarte]() and [Geoffrey Smith](https://github.com/geoffsmith82))
- New! Added Swagger support (thanks to [João Antônio Duarte](https://github.com/joaoduarte19) and [Geoffrey Smith](https://github.com/geoffsmith82))
- New! Added SQLGenerator and RQL compiler for PostgreSQL, SQLite and MSSQLServer (in addition to MySQL, MariaDB, Firebird and Interbase)
- New! Added support for interfaces serialization - now it is possible to serialize Spring4D collections (thanks to [João Antônio Duarte](https://github.com/joaoduarte19))
- Improved! Greatly improved support for [HATEOAS](https://en.wikipedia.org/wiki/HATEOAS) in renders. Check `TRenderSampleController.GetPeople_AsObjectList_HATEOS` and all the others actions end with `HATEOS` in `renders.dproj` sample)
```delphi

View File

@ -59,6 +59,39 @@ type
class function GetList(const aCount: Integer = 3): TObjectList<TPerson>;
end;
IPerson = interface
['{1D00C67A-A6D9-4B31-8291-705B339CDE9B}']
function GetName: String;
procedure SetName(const Value: String);
function GetAge: Integer;
procedure SetAge(const Value: Integer);
function GetDOB: TDate;
procedure SetDOB(const Value: TDate);
property Name: String read GetName write SetName;
property Age: Integer read GetAge write SetAge;
property DOB: TDate read GetDOB write SetDOB;
end;
[MVCNameCase(ncCamelCase)]
TInterfacedPerson = class(TInterfacedObject, IPerson)
private
fName: string;
FDOB: TDate;
fAge: Integer;
protected
function GetName: String;
procedure SetName(const Value: String);
function GetAge: Integer;
procedure SetAge(const Value: Integer);
function GetDOB: TDate;
procedure SetDOB(const Value: TDate);
public
property Name: String read GetName write SetName;
property Age: Integer read GetAge write SetAge;
property DOB: TDate read GetDOB write SetDOB;
end;
TPeople = class(TObjectList<TPerson>);
[MVCNameCase(ncLowerCase)]
@ -91,7 +124,7 @@ type
[MVCNameCase(ncLowerCase)]
TCustomer = class
private
FName: string;
fName: string;
FAddressLine2: string;
FAddressLine1: string;
FContactFirst: string;
@ -108,7 +141,7 @@ type
public
constructor Create;
destructor Destroy; override;
property Name: string read FName write SetName;
property Name: string read fName write SetName;
[MVCDoNotSerialize]
property ContactFirst: string read FContactFirst write SetContactFirst;
[MVCDoNotSerialize]
@ -185,14 +218,13 @@ begin
Result := TObjectList<TPerson>.Create(true);
for I := 1 to aCount do
begin
Result.Add(TPerson.GetNew(GetRndFirstName, GetRndLastName, EncodeDate(1900 + Random(100),
Random(12) + 1, Random(27) + 1), true));
Result.Add(TPerson.GetNew(GetRndFirstName, GetRndLastName, EncodeDate(1900 + Random(100), Random(12) + 1,
Random(27) + 1), true));
end;
end;
end;
class function TPerson.GetNew(AFirstName, ALastName: string; ADOB: TDate;
AMarried: boolean): TPerson;
class function TPerson.GetNew(AFirstName, ALastName: string; ADOB: TDate; AMarried: boolean): TPerson;
begin
Result := TPerson.Create;
Result.FLastName := ALastName;
@ -302,7 +334,7 @@ end;
procedure TCustomer.SetName(const Value: string);
begin
FName := Value;
fName := Value;
end;
{ TProgrammer }
@ -352,6 +384,38 @@ begin
inherited;
end;
{ TInterfacedPerson }
function TInterfacedPerson.GetAge: Integer;
begin
Result := fAge;
end;
function TInterfacedPerson.GetDOB: TDate;
begin
Result := FDOB;
end;
function TInterfacedPerson.GetName: String;
begin
Result := fName;
end;
procedure TInterfacedPerson.SetAge(const Value: Integer);
begin
fAge := Value;
end;
procedure TInterfacedPerson.SetDOB(const Value: TDate);
begin
FDOB := Value;
end;
procedure TInterfacedPerson.SetName(const Value: String);
begin
fName := Value;
end;
initialization
Randomize;

View File

@ -8,6 +8,7 @@ uses
function GetPeopleList: TObjectList<TPerson>;
function GetPeopleSmallList: TObjectList<TPerson>;
function GetInterfacedPeopleList: TList<IPerson>;
implementation
@ -17,6 +18,23 @@ uses
var
GPeople, GPeopleSmall: TObjectList<TPerson>;
function GetInterfacedPeopleList: TList<IPerson>;
var
lPerson: IPerson;
begin
Result := TList<IPerson>.Create;
lPerson := TInterfacedPerson.Create;
lPerson.Name := 'Daniele Teti';
lPerson.Age := 40;
lPerson.DOB := EncodeDate(1979, 11, 4);
Result.Add(lPerson);
lPerson := TInterfacedPerson.Create;
lPerson.Name := 'Peter Parker';
lPerson.Age := 35;
lPerson.DOB := EncodeDate(1984, 11, 4);
Result.Add(lPerson);
end;
procedure PopulateList;
var
p: TPerson;

View File

@ -39,8 +39,7 @@ type
[MVCPath('/')]
TRenderSampleController = class(TMVCController)
protected
procedure OnBeforeAction(AContext: TWebContext; const AActionName: string;
var AHandled: Boolean); override;
procedure OnBeforeAction(AContext: TWebContext; const AActionName: string; var AHandled: Boolean); override;
public
[MVCHTTPMethod([httpGET])]
[MVCPath('/customers/($ID)')]
@ -79,6 +78,11 @@ type
[MVCProduces('application/json')]
procedure GetPeople_AsObjectList;
[MVCHTTPMethod([httpGET])]
[MVCPath('/interfacedpeople')]
[MVCProduces('application/json')]
procedure GetInterfacedPeople;
[MVCHTTPMethod([httpGET])]
[MVCPath('/people/hateoas')]
[MVCProduces('application/json')]
@ -289,8 +293,7 @@ begin
end;
Context.Response.ContentType := TMVCMediaType.APPLICATION_OCTET_STREAM;
Context.Response.StatusCode := HTTP_STATUS.OK;
Context.Response.CustomHeaders.Values['Content-Disposition'] := 'attachment; filename=' +
filename + ';';
Context.Response.CustomHeaders.Values['Content-Disposition'] := 'attachment; filename=' + filename + ';';
Render(TFileStream.Create(lFullFilePath, fmOpenRead or fmShareDenyNone));
end;
@ -330,8 +333,7 @@ begin
// We need a non standard representation, let's create a specific serializer.
lSer := TMVCJsonDataObjectsSerializer.Create;
try
lSer.DataSetToJsonArray(lDM.qryCustomers, lJObj.a['customers'],
TMVCNameCase.ncLowerCase, []);
lSer.DataSetToJsonArray(lDM.qryCustomers, lJObj.a['customers'], TMVCNameCase.ncLowerCase, []);
lSer.DataSetToJsonArray(lDM.qryCountry, lJObj.a['countries'], TMVCNameCase.ncLowerCase, []);
finally
lSer.Free;
@ -369,22 +371,17 @@ begin
Render(lDM.qryCustomers, False,
procedure(const DS: TDataset; const Links: IMVCLinks)
begin
Links.AddRefLink
.Add(HATEOAS.HREF, '/customers/' + DS.FieldByName('cust_no').AsString)
.Add(HATEOAS.REL, 'self')
.Add(HATEOAS._TYPE, 'application/json');
Links.AddRefLink
.Add(HATEOAS.HREF, '/customers/' + DS.FieldByName('cust_no').AsString + '/orders')
.Add(HATEOAS.REL, 'orders')
Links.AddRefLink.Add(HATEOAS.HREF, '/customers/' + DS.FieldByName('cust_no').AsString).Add(HATEOAS.REL, 'self')
.Add(HATEOAS._TYPE, 'application/json');
Links.AddRefLink.Add(HATEOAS.HREF, '/customers/' + DS.FieldByName('cust_no').AsString + '/orders')
.Add(HATEOAS.REL, 'orders').Add(HATEOAS._TYPE, 'application/json');
end);
finally
lDM.Free;
end;
end;
procedure TRenderSampleController.GetCustomer_AsDataSetRecord(
const ID: Integer);
procedure TRenderSampleController.GetCustomer_AsDataSetRecord(const ID: Integer);
var
lDM: TMyDataModule;
begin
@ -394,13 +391,9 @@ begin
Render(lDM.qryCustomers, False, [], dstSingleRecord,
procedure(const DS: TDataset; const Links: IMVCLinks)
begin
Links.AddRefLink
.Add(HATEOAS.HREF, '/customers')
.Add(HATEOAS.REL, 'customers')
.Add(HATEOAS._TYPE, TMVCMediaType.APPLICATION_JSON);
Links.AddRefLink
.Add(HATEOAS.HREF, '/customers/' + DS.FieldByName('cust_no').AsString)
.Add(HATEOAS.REL, 'self')
Links.AddRefLink.Add(HATEOAS.HREF, '/customers').Add(HATEOAS.REL, 'customers').Add(HATEOAS._TYPE,
TMVCMediaType.APPLICATION_JSON);
Links.AddRefLink.Add(HATEOAS.HREF, '/customers/' + DS.FieldByName('cust_no').AsString).Add(HATEOAS.REL, 'self')
.Add(HATEOAS._TYPE, TMVCMediaType.APPLICATION_JSON);
end);
finally
@ -432,6 +425,11 @@ begin
end;
procedure TRenderSampleController.GetInterfacedPeople;
begin
Render(ToMVCList(GetInterfacedPeopleList, True));
end;
procedure TRenderSampleController.GetLotOfPeople;
begin
Render<TPerson>(GetPeopleList, False);
@ -439,10 +437,8 @@ end;
procedure TRenderSampleController.GetPerson_AsHTML;
begin
ResponseStream.Append('<html><body><ul>').Append('<li>FirstName: Daniele</li>')
.Append('<li>LastName: Teti')
.AppendFormat('<li>DOB: %s</li>', [DateToISODate(EncodeDate(1975, 5, 2))])
.Append('<li>Married: yes</li>')
ResponseStream.Append('<html><body><ul>').Append('<li>FirstName: Daniele</li>').Append('<li>LastName: Teti')
.AppendFormat('<li>DOB: %s</li>', [DateToISODate(EncodeDate(1975, 5, 2))]).Append('<li>Married: yes</li>')
.Append('</ul></body></html>');
RenderResponseStream;
end;
@ -472,11 +468,8 @@ end;
procedure TRenderSampleController.GetPerson_AsText(const ID: Integer);
begin
ResponseStream
.AppendLine('ID : ' + ID.ToString)
.AppendLine('FirstName : Daniele')
.AppendLine('LastName : Teti')
.AppendLine('DOB : ' + DateToStr(EncodeDate(1979, 5, 2)))
ResponseStream.AppendLine('ID : ' + ID.ToString).AppendLine('FirstName : Daniele')
.AppendLine('LastName : Teti').AppendLine('DOB : ' + DateToStr(EncodeDate(1979, 5, 2)))
.AppendLine('Married : yes');
RenderResponseStream;
end;
@ -627,15 +620,9 @@ begin
Render<TPerson>(People, True,
procedure(const APerson: TPerson; const Links: IMVCLinks)
begin
Links.AddRefLink
.Add(HATEOAS.HREF, '/people/' + APerson.ID.ToString)
.Add(HATEOAS.REL, 'self')
.Add(HATEOAS._TYPE, 'application/json')
.Add('title', 'Details for ' + APerson.FullName);
Links.AddRefLink
.Add(HATEOAS.HREF, '/people')
.Add(HATEOAS.REL, 'people')
.Add(HATEOAS._TYPE, 'application/json');
Links.AddRefLink.Add(HATEOAS.HREF, '/people/' + APerson.ID.ToString).Add(HATEOAS.REL, 'self').Add(HATEOAS._TYPE,
'application/json').Add('title', 'Details for ' + APerson.FullName);
Links.AddRefLink.Add(HATEOAS.HREF, '/people').Add(HATEOAS.REL, 'people').Add(HATEOAS._TYPE, 'application/json');
end);
end;
@ -653,14 +640,10 @@ begin
Render(lPerson, False,
procedure(const AObject: TObject; const Links: IMVCLinks)
begin
Links.AddRefLink
.Add(HATEOAS.HREF, '/people/' + TPerson(AObject).ID.ToString)
.Add(HATEOAS.REL, 'self')
.Add(HATEOAS._TYPE, TMVCMediaType.APPLICATION_JSON);
Links.AddRefLink
.Add(HATEOAS.HREF, '/people')
.Add(HATEOAS.REL, 'people')
Links.AddRefLink.Add(HATEOAS.HREF, '/people/' + TPerson(AObject).ID.ToString).Add(HATEOAS.REL, 'self')
.Add(HATEOAS._TYPE, TMVCMediaType.APPLICATION_JSON);
Links.AddRefLink.Add(HATEOAS.HREF, '/people').Add(HATEOAS.REL, 'people').Add(HATEOAS._TYPE,
TMVCMediaType.APPLICATION_JSON);
end);
finally
lPerson.Free;

View File

@ -1,7 +1,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{8CCDACDA-3FA5-486E-AD8E-63E4113177EE}</ProjectGuid>
<ProjectVersion>18.6</ProjectVersion>
<ProjectVersion>18.7</ProjectVersion>
<FrameworkType>None</FrameworkType>
<MainSource>renders.dpr</MainSource>
<Base>True</Base>
@ -89,6 +89,11 @@
<Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
<AUP_INTERNET>true</AUP_INTERNET>
<Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
<Android_NotificationIcon24>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png</Android_NotificationIcon24>
<Android_NotificationIcon36>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png</Android_NotificationIcon36>
<Android_NotificationIcon48>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png</Android_NotificationIcon48>
<Android_NotificationIcon72>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png</Android_NotificationIcon72>
<Android_NotificationIcon96>$(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png</Android_NotificationIcon96>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<Manifest_File>None</Manifest_File>
@ -317,6 +322,12 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders\default.txvpck" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule">
<Platform Name="iOSSimulator">
<Overwrite>true</Overwrite>
@ -328,19 +339,13 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders\default.txaPackage" Configuration="Debug" Class="ProjectFile">
<DeployFile LocalName="ModelSupport_renders\renders1\default.txvpck" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders\default.txvpck" Configuration="Debug" Class="ProjectFile">
<Platform Name="Linux64">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\RenderSampleControllerU\default.txaPackage" Configuration="Release" Class="ProjectFile">
<DeployFile LocalName="ModelSupport_renders\renders\default.txaPackage" Configuration="Debug" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
@ -352,13 +357,13 @@
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders1\default.txvpck" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<DeployFile LocalName="ModelSupport_renders\renders\default.txvpck" Configuration="Debug" Class="ProjectFile">
<Platform Name="Linux64">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployFile LocalName="ModelSupport_renders\renders\default.txvpck" Configuration="Release" Class="ProjectFile">
<DeployFile LocalName="ModelSupport_renders\RenderSampleControllerU\default.txaPackage" Configuration="Release" Class="ProjectFile">
<Platform Name="Win32">
<RemoteDir>.\</RemoteDir>
<Overwrite>true</Overwrite>
@ -560,6 +565,12 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Colors">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
@ -596,6 +607,36 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
@ -620,6 +661,12 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
@ -718,6 +765,17 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024x768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -729,6 +787,39 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668x2388">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -740,6 +831,61 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x2732">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2224">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2388x1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2732x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -751,6 +897,116 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768x1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1136x640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242x2688">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1334">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1792">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2208">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2436">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2688x1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
@ -784,6 +1040,28 @@
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch750">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch828">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>

View File

@ -1,18 +1,34 @@
// ***************************************************************************
//
// Delphi MVC Framework
//
// Copyright (c) 2010-2019 Daniele Teti and the DMVCFramework Team
//
// https://github.com/danieleteti/delphimvcframework
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// *************************************************************************** }
unit MVCFramework.Console;
interface
type
TConsoleMode = (Normal, Bright);
TConsoleColor = (
Black = 30,
Red = 31,
Green = 32,
Yellow = 33,
Blue = 34,
Magenta = 35,
Cyan = 36,
White = 37);
TConsoleColor = (Black = 30, Red = 31, Green = 32, Yellow = 33, Blue = 34, Magenta = 35, Cyan = 36, White = 37);
procedure ResetConsole;
procedure TextColor(const Color: TConsoleColor);
@ -23,12 +39,10 @@ implementation
uses
{$IFDEF MSWINDOWS}
{$IFDEF MSWINDOWS}
WinApi.Windows,
{$ENDIF}
{$ENDIF}
System.SysUtils;
const
@ -37,7 +51,7 @@ const
var
GForeGround: TConsoleColor;
GBackGround: TConsoleColor;
GMode: TConsoleMode = TConsolemode.Normal;
GMode: TConsoleMode = TConsoleMode.Normal;
function ToBackGround(const ForeGround: Byte): Byte;
begin

View File

@ -292,11 +292,16 @@ begin
raise EMVCDuckTypingException.Create
('Cannot find method Indexed property "Items" or method "GetItem" or method "GetElement" in the Duck Object.');
lValue := FGetItemMethod.Invoke(FObjectAsDuck, [AIndex]);
if not lValue.IsObject then
if lValue.Kind = tkInterface then
begin
raise EMVCDuckTypingException.Create('Items in list can be only objects');
Exit(TObject(lValue.AsInterface));
end;
Result := lValue.AsObject;
if lValue.Kind = tkClass then
begin
Exit(lValue.AsObject);
end;
raise EMVCDuckTypingException.Create('Items in list can be only objects or interfaces');
end;
function TDuckTypedList.GetOwnsObjects: Boolean;

View File

@ -221,6 +221,11 @@ var
LEnumPrefix: string;
LEnumName: string;
begin
if SameText(AName, 'RefCount') then
begin
Exit;
end;
if AValue.IsEmpty then
begin
AJsonObject[AName] := Null;
@ -1369,9 +1374,8 @@ begin
LIgnoredAttrs := TList<string>.Create;
try
LIgnoredAttrs.AddRange(AIgnoredAttributes);
if Assigned(GetRttiContext.GetType(TObject(AObject).ClassType).GetProperty('RefCount')) then
LIgnoredAttrs.Add('RefCount');
// if Assigned(GetRttiContext.GetType(TObject(AObject).ClassType).GetProperty('RefCount')) then
// LIgnoredAttrs.Add('RefCount');
Result := SerializeObject(TObject(AObject), AType, TMVCIgnoredList(LIgnoredAttrs.ToArray), ASerializationAction);
finally
LIgnoredAttrs.Free;

View File

@ -601,6 +601,7 @@ type
FContext: TWebContext;
FContentCharset: string;
FResponseStream: TStringBuilder;
function ToMVCList(const AObject: TObject; AOwnsObject: Boolean = False): IMVCList;
public
function GetContentType: string;
function GetStatusCode: Integer;
@ -3060,6 +3061,11 @@ begin
GetContext.Response.StatusCode := AValue;
end;
function TMVCRenderer.ToMVCList(const AObject: TObject; AOwnsObject: Boolean): IMVCList;
begin
Result := MVCFramework.DuckTyping.WrapAsList(AObject,AOwnsObject);
end;
procedure TMVCController.SetViewData(const aModelName: string; const Value: TObject);
begin
GetViewModel.Add(aModelName, Value);