Code Monkey home page Code Monkey logo

danieleteti / delphimvcframework Goto Github PK

View Code? Open in Web Editor NEW
1.2K 167.0 344.0 274.93 MB

DMVCFramework (for short) is a popular and powerful framework for WEB API in Delphi. Supports RESTful and JSON-RPC WEB APIs development.

License: Apache License 2.0

Batchfile 0.11% Python 0.29% Pascal 70.97% C++ 19.55% HTML 0.06% C 6.17% SQLPL 0.08% PLpgSQL 2.32% Eiffel 0.42% CMake 0.04%
restful restful-api restful-webservices application-server native delphi serialization-library speed jsonwebtoken jwt-authentication

delphimvcframework's Introduction

DelphiMVCFramework Mentioned in Awesome Go GitHub All Releases

๐Ÿ’ป Code Contributors

Table of Contents

DelphiMVCFramework Logo

What's DelphiMVCFramework

DMVCFramework is a very popular Delphi framework which provides an easy to use, scalable, flexible RESTful, JSON-RPC and ActiveRecord framework for Delphi developers. DMVCFramework is the most popular Delphi project on GitHub and compiles for Windows (32 and 64bit) and Linux (64bit). DMVCFramework services can be compiled as console application, Windows Service, Linux daemon, Apache module (Windows and Linux) and IIS ISAPI (Windows).

DMVCFramework works with Delphi 11 Alexandria, Delphi 10.4 Sydney, Delphi 10.3 Rio, Delphi 10.2 Tokyo, Delphi 10.1 Berlin, Delphi 10 Seattle.

Support DMVCFramework

Are you using DMVCFramework? Do you want to say "Thanks"? Become a Patron!

DelphiMVCFramework Main Features

  • DMVCFramwork is simple to use, has a lot of examples, is documented and there are a lot of tutorials available.

  • DMVCFramework is very well documented and the book DMVCFramework - the official guide is available to fastly get a solid knowledge (available as e-book and hardcopy).

  • Project Roadmap is always public

  • There are more than 40 samples to learn all the features and be proficient and productive

  • Commercially supported by bit Time Professionals (training, consultancy, custom development etc.)

  • RESTful (RMM Level 3) compliant

  • JSON-RPC 2.0 Support with automatic objects remotization (check sample)

  • DMVCFramework' MVCActiveRecord allows an easy and fast database access.

  • Stable and solid, used by small/mid/big projects since 2010

  • Very fast! (2.x was pretty fast and now, 3.x is 60% faster than the 2.x!)

  • Support group at https://www.facebook.com/groups/delphimvcframework with more than 4900 active members

  • Can be used in load balanced environment

  • Wizard for the Delphi IDE. It makes DelphiMVCFramework even more simple to use!

  • Optional session support

  • JSON Web Token Support (JWT) (check sample)

  • Extendable using middleware - simple hooks to handle request/response (check sample)

  • Flexible yet simple to use, authorization/authentication framework based on industry standards.

    • HTTP Basic Authentication
    • JWT Authentication
    • Custom Authentication
    • CORS support
  • Controllers inheritance! You can define your own base controller and inherit from it.

  • Fancy URL with parameter mappings

  • Specialized renders to generate text, HTML, JSON.

  • Powerful and customizable mapper to serialize/deserialize data.

  • Can be packaged as stand alone server, apache module (XE6 or better) and ISAPI dll

  • Integrated REST Client

  • Works on Linux (Delphi 10.2 Tokyo or better)

  • Completely unit tested (more than 250 unit tests)

  • There is a sample for each functionality (check the dmvcframework_(yourversion)_samples.zip)

  • Server side generated pages using Mustache for Delphi or TemplatePro

  • Specific trainings are available (email to [email protected] for a date and a place)

  • Push notifications support using ServerSentEvents

  • Automatic documentation through /system/describeserver.info

  • Driven by its huge community (Facebook group https://www.facebook.com/groups/delphimvcframework)

  • Semantic Versioning

  • To get a fast introduction to DMVCFramework read the slides from ITDevCon conference

Install the latest stable version

If you are not involved in development or testing, do not clone the repo! Use the Github release!

The last stable version available here ๐Ÿ“ฅ. Just download latest release as a zip file and you are ok. Samples are available as separate zip file downloadable from the same page where you download the release.

Book: "DelphiMVCFramework - the official guide"

The official guide for DMVCFramework is available. DMVCFramework has a lot functionalities and can really help your business. However many developers don't use it at its full potential. Why don't get more when is easily available? The DMVCFramework lead developer and project coordinator Daniele Teti, wrote the official guide for this great framework.

DelphiMVCFramework - the official guide

Buy your copy and improve your DMVCFramework knowledge now! "DMVCFramework - the official guide" is available as e-book and hardcopy, pick what you prefer.

While a huge work has been done by the author and the reviews to make the book and the examples well written, complete and effective, things can be always improved. For any suggestions, complains or requests there is the official Github book project (https://github.com/danieleteti/dmvcframeworktheofficialguide) where you can fill an issue and get in touch directly with the author.

Book translations

Given the success of DMVCFramework in the Delphi community, the official DMVCFramework guide has been translated also in the following languages.


Please, if you use DMVCFramework "star" this project in GitHub! It cost nothing to you but helps other developers to reference the code.

How to partecipate to DMVCFramework development and/or tests

Only if you want to participate to the testing phase (which usually contains brand new features but can sometimes be instable) you can get the development version clonig this repo or downloading the master repository zip file. Take in mind that even if development version is usually very stable, it isn't not ready for production utilization.

Sponsors

While DMVCFramework is born from the head of Daniele Teti from bit Time Professionals, it wouldn't what is now without the support and work of many people all around the world. The following companies sponsored some specific part of DMVCFramework so they wort a special mention.

GOLD SPONSORS

COMPANY NAME LOGO
bit Time Professionals
bit Time Professionals - ITALY
bit Time Software

SILVER SPONSOR

COMPANY NAME LOGO
Centro Software
Delphi Studio ES
Orion Law
Vivaticket

What users say about DMVCFramework

"Our wishes are coming true" -- one Delphi programmer after a small dmvcframework demo for an IT department of a very important national research institute

"I'm still amazed by the DelphiMVCFramework code and documentation. Thank you very much and I am amazed by your quick feedback." -- Benjamin Yang (Director of SQLGate)

"DMVCFramework and the Entity utility are fantastic!" -- Roberto

"DMVCFramework is a great framework. It's very intuitive, fast, easy to use, actually there is nothing more to ask for." -- Samir

"Wow! To do that in J2EE it takes 2 days" -- a training participant after a 5 minutes demo.

"I'm starting with the DMVCFramework and I'm finding it fantastic, congratulations for the project!" -- Rafael

"I'm looking at DMVCFramework project in it works great - for my use case scenarios is much better than 'Similar commercial product'." -- Luka

"It's fantastic! Just define your entities and you are up and running in 5 minutes. Nothing comparable on the market." -- Marco

"The best framework for creating web servers with Delphi! It is very easy to create Delphi servers and publish APIs and Rest resources. Congratulations to Daniele Teti and all the staff for the excellent work!" -- Marcos N.

We started the process of migrating our systems to micro services and are loving the DMVCFramework "DMVCFramework is definitely part of our lives right now". -- E. Costa

"Thank you for the great framework! We are very happy with this!" -- Andreas

"I managed to generate an API for my application thanks to this framework, it is truly useful and efficient!" -- J. Urbani

What's New in DMVCFramework-3.4.1-sodium (stable version)

๐Ÿ‘‰ A deep analisys of what's new in DelphiMVCFramework-3.4.1-sodium is available on Daniele Teti Blog ๐Ÿ‘ˆ

Older Versions

What's New in DMVCFramework-3.4.0-neon

๐Ÿ‘‰ Deeper analisys of what's new in DelphiMVCFramework-3.4.0-neon is available on Daniele Teti Blog ๐Ÿ‘ˆ

  • โšก Added support for dotEnv

  • โšก Added MSHeap memory manager for Win32 and Win64 (https://github.com/RDP1974/DelphiMSHeap)

  • ๐Ÿž FIX Issue 664 Thanks to MPannier

  • ๐Ÿž FIX Issue 667

  • ๐Ÿž FIX Issue 680

  • ๐Ÿž FIX Issue 682 (Thanks to wuhao13)

  • ๐Ÿž FIX Wrong comparison in checks for ro/RW/PK fields in TMVCActiveRecord

  • ๐Ÿž FIX wrong default initialization for JWT (thanks to Flavio Basile)

  • โšก Wizard updated to be dotEnv aware

  • โšก Added HTMX server side support through unit samples\htmx\MVCFramework.HTMX.pas and the relative sample (Thanks to David Moorhouse). This unit provides class helper for TMVCWebRequest and TMVCWebResponse classes to easily work with HTMX. If you want to use this unit just download the samples and add it to your project or put $(DMVCHOME)\samples\htmx in your library path.

  • โšก Added "Load Style" methods to TMVCActiveRecord (more info #675)

    • TMVCActiveRecord support "Factory Style" and "Load Style" methods when loads data from database.

      Using "Factory Style" methods (available from the first version) the result list is returned by the loader method (as shown in this piece of code from the activerecord_showcase sample).

        Log('>> RQL Query (2) - ' + cRQL2);
        lCustList := TMVCActiveRecord.SelectRQL<TCustomer>(cRQL2, 20);
        try
          Log(lCustList.Count.ToString + ' record/s found');
          for lCustomer in lCustList do
          begin
            Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault,
              lCustomer.CompanyName.ValueOrDefault, lCustomer.City]));
          end;
        finally
          lCustList.Free;
        end;

      For some scenarios would be useful to have also "Load Style" methods where the list is filled by the loader method (not instantiated internally).

        Log('>> RQL Query (2) - ' + cRQL2);
        lCustList := TObjectList<TCustomer>.Create;
        try
          lRecCount := TMVCActiveRecord.SelectRQL<TCustomer>(cRQL2, 20, lCustList); //new in 3.4.0-neon
          Log(lRecCount.ToString + ' record/s found');
          for lCustomer in lCustList do
          begin
            Log(Format('%5s - %s (%s)', [lCustomer.Code.ValueOrDefault,
              lCustomer.CompanyName.ValueOrDefault, lCustomer.City]));
          end;
        finally
          lCustList.Free;
        end;
  • โšก Better error message in case of serialization of TArray<TObject>

  • โšก Improved CORS handling - Issue 679 (Thanks to David Moorhouse)

  • โšก Improved serialization of TObjectList<TDataSet> (however ObjectDict is still the preferred way to serialize multiple datasets).

  • โšก Added static method for easier cloning of FireDAC dataset into TFDMemTable.

  • In the class EMVCException the property HTTPErrorCode has been renamed in HTTPStatusCode.

  • โšก Functional Actions

    • In addition to the classic procedure based actions, now it's possibile to use functions as actions. The Result variable is automatically rendered and, if it is an object, its memory is freed.

      type
        [MVCNameCase(ncCamelCase)]
        TPersonRec = record
          FirstName, LastName: String;
          Age: Integer;
          class function Create: TPersonRec; static;
        end;
      
        [MVCNameCase(ncCamelCase)]
        TPerson = class
        private
          fAge: Integer;
          fFirstName, fLastName: String;
        public
          property FirstName: String read fFirstName write fFirstName;
          property LastName: String read fLastName write fLastName;
          property Age: Integer read fAge write fAge;
        end;
      
        [MVCPath('/api')]
        TMyController = class(TMVCController)
        public
          { actions returning a simple type }
          [MVCPath('/sumsasinteger/($A)/($B)')]
          function GetSum(const A, B: Integer): Integer;
          [MVCPath('/sumsasfloat/($A)/($B)')]
          function GetSumAsFloat(const A, B: Extended): Extended;
      
          { actions returning records }
          [MVCPath('/records/single')]
          function GetSingleRecord: TPersonRec;
          [MVCPath('/records/multiple')]
          function GetMultipleRecords: TArray<TPersonRec>;
      
          { actions returning objects }
          [MVCPath('/objects/single')]
          function GetSingleObject: TPerson;
          [MVCPath('/objects/multiple')]
          function GetMultipleObjects: TObjectList<TPerson>;
      
          { actions returning datasets }
          [MVCPath('/datasets/single')]
          function GetSingleDataSet: TDataSet;
          [MVCPath('/datasets/multiple')]
          function GetMultipleDataSet: TEnumerable<TDataSet>;
          [MVCPath('/datasets/multiple2')]
          function GetMultipleDataSet2: IMVCObjectDictionary;
      
          { customize response headers }
          [MVCPath('/headers')]
          function GetWithCustomHeaders: TObjectList<TPerson>;
        end;

      Check sample "function_actions_showcase.dproj" for more info.

  • โšก Improved TMVCResponse type to better suits the new functional actions.

    TMVCResponse can be used with "message based" responses and also with "data based" responses (with single object, with a list of objects or with a dictionary of objects).

    More info here

  • Removed statuscode, reasonstring and all the field with a default value from exception's JSON rendering. All the high-level rendering methods will emit standard ReasonString.

    Before

    {
        "apperrorcode": 0,
        "statuscode": 404,
        "reasonstring": "Not Found"
        "classname": "EMVCException",
        "data": null,
        "detailedmessage": "",
        "items": [],
        "message": "[EMVCException] Not Found"
    }
    

    Now

    {
        "classname": "EMVCException",
        "message": "Not Found"
    }
  • โšก New! SQL and RQL Named Queries support for TMVCActiveRecord.

    Here's all the new methods available for Named Queries

        class function SelectByNamedQuery<T: TMVCActiveRecord, constructor>(
          const QueryName: String;
          const Params: array of Variant;
          const ParamTypes: array of TFieldType;
          const Options: TMVCActiveRecordLoadOptions = []): TObjectList<T>; overload;
        class function SelectByNamedQuery(
          const MVCActiveRecordClass: TMVCActiveRecordClass;
          const QueryName: String;
          const Params: array of Variant;
          const ParamTypes: array of TFieldType;
          const Options: TMVCActiveRecordLoadOptions = []): TMVCActiveRecordList; overload;
        class function SelectRQLByNamedQuery<T: constructor, TMVCActiveRecord>(
          const QueryName: String;
          const Params: array of const;
          const MaxRecordCount: Integer): TObjectList<T>; overload;
        class function SelectRQLByNamedQuery(
          const MVCActiveRecordClass: TMVCActiveRecordClass;
          const QueryName: String;
          const Params: array of const;
          const MaxRecordCount: Integer): TMVCActiveRecordList; overload;
        class function DeleteRQLByNamedQuery<T: TMVCActiveRecord, constructor>(
          const QueryName: String;
          const Params: array of const): Int64;
        class function CountRQLByNamedQuery<T: TMVCActiveRecord, constructor>(
          const QueryName: string;
          const Params: array of const): Int64;

    MVCNamedSQLQuery allows to define a "named query" which is, well, a SQL query with a name. Then such query can be used by the method SelectByNamedQuery<T> or SelectByNamedQuery. Moreover in the attribute it is possible to define on which backend engine that query is usable. In this way you can define optimized query for each supported DMBS you need.

    More info here

What's New in DMVCFramework-3.3.0-fluorine

  • โšก Support for Delphi 11.3 Alexandria
  • โšก Ability to use records in swagger param and response attributes Issue 649
  • โšก Improved Wizard - now it produces commented code to show how to use ContextEvents
  • โšก Improved compatibility with Delphi 10.2 Tokyo and older versions (Thanks Mark Lobanov)
  • โšก Added sample and middleware for Prometheus (using https://github.com/marcobreveglieri/prometheus-client-delphi)
  • โšก Added "Profiler.LogsOnlyIfOverThreshold" which logs only if over the defined threshold
  • ๐Ÿž FIX Issue 648 Thanks to sf-spb
  • ๐Ÿž FIX Issue 652 Thanks to BssdTS
  • ๐Ÿž PR 651 Thanks to Francisco Zanini

What's New in DMVCFramework-3.2.3-radium

  • โšก Default error responses contains the official "reason string" associated to the HTTP status code (this can be a breaking change for some generic client which doesn't correctly interpret the http status code)

  • โšก Added static method HTTP_STATUS.ReasonStringFor(HTTPStatusCode) wich returns the standard ReasonString for a given HTTP status code.

  • โšก Improved handling of TMVCErrorResponse information

  • โšก mid-air-collision handling now uses SHA1 instead of MD5

  • โšก Added MVCFramework.Commons.MVC_HTTP_STATUS_CODES const array containing all the HTTP status codes with its ReasonString.

  • โšก Support for TObject descendants in JSONRPC APIs (not only for JSONObject and JSONArray).

  • โšก New global configuration variable MVCSerializeNulls.

    • When MVCSerializeNulls = True (default) empty nullables and nil are serialized as json null.
    • When MVCSerializeNulls = False empty nullables and nil are not serialized at all.
  • โšก Nullable types now have Equal method support, the new method TryHasValue(out Value) works like HasValue but returns the contained value if present. Also there is a better "equality check" strategy.

  • โšก Unit tests now are always executed for Win32 and Win64 bit (both client and server).

  • โšก Added TMVCActiveRecord.Refresh method

  • โšก Unit test suites generates one NUnit XML output file for each platform

  • โšก New built-in profiler (usable with Delphi 10.4+) - to profile a block of code, write the following

    procedure TMyController.ProfilerSample1;
    begin
      NotProfiled(); //this line is not profiled
      //the following begin..end block will be profiled
      //timing will be saved in a "profiler" log
      begin var lProf := Profiler.Start(Context.ActionQualifiedName);
        DoSomething();
        DoSomethingElse();
        Render('Just executed ' + Context.ActionQualifiedName);
      end; // profiler writes automatically to the log
      NotProfiled(); //this line is not profiled
    end;
    
    procedure TMyController.DoSomething;
    begin
      begin var lProf := Profiler.Start('DoSomething');
        Sleep(100);
      end;
    end;
    
    procedure TMyController.DoSomethingElse;
    begin
      begin var lProf := Profiler.Start('DoSomethingElse');
        Sleep(100);
        DoSomething();
      end;
    end;
    
    procedure TMyController.NotProfiled;
    begin
      Sleep(100);
    end;

    The log contains the following lines - check the caller/called relationship shown using >> and << and the deep level

    [>>][     1][MainControllerU.TMyController.ProfilerSample1] [profiler]
    [ >>][     2][DoSomething] [profiler]
    [ <<][     2][DoSomething][ELAPSED: 00:00:00.1088214] [profiler]
    [ >>][     2][DoSomethingElse] [profiler]
    [  >>][     3][DoSomething] [profiler]
    [  <<][     3][DoSomething][ELAPSED: 00:00:00.1096617] [profiler]
    [ <<][     2][DoSomethingElse][ELAPSED: 00:00:00.2188468] [profiler]
    [<<][     1][MainControllerU.TMyController.ProfilerSample1][ELAPSED: 00:00:00.3277806] [profiler]
    

    To get more info check the "profiling" example.

    All profiler logs are generated with a log level info. If measured time is greater than WarningThreshold the log level is warning.

    WarningThreshold is expressed in milliseconds and by default is equals to 1000.

  • โšก New Context property named ActionQualifiedName which contains the currently executed action in the form UnitName.ClassName.ActionName. It is available where the Context property is available. Obviously is not available in the OnBeforeRouting middleware events.

  • โšก Added ObjectPool and IntfObjectPool (and related unit tests). Thanks to our sponsor Vivaticket S.p.A.

  • โšก Method procedure Render(const AErrorCode: Integer; const AErrorMessage: string = '' ... has been renamed to RenderStatusMessage with a better parameter names.

  • โšก IMVCJSONRPCExecutor supports async call. Thanks to our sponsor Orion Law. Check the new Async sample in samples\jsonrpc_with_published_objects\.

  • โšก Removed foTransient if TMVCActiveRecord FieldOptions. It became obsolete after introduction of foReadOnly and foWriteOnly.

  • โšก Improved TMVCActiveRecordMiddleware. Now it can handle multiple connections for the same request. Also, you can completely omit the 'default' connection and just specify wich connection you want to use before starting to create your TMVCActiveRecord inherited entities.

Bug Fix in 3.2.3-radium

More details about dmvcframework-3.2.3-radium fixes here

What's new in DMVCFramework-3.2.2-nitrogen

  • โšกNew! Support for Delphi 11.x Alexandria

  • โšกNew TMVCRESTClient implementation based on *Net components, the previous one was based on INDY Components (thanks to Joรฃo Antรดnio Duarte).

  • โšกNew! MVCJSONRPCAllowGET attribute allows a remote JSON-RPC published object, or a specific method, to be called using GET HTTP Verb as well as POST HTTP Verb. POST is always available, GET is available only if explicitly allowed. IMVCJSONRPCExecutor allows to specify which HTTP Verb to use when call the server JSON-RPC methods. The default verb can be injected in the constructor and each ExecuteRequest/ExecuteNotification allows to override od adhere to the instance default.

  • โšกNew! eLua server side view support added! The View engine requires Lua's dlls so it is not included in the main package but in a sampl project. Check serversideviews_lua sample.

  • โœ… Improved! Under some heavy load circumnstances the logger queue can get full. Now TThreadSafeQueue class uses a cubic function instead of a linear one to wait in case of very high concurrency. This allows a better resiliency in case of high load.

  • โœ… Improved internal architecture of custom type serializers in case of dynamic linked packages.

  • โœ… Improved Swagger/OpenAPI support for System Controllers and improved support for param models.

  • โšกNew TMVCLRUCache implementation. Very efficient implementation of LRU cache borrowed directly from DMSContainer

  • โšกNew TMVCRedirectMiddleware to handle HTTP redirections in a very simple and flexible way.

  • โšกNew! TMVCActiveRecord supports XML field type in PostgreSQL (in addition to JSON and JSONB).

  • โšกNew OnContextCreate and OnContextDetroyed events for TMVCEngine.

  • โšกNew! Added parameter RootNode in BodyFor and BodyForListOf<T> methods, just like the BodyAs* methods.

  • โšกNew! Added NullableTGUID in MVCFramework.Nullables.pas.

  • โšกNew property CustomIntfObject: IInterface in TWebContext. This property can be used to inject custom services factory.

    procedure TMyWebModule.WebModuleCreate(Sender: TObject);
    begin
      FMVC := TMVCEngine.Create(Self,
        procedure(Config: TMVCConfig)
        begin
          //configuration code
        end);
      FMVC.AddController(TMyController);
      FMVC.OnWebContextCreate(
        procedure(const CTX: TWebContext)
        begin
          CTX.CustomIntfObject := TServicesFactory.Create; //implements an interface
        end);
      FMVC.OnWebContextDestroy(
        procedure(const CTX: TWebContext)
        begin
          //do nothing here
        end);
    end;
  • โœ… Added parameter to set local timeStamp as UTC.

  • โœ… Improved OpenAPI (Swagger) support.

  • โœ… Improved Support for OpenAPI (Swagger) API Versioning (check swagger_api_versioning_primer sample)

  • โœ… Improved! The unit tests fully test PostgreSQL, FirebirdSQL and SQLite while testing MVCActiveRecord framework. The other engines are tested using activerecord_showcase sample project.

  • โœ… Improved! MVCActiveRecord does a better job to handle TDate/TTime/TDateTime types for SQLite (it is automatic because SQLite doesn't support date/time types).

  • โœ… Improved! PostgreSQL, FirebirdSQL, Interbase and SQLite now support tablename and fields with spaces.

  • โœ… Improved Nullable Types. Now it's possible to assign nil to a nullable type and to check its state using the new property IsNull which is the negation of the already available property HasValue.

  • โœ… Improved! Now TMVCStaticFileMiddleware is able to manage high-level criteria to show/hide/mask specific files in the document web root. Check Issue 548 and the updated sample samples\middleware_staticfiles\ for more info.

  • โœ… Improved! In case of multiple MVCPath, Swagger consider only the first one (Thanks to V. Ferri and our sponsors)

  • โšกNew! Mechanism to customize the JWT claims setup using the client request as suggested in issue495

  • โšกNew! Added TMVCActiveRecord.Merge<T>(CurrentListOfT, ChangesOfT) to allow merge between two lists of TMVCActiveRecord descendants using UnitOfWork design pattern. Check the button "Merge" in demo "activerecord_showcase".

  • โšก New! Added default filtering for TMVCActiveRecord descendants (check activerecord_showcase sample project).

  • โšก New! Serialization and Deserialization for Pascal set (Thanks to rshuck for his suggestions)

  • โšก New! Added partitioning for TMVCActiveRecord descendants (more info ASAP)

  • โœ… Dramatically improved all "JSON-To-DataSet" operations (1 order of magnitude c.a.). Thanks to MPannier and David Moorhouse for their detailed analysis - More info here.

  • โœ… Improved! After a big refactoring ("I love to delete code" -- cit. Daniele Teti), support a new SQLGenerator is just 2 (two) methods away! Just as example, this is the current version of TMVCSQLGeneratorPostgreSQL

    type
      TMVCSQLGeneratorPostgreSQL = class(TMVCSQLGenerator)
      protected
        function GetCompilerClass: TRQLCompilerClass; override;
      public
        function CreateInsertSQL(
          const TableName: string;
          const Map: TFieldsMap;
          const PKFieldName: string;
          const PKOptions: TMVCActiveRecordFieldOptions): string; override;
        function GetSequenceValueSQL(const PKFieldName: string;
          const SequenceName: string;
          const Step: Integer = 1): string; override;
      end;
  • โšก New! Added new default parameter to TMVCActiveRecord.RemoveDefaultConnection and TMVCActiveRecord.RemoveConnection to avoid exceptions in case of not initialized connection.

  • โšก New! Added the new MVCOwned attribute which allows to auto-create nested objects in the deserialization phase. This will not change the current behavior, you ned to explocitly define a property (or a field) as MVCOwned to allows the serialization to create or destroy object for you.

  • โœ… Improved! Context.Data property is now created on-demand using a lazy loading approach (expect an overall speed improvement).

  • โœ… Added LogException function in MVCFramework.Logger.pas to easily log exception in standard way.

  • โœ… Improved MVCAREntitiesGenerator project - now it can better handle border cases, field names which collide with Delphi keywords and a big number of tables.

  • โœ… Improved error handling for JSON-RPC APIs (Thanks to David Moorhouse). More info here.

  • โœ… Improved parameter handling for enum and set in JSON-RPC APIs.

  • โšก New! Added ActiveRecordConnectionRegistry.AddDefaultConnection(const aConnetionDefName: String). The connection definition must be known by FireDAC. This method simplifies the most common scenario shown below.

    ActiveRecordConnectionRegistry.AddDefaultConnection('MyConDefName');
    try
      //Use active record classes
    finally
      ActiveRecordConnectionRegistry.RemoveDefaultConnection;
    end;
  • โšก New! Added ToJSONObject and ToJSONArray to the IMVCRESTResponse. These methods automatically parse the response body and return a TJSONObject or a TJSONArray respectively. These methods work as a factory - the client code need to handle returned istances. Is the body is not compatible with the request (a.k.a. is not a JSONObject in case of ToJSONObject, or is not a JSONArray in case of ToJSONArray) an exception is raised.

  • โšก New! Added support for primary GUID (UUID) primary keys, attributes and serialization (More info at issue 552). Thanks to Marcelo Jaloto for its important collaboration.

  • โšก New! Added TMVCJWTBlackListMiddleware to allow black-listing and (a sort of) logout for a JWT based authentication. This middleware must be registered after the TMVCJWTAuthenticationMiddleware.

    This middleware provides 2 events named: OnAcceptToken (invoked when a request contains a token - need to returns true/false if the token is still accepted by the server or not) and OnNewJWTToBlackList (invoked when a client ask to blacklist its current token). There is a new sample available which shows the funtionalities: samples\middleware_jwtblacklist.

  • โšกNew! MVCFromBody attribute, useful to automatically inject the request body as actual object in the action paramaters. For instance in the following action the body request is automatically deserialized as an object of class TPerson.

    //interface
    [MVCHTTPMethod([httpPOST])]
    [MVCPath('/people')]
    procedure CreatePerson(const [MVCFromBody] Person: TPerson);
    
    //implementation
    procedure TRenderSampleController.CreatePerson(const Person: TPerson);
    begin
      //here you can directly use Person without call Context.Request.BodyAs<TPerson>
      //the Person object lifecycle is automatically handled by dmvcframework, so don't destroy      
      //If the request body doesn't exist (or cannot be deserialized) an exception is raised.      
    end;

    MVCFromBody can be used also with "Collection Like" data structures. //interface

    [MVCDoc('Creates new articles from a list and returns "201: Created"')]
    [MVCPath('/bulk')]
    [MVCHTTPMethod([httpPOST])]
    procedure CreateArticles(const [MVCFromBody] ArticleList: TObjectList<TArticle>);
    
    //implementation
    procedure TArticlesController.CreateArticles(const ArticleList: TObjectList<TArticle>);
    var
      lArticle: TArticle;
    begin
      for lArticle in ArticleList do
      begin
        GetArticlesService.Add(lArticle);
      end;
      Render(201, 'Articles Created');
    end;    
  • โšกNew! MVCFromQueryString attribute, useful to automatically inject a query string paramater an action paramater. For instance in the following action the query string params fromDate is automatically deserialized as a TDate value and injected in the action.

    //interface
    [MVCHTTPMethod([httpGET])]
    [MVCPath('/invoices')]
    procedure GetInvoices(const [MVCFromQueryString('fromDate')] FromDate: TDate);
    
    //implementation
    procedure TRenderSampleController.GetInvoices(const FromDate: TDate);
    begin
      //here FromDate is a valid TDate value deserialized from the querystring paramater
      //named fromDate. 
      //If the query string parameter doesn't exist (or cannot be deserialized) an exception is raised.
    end;
  • โšกNew! MVCFromHeader attribute, useful to automatically inject a header value as an action parameter. For instance in the following action the header params XMyCoolHeader is automatically deserialized as String value and injected in the action.

    //interface
    [MVCHTTPMethod([httpGET])]
    [MVCPath('/invoices')]
    procedure GetInvoices(const [MVCFromQueryString('fromDate')] FromDate: TDate; const [MVCFromHeader('X-MY-COOL-HEADER')] XMyCoolHeader: String);
    
    //implementation
    procedure TRenderSampleController.GetInvoices(const FromDate: TDate; const XMyCoolHeader: String);
    begin
      //here XMyCoolHeader is a string read from the "X-MY-COOL-HEADER' request header.
      //If the header doesn't exist (or cannot be deserialized) an exception is raised.
    end;
  • โšกNew! MVCFromCookie attribute, useful to automatically inject a cookie value as an action parameter. For instance in the following action the cookie MyCoolCookie is automatically deserialized as TDate value and injected in the action.

    //interface
    [MVCHTTPMethod([httpGET])]
    [MVCPath('/invoices')]
    procedure GetInvoices(
      const [MVCFromQueryString('fromDate')] FromDate: TDate; 
      const [MVCFromHeader('X-MY-COOL-HEADER')] XMyCoolHeader: String;
      const [MVCFromCookie('MyCoolCookie')] MyCoolCookie: TDate;
      );
    
    //implementation
    procedure TRenderSampleController.GetInvoices(const FromDate: TDate; const XMyCoolHeader: String; const MyCoolCookie: TDate);
    begin
      //here MyCoolCookie is a TDate read from "MyCoolCookie' cookie available in the request.
      //If the cookie doesn't exist (or cannot be deserialized) an exception is raised.
    end;
  • โœ… Improved! While not strictly required nor defined, DMVCFramework supports sending body data for all HTTP VERBS - see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET

  • โšก New! Automated support to avoid "mid-air collisions". New methods SetETag and CheckIfMatch allows a better security without adding complexity to the controller code - check avoid_mid_air_collisions_sample.dproj sample and see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag#avoiding_mid-air_collisions for more info about mid-air collisions.

  • โœ… Improved! Ignored fields handling now is much better in renders method and in ObjDict as well. See issue 528.

Bug Fixes in 3.2.2-nitrogen

Breaking Changes in 3.2.2-nitrogen

  • Removed deprecated constructor for TMVCJWTAuthenticationMiddleware - was deprecated since 2019. Just use the other one as suggested.
  • Changed signature of method IMVCMiddleware.OnAfterControllerAction

What's New in DelphiMVCFramework 3.2.1-carbon

This version is the version referenced by the DelphiMVCFramework - The Official Guide book (available in english, portuguese and spanish).

This version introduced new features in many different areas (swagger, server side view, MVCActiveRecord, renders etc.) however there is no a single-big-feature. This version contains also a good number of bugfixes. It's not a critical updated, but this is the best version ever (at least, so far...) and is the suggested version for starting new projects. Enjoy!

Improvements

  • docExpansion parameter for Swagger

  • New Context: TWebContext parameter in JSON-RPC Hooks

    { Called before any actual routing }
    procedure OnBeforeRoutingHook(const Context: TWebContext; const JSON: TJsonObject);
    { Called after routing and before the actual remote method invocation }
    procedure OnBeforeCallHook(const Context: TWebContext; const JSON: TJsonObject);
    { Called after actual remote method invocation, even if the method raised an exception }
    procedure OnAfterCallHook(const Context: TWebContext; const JSON: TJsonObject);
  • When a JSON-RPC Request returns a System.Boolean the result will be a JSON true or false and no 1 or 0 as it was in the 3.2.0-boron.

  • IMVCJSONRPCExecutor.ExecuteNotification returns a IJSONRPCResponse. In case of error response contains information about the error, in case of successful execution the response is a Null Object.

  • New React demo (Thanks to Angelo Sobreira da Silva)

  • Serialization support for TList<Integer>, TList<String>, TList<Boolean> and for all TList<T> of simple types.

  • Added method MetadataAsJSONObject(FieldNameCase: TMVCNameCase = ncLowerCase): TJSONObject; in TDataSetHelper. This method returns the dataset field definitions. While this is valid only for Delphi datasets, can be useful to describe a dataset to a Delphi client.

    {
    	"fielddefs": [
        	{
            	"datatype": 3,
                "displayname": "ID",
                "fieldname": "id",
                "precision": 0,
                "size": 0
             },
             {
             	"datatype": 24,
                "displayname": "CODE",
                "fieldname": "code",
                "precision": 0,
                "size": 5
             },
             {
             	"datatype": 24,
                "displayname": "DESCRIPTION",
                "fieldname": "description",
                "precision": 0,
                "size": 200
             },
             {
             	"datatype": 37,
                "displayname": "PRICE",
                "fieldname": "price",
                "precision": 18,
                "size": 2
              }
          ]
    }

    The static method class procedure TFireDACUtils.CreateDatasetFromMetadata( AFDMemTable: TFDMemTable; AMeta: TJSONObject); gets the previous structure and initialize the fields of AFDMemTable with it. When a TFDMemTable is initialized using this approach, the data can be directly loaded from a jsonarray of jsonobject with the same field names. WARNING: This mechanism works only for Delphi clients. Check sample articles_crud_vcl_client_meta.dproj to understand the involved mechanisms.

  • Added foReadOnly and foWriteOnly as field options in MVCTableField attribute (used by TMVCActiveRecord). Currently available field options are:

    • foPrimaryKey { it's the primary key of the mapped table }
    • foAutoGenerated { not written, read - similar to foReadOnly but is reloaded after insert and update }
    • foReadOnly { not written, read }
    • foWriteOnly { written, not read }

    Now it is possible to declare entities like the followings (or with any other combinations):

      [MVCNameCase(ncLowerCase)]
      [MVCTable('articles')]
      TArticleWithWriteOnlyFields = class(TCustomEntity)
      private
        [MVCTableField('ID', [foPrimaryKey, foAutoGenerated])]
        fID: NullableInt32;
        [MVCTableField('description', [foWriteOnly])]
        fDescription: string;
        [MVCTableField('price', [foWriteOnly])]
        fPrice: Integer;
      public
        property ID: NullableInt32 read fID write fID;
        property Description: string read fDescription write fDescription;
        property Price: Integer read fPrice write fPrice;
      end;
    
      [MVCNameCase(ncLowerCase)]
      [MVCTable('articles')]
      TArticleWithReadOnlyFields = class(TCustomEntity)
      private
        [MVCTableField('ID', [foPrimaryKey, foReadOnly])]
        fID: NullableInt32;
        fCode: NullableString;
        [MVCTableField('description', [foReadOnly])]
        fDescrizione: string;
        [MVCTableField('price', [foReadOnly])]
        fPrice: Currency;
      public
        property ID: NullableInt32 read fID write fID;
        property Code: NullableString read fCode write fCode;
        property Description: string read fDescription write fDescription;
        property Price: Currency read fPrice write fPrice;
      end;
  • Added the ability to deserialize an object, or alist of objects, starting from an arbitrary node in the JSON (or other format) present in the request body. Works for BodyAs<T> and for BodyAsListOf<T> (Thanks to Raphaรซl Emourgeon for the BodyAsListOf<T> implementation).

    procedure TBooksController.CreateBook;
    var
      lBook: TBook;
    begin
      //this call deserialize a TBook instance
      //starting from the 'book' node of
      //the request body
      lBook := Context.Request.BodyAs<TBook>('book');
      try
        lBook.Insert;
        Render201Created('/api/books/' + lBook.ID.ToString);
      finally
        lBook.Free;
      end;
    end;
  • Improved the primary key type handling for manual handling in MVCActiveRecord.

    procedure TMyBaseEntity.OnBeforeInsert;
    begin
      inherited;
      //regardless the name of the PK field
      //the following code fills the PK with a GUID
      //Inheriting the other entities from this, all
      //will inherit this behavior.
      SetPK(TValue.From<NullableString>(TGUID.NewGuid.ToString));
      
      //if the PK was a simple string, the code
      //should be like the following
      //SetPK(TGUID.NewGuid.ToString);  
    end;
    
  • Improved activerecord_showcase sample.

  • Improved TMVCStaticFilesMiddleware. Now is able to correctly serve SPA applications from any subfolder.

  • Added property Context.HostingFrameworkType. This property is of type TMVCHostingFrameworkType and can assume one of the following values: hftIndy (if the service is using the built-in Indy HTTP server) , hftApache (if the project is compiled as Apache module) or hftISAPI (if the project is compiled as ISAPI module).

  • TMVCNameCase got the new ncSnakeCase among the possibles casing (thanks to Joรฃo Antรดnio Duarte for its work in this area).

    Now the TMVCNameCase declaration is the following:

    TMVCNameCase = (ncAsIs, ncUpperCase, ncLowerCase, ncCamelCase, ncPascalCase, ncSnakeCase);

    Here's how the new ncSnakeCase works

    Original SnakeCase
    OneTwo one_two
    One__Two one_two
    OneTwo03 one_two_03
  • Support for Mustache partials (Thanks to David Moorhouse and his work about issue 221). Sample \samples\serversideviews_mustache has been updated to show how to use partials.

  • Added dynamic properties access to TMVCActiveRecord descendants. Indexed property Attributes is index using the property name and set/get a TValue representing the property value.

    procedure TMainForm.btnAttributesClick(Sender: TObject);
    var
      lCustomer: TCustomer;
      lID: Integer;
    begin
      lCustomer := TCustomer.Create;
      try
        lCustomer.Attributes['CompanyName'] := 'Google Inc.';
        lCustomer.Attributes['City'] := 'Montain View, CA';
        lCustomer.Attributes['Note'] := 'Hello there!';
        lCustomer.Attributes['Code'] := 'XX123';
        lCustomer.Attributes['Rating'] := 3;
        lCustomer.Insert;
        lID := lCustomer.ID;
      finally
        lCustomer.Free;
      end;
    
      lCustomer := TMVCActiveRecord.GetByPK<TCustomer>(lID);
      try
        Assert('Google Inc.' = 
        	lCustomer.Attributes['CompanyName']
        		.AsType<NullableString>().Value);
        Assert('Montain View, CA' = 	
        	lCustomer.Attributes['City'].AsString);
        Assert('XX123' = 
        	lCustomer.Attributes['Code']
        		.AsType<NullableString>().Value);
        Assert('Hello there!' = 
        	lCustomer.Attributes['Note'].AsString);
        lCustomer.Update;
      finally
        lCustomer.Free;
      end;
  • Breaking Change! TMVCStaticFileMiddleware cannot be registered to "/" anymore

    • The suggested solution is to create a simple redirection controller which redirect "/" to the proper path (check this example).
  • Breaking Change! DocumentRoot of TMVCStaticFileMiddleware must be a valid folder. If DocumentRoot doesn't exist an exception is raised.

  • Fix for issue 421

  • Fix for issue 424

  • Fix for issue436.

  • Fix for issue438 (Thanks to jadeade)

  • Fix for issue432

  • Fix for issue435 (Thanks to sonjli for its initial work)

  • Fix for issue434 (Thanks to David Moorhouse for his detailed analysis)

  • Fix for issue221

  • Fix for issue430 (Thanks to sonjli for its initial work)

  • Fix for issue444

  • Fix for issue408 a.k.a. docExpansion parameter for Swagger

    Check all the issues closed in this release.

What's New in 3.2.0-boron

  • New! Support for Delphi 10.4 Sydney!

  • New! Added Nullable support in MVCActiveRecord (nullables defined in MVCFramework.Nullables.pas)! Check activerecord_showcase sample.

  • New! Added non autogenerated primary keys in MVCActiveRecord! Check activerecord_showcase sample.

  • New! Complete support for nullable types in the default serializer (nullables defined in MVCFramework.Nullables.pas)

  • New! Added ncCamelCase and ncPascalCase to the available attribute formatters.

    MVCNameCase Property/Field Name Rendered Name
    ncUpperCase Cod_Article COD_ARTICLE
    ncLowerCase Cod_Article cod_article
    ncPascalCase Cod_Article CodArticle
    ncPascalCase CodArticle CodArticle
    ncPascalCase _WITH__UNDERSCORES_ WithUnderscores
    ncCamelCase Cod_Article codArticle
    ncCamelCase CodArticle codArticle
    ncCamelCase _WITH__UNDERSCORES_ WithUnderscores
  • New! Added Swagger support (thanks to Joรฃo Antรดnio Duarte and Geoffrey Smith)

  • New! Attribute MVCDoNotDeserialize. If marked with this RTTI attribute, a property or a field is not deserialized and its value remain the same as was before the object deserialization.

  • New! Added SQLGenerator and RQL compiler for PostgreSQL, SQLite and MSSQLServer (in addition to MySQL, MariaDB, Firebird and Interbase)

  • New! MVCNameAs attribute got the param Fixed (default: false). If Fixed is true, then the name is not processed by the MVCNameCase attribute assigned to the owner type.

  • New! Added support for interfaces serialization - now it is possible to serialize Spring4D collections (thanks to Joรฃo Antรดnio Duarte)

  • New! Added support for rendering Spring4D Nullable Types - (thanks to Joรฃo Antรดnio Duarte)

  • New! Added OnRouterLog event to log custom information for each request (thanks to Andrea Ciotti for the first implementation and its PR)

  • New! Optionally load system controllers (those who provide /describeserver.info, /describeplatform.info and /serverconfig.info system actions) setting Config[TMVCConfigKey.LoadSystemControllers] := 'false'; in the configuration block.

  • Improved! Now the router consider Accept:*/* compatible for every MVCProduces values.

  • Improved! Greatly improved support for HATEOAS in renders. Check TRenderSampleController.GetPeople_AsObjectList_HATEOS and all the others actions end with HATEOS in renders.dproj sample).

//Now is really easy to add "links" property automatically for each collection element while rendering
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');
    end);

		
//Datasets have a similar anon method to do the same thing
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')
	  .Add(HATEOAS._TYPE, 'application/json');
  end);

//Single object rendering allows HATEOAS too!
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')
	  .Add(HATEOAS._TYPE, TMVCMediaType.APPLICATION_JSON);
  end);
	
  • Better packages organization (check packages folder)
  • New! TMVCActiveRecord.Count method (e.g. TMVCActiveRecord.Count(TCustomer) returns the number of records for the entity mapped by the class TCustomer)
  • Change! TMVCACtiveRecord.GetByPK<T> raises an exception by default if the record is not found - optionally can returns nil using new parameter RaiseExceptionIfNotFound
  • New! contains clause has been added in the RQL compiler for Firebird and Interbase
  • New! Added support out operator in RQL parser. The RQL out operator is equivalent to the SQL NOT IN operator.
  • New! TMVCAnalyticsMiddleware to do automatic analytics on the API (generates a CSV file). Based on an idea by Nirav Kaku (https://www.facebook.com/nirav.kaku). Check the sample in \samples\middleware_analytics\
  • New! TMVCActiveRecord.DeleteAll deletes all the records from a table
  • New! TMVCActiveRecord.DeleteRQL deletes records using an RQL expression as where clause.
  • New! TMVCActiveRecord.Store which automatically executes Insert or Update considering primary key value.
  • New! TMVCActiveRecord allows to use table name and field name with spaces (currently supported only by the PostgreSQL compiler).
  • New! Microsoft SQLServer Support in MVCActiveRecord and RQL (thanks to one of the biggest Delphi based company in Italy which heavily uses DMVCFramework and DMSContainer).
  • New! SQLite support in MVCActiveRecord and RQL, so that MVCActiveRecord can be used also for Delphi mobile projects!
  • Default JSON Serializer can verbatim pass properties with type JsonDataObjects.TJSONObject without using string as carrier of JSON.
  • Improved! ActiveRecordShowCase sample is much better now.
  • Improved! All ActiveRecord methods which retrieve records can now specify the data type of each parameter (using Delphi's TFieldType enumeration).
  • Improved! In case of unhandled exception TMVCEngine is compliant with the default response content-type (usually it did would reply using text/plain).
  • Added! New overloads for all the Log* calls. Now it is possible to call LogD(lMyObject) to get logged lMyObject as JSON (custom type serializers not supported in log).
  • New! StrDict(array of string, array of string) function allows to render a dictionary of strings in a really simple way. See the following action sample.
procedure TMy.GetPeople(const Value: Integer);
begin
  if Value mod 2 <> 0 then
  begin
    raise EMVCException.Create(HTTP_STATUS.NotAcceptable, 'We don''t like odd numbers');
  end;
  Render(
    StrDict(
      ['id', 'message'],
      ['123', 'We like even numbers, thank you for your ' + Value.ToString]
    ));
end;
  • New! Custom Exception Handling (Based on work of David Moorhouse). Sample custom_exception_handling show how to use it.
  • Improved! Exceptions rendering while using MIME types different to application/json.
  • SSL Server support for TMVCListener (Thanks to Sven Harazim).
  • Improved! Datasets serialization speed improvement. In some case the performance improves of 2 order of magnitude. (Thanks to https://github.com/pedrooliveira01).
  • New! Added in operator in RQL parser (Thank you to Joรฃo Antรดnio Duarte for his initial work on this).
  • New! Added TMVCActiveRecord.Count<T>(RQL) to count record based on RQL criteria.
  • New! TMVCActiveRecord can handle non autogenerated primary key.
  • New! Added support for X-HTTP-Method-Override to work behind corporate firewalls.
  • New Sample! Server in DLL
  • Added new method in the dataset helper to load data into a dataset from a specific JSONArray property of a JSONObject procedure TDataSetHelper.LoadJSONArrayFromJSONObjectProperty(const AJSONObjectString: string; const aPropertyName: String);
  • Improved! New constants defined in HTTP_STATUS to better describe the http status response.
  • Improved! Now Firebird RQL' SQLGenerator can include primary key in CreateInsert if not autogenerated.
  • New! Added support for TArray<String>, TArray<Integer> and TArray<Double> in default JSON serializer (Thank you Pedro Oliveira)
  • Improved JWT Standard Compliance! Thanks to Vinicius Sanchez for his work on issue #241
  • Improved! DMVCFramework now has 180+ unit tests that checks its functionalities at each build!
  • Improved! Better exception handling in OnBeforeDispatch (Thanks to Spinettaro)
  • New! StrToJSONObject function to safely parse a string into a JSON object.
  • New! Serialization callback for custom TDataSet descendants serialization in TMVCJsonDataObjectsSerializer.
procedure TMainForm.btnDataSetToJSONArrayClick(Sender: TObject);
var
  lSer: TMVCJsonDataObjectsSerializer;
  lJArray: TJSONArray;
begin
  FDQuery1.Open();
  lSer := TMVCJsonDataObjectsSerializer.Create;
  try
    lJArray := TJSONArray.Create;
    try
      lSer.DataSetToJsonArray(FDQuery1, lJArray, TMVCNameCase.ncLowerCase, [],
        procedure(const aField: TField; const aJsonObject: TJSONObject; var Handled: Boolean)
        begin
          if SameText(aField.FieldName, 'created_at') then
          begin
            aJsonObject.S['year_and_month'] := FormatDateTime('yyyy-mm', TDateTimeField(aField).Value);
            Handled := True;
          end;
        end);
	  //The json objects will not contains "created_at" anymore, but only "year_and_month".
      Memo1.Lines.Text := lJArray.ToJSON(false);
    finally
      lJArray.Free;
    end;
  finally
    lSer.Free;
  end;
end;
  • New! Shortcut render' methods which simplify RESTful API development

    • procedure Render201Created(const Location: String = ''; const Reason: String = 'Created'); virtual;
    • procedure Render202Accepted(const HREF: String; const ID: String; const Reason: String = 'Accepted'); virtual;
    • procedure Render204NoContent(const Reason: String = 'No Content'); virtual;
  • Added de/serializing iterables (e.g. generic lists) support without MVCListOf attribute (Thank you to Joรฃo Antรดnio Duarte).

    It is now possible to deserialize a generic class like this:

      TGenericEntity<T: class> = class
      private
        FCode: Integer;
        FItems: TObjectList<T>;
        FDescription: string;
      public
        constructor Create;
        destructor Destroy; override;
        property Code: Integer read FCode write FCode;
        property Description: string read FDescription write FDescription;
        // MVCListOf(T) <- No need
        property Items: TObjectList<T> read FItems write FItems;
      end;

    Before it was not possible because you should add the MVCListOf attribute to the TObjectList type property.

  • New! Added serialization support for (thanks to dockerandy for his initial work)

    • TArray<String>
    • TArray<Integer>
    • TArray<Int64>
    • TArray<Double>
  • New! The MVCAREntitiesGenerator can optionally register all the generated entities also in the ActiveRecordMappingRegistry (Thanks to Fabrizio Bitti from bit Time Software)

  • New! Experimental (alpha stage) support for Android servers!

  • New! Children objects lifecycle management in TMVCActiveRecord (methods AddChildren and RemoveChildren). Really useful to manage child objects such relations or derived properties and are safe in case of multiple addition of the same object as children.

    //Having the following declaration
    
    type
      [MVCNameCase(ncCamelCase)]
      [MVCTable('authors')]
      TAuthor = class(TPersonEntityBase)
      private
        fBooks: TEnumerable<TBookRef>;
        [MVCTableField('full_name')]
        fFullName: string;
        function GetBooks: TEnumerable<TBookRef>;
      public
        [MVCNameAs('full_name')]
        property FullName: string read fFullName write fFullName;
        property Books: TEnumerable<TBookRef> read GetBooks;
      end;
    
    
    //method GetBooks can be implemented as follows:
    
    implementation
    
    function TAuthor.GetBooks: TEnumerable<TBookRef>;
    begin
      if fBooks = nil then
      begin
        fBooks := TMVCActiveRecord.Where<TBookRef>('author_id = ?', [ID]);
        AddChildren(fBooks); //fBooks will be freed when self will be freed
      end;
      Result := fBooks;
    end;
  • JSON-RPC Improvements

    • New! Added TMVCJSONRPCExecutor.ConfigHTTPClient to fully customize the inner THTTPClient (e.g. ConnectionTimeout, ResponseTimeout and so on)

    • Improved! JSONRPC Automatic Object Publishing can not invoke inherited methods if not explicitly defined with MVCInheritable attribute.

    • New! Calling <jsonrpcendpoint>/describe returns the methods list available for that endpoint.

    • New! Full support for named parameters in JSON-RPC call (server and client)

      • Positional parameters example

        procedure TMainForm.btnSubtractClick(Sender: TObject);
        var
          lReq: IJSONRPCRequest;
          lResp: IJSONRPCResponse;
        begin
          lReq := TJSONRPCRequest.Create;
          lReq.Method := 'subtract';
          lReq.RequestID := Random(1000);
          lReq.Params.Add(StrToInt(edtValue1.Text));
          lReq.Params.Add(StrToInt(edtValue2.Text));
          lResp := FExecutor.ExecuteRequest(lReq);
          edtResult.Text := lResp.Result.AsInteger.ToString;
        end;
      • Named parameters example

        procedure TMainForm.btnSubtractWithNamedParamsClick(Sender: TObject);
        var
          lReq: IJSONRPCRequest;
          lResp: IJSONRPCResponse;
        begin
          lReq := TJSONRPCRequest.Create;
          lReq.Method := 'subtract';
          lReq.RequestID := Random(1000);
          lReq.Params.AddByName('Value1', StrToInt(Edit1.Text));
          lReq.Params.AddByName('Value2', StrToInt(Edit2.Text));
          lResp := FExecutor.ExecuteRequest(lReq);
          Edit3.Text := lResp.Result.AsInteger.ToString;
        end;
      • Check official JSONRPC 2.0 documentation for more examples.

    • New! JSONRPC Hooks for published objects

      //Called before as soon as the HTTP arrives
      procedure TMyPublishedObject.OnBeforeRouting(const JSON: TJDOJsonObject);
      
      //Called before the invoked method
      procedure TMyPublishedObject.OnBeforeCall(const JSONRequest: TJDOJsonObject);
      
      //Called just before to send response to the client
      procedure TMyPublishedObject.OnBeforeSendResponse(const JSONResponse: TJDOJsonObject);
      
  • Deprecated! TDataSetHolder is deprecated! Use the shining new ObjectDict(boolean) instead.

  • New! ObjectDict function is the suggested way to render all the most common data types. It returns a IMVCObjectDictionary which is automatically rendered by the renders. Check the renders.dproj sample. Here's some example of the shining new ObjectDict().

    Example 1: Rendering a list of objects not freeing them after rendering

    Classic

    procedure TRenderSampleController.GetLotOfPeople;
    begin
      Render<TPerson>(GetPeopleList, False);
    end;

    New approach with ObjectDict

    procedure TRenderSampleController.GetLotOfPeople;
    begin
      Render(ObjectDict(False).Add('data', GetPeopleList));
    end;

    Example 2: Rendering a list of objects and automatically free them after rendering

    Classic

    procedure TRenderSampleController.GetLotOfPeople;
    begin
      Render<TPerson>(GetPeopleList);
    end;
    

    New approach with ObjectDict

    procedure TRenderSampleController.GetLotOfPeople;
    begin
      Render(ObjectDict().Add('data', GetPeopleList));
    end;
    

    Example 3: Rendering a list of objects adding links for HATEOAS support

    Classic

    procedure TRenderSampleController.GetPeople_AsObjectList_HATEOAS;
    var
      p: TPerson;
      People: TObjectList<TPerson>;
    begin
      People := TObjectList<TPerson>.Create(True);
    
    {$REGION 'Fake data'}
      p := TPerson.Create;
      p.FirstName := 'Daniele';
      p.LastName := 'Teti';
      p.DOB := EncodeDate(1979, 8, 4);
      p.Married := True;
      People.Add(p);
    
      p := TPerson.Create;
      p.FirstName := 'John';
      p.LastName := 'Doe';
      p.DOB := EncodeDate(1879, 10, 2);
      p.Married := False;
      People.Add(p);
    
      p := TPerson.Create;
      p.FirstName := 'Jane';
      p.LastName := 'Doe';
      p.DOB := EncodeDate(1883, 1, 5);
      p.Married := True;
      People.Add(p);
    {$ENDREGION}
    
      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');
        end);
    end;
    

    New approach with ObjectDict

    procedure TRenderSampleController.GetPeople_AsObjectList_HATEOAS;
    var
      p: TPerson;
      People: TObjectList<TPerson>;
    begin
      People := TObjectList<TPerson>.Create(True);
    
    {$REGION 'Fake data'}
      p := TPerson.Create;
      p.FirstName := 'Daniele';
      p.LastName := 'Teti';
      p.DOB := EncodeDate(1979, 8, 4);
      p.Married := True;
      People.Add(p);
    
      p := TPerson.Create;
      p.FirstName := 'John';
      p.LastName := 'Doe';
      p.DOB := EncodeDate(1879, 10, 2);
      p.Married := False;
      People.Add(p);
    
      p := TPerson.Create;
      p.FirstName := 'Jane';
      p.LastName := 'Doe';
      p.DOB := EncodeDate(1883, 1, 5);
      p.Married := True;
      People.Add(p);
    
    {$ENDREGION}
     
      Render(ObjectDict().Add('data', People,
        procedure(const APerson: TObject; const Links: IMVCLinks)
        begin
          Links
            .AddRefLink
            .Add(HATEOAS.HREF, '/people/' + TPerson(APerson).ID.ToString)
            .Add(HATEOAS.REL, 'self')
            .Add(HATEOAS._TYPE, 'application/json')
            .Add('title', 'Details for ' + TPerson(APerson).FullName);
          Links
            .AddRefLink
            .Add(HATEOAS.HREF, '/people')
            .Add(HATEOAS.REL, 'people')
            .Add(HATEOAS._TYPE, 'application/json');
        end));
    end;
    

    ObjectDict is able to render multiple data sources (datasets, objectlists, objects or StrDict) at the same time using different casing, HATEOAS callbacks and modes.

    procedure TTestServerController.TestObjectDict;
    var
      lDict: IMVCObjectDictionary;
    begin
      lDict := ObjectDict(false)
        .Add('ncUpperCase_List', GetDataSet, nil, dstAllRecords, ncUpperCase)
        .Add('ncLowerCase_List', GetDataSet, nil, dstAllRecords, ncLowerCase)
        .Add('ncCamelCase_List', GetDataSet, nil, dstAllRecords, ncCamelCase)
        .Add('ncPascalCase_List', GetDataSet, nil, dstAllRecords, ncPascalCase)
        .Add('ncUpperCase_Single', GetDataSet, nil, dstSingleRecord, ncUpperCase)
        .Add('ncLowerCase_Single', GetDataSet, nil, dstSingleRecord, ncLowerCase)
        .Add('ncCamelCase_Single', GetDataSet, nil, dstSingleRecord, ncCamelCase)
        .Add('ncPascalCase_Single', GetDataSet, nil, dstSingleRecord, ncPascalCase)
        .Add('meta', StrDict(['page'], ['1']));
      Render(lDict);
    end;
    

    ObjectDict is the suggested way to renders data. However, the other ones are still there and works as usual.

  • Added ability to serialize/deserialize types enumerated by an array of mapped values (Thanks to Joรฃo Antรดnio Duarte).

    type
      TMonthEnum = (meJanuary, meFebruary, meMarch, meApril);
    
      TEntityWithEnums = class
      private
        FMonthMappedNames: TMonthEnum;
        FMonthEnumName: TMonthEnum;    
        FMonthOrder: TMonthEnum;    
      public
        // List items separated by comma or semicolon
        [MVCEnumSerializationType(estEnumMappedValues,
        	'January,February,March,April')]
        property MonthMappedNames: TMonthEnum 
        	read FMonthMappedNames write FMonthMappedNames;
        [MVCEnumSerializationType(estEnumName)]
        property MonthEnumName: TMonthEnum 
        	read FMonthEnumName write FMonthEnumName;
        [MVCEnumSerializationType(estEnumOrd)]
        property MonthOrder: TMonthEnum read FMonthOrder write FMonthOrder;
      end;
    ...
  • New Installation procedure!

    • Open the project group (select the correct one from the following table)
    • Build all
    • Install the design-time package (dmvcframeworkDT)
    • Add the following paths in the Delphi Library Path (here, C:\DEV\dmvcframework is the dmvcframework main folder)
      • C:\DEV\dmvcframework\sources
      • C:\DEV\dmvcframework\lib\loggerpro
      • C:\DEV\dmvcframework\lib\swagdoc\Source
      • C:\DEV\dmvcframework\lib\dmustache
Delphi Version Project Group
Delphi 10.4 Sydney packages\d104\dmvcframework_group.groupproj
Delphi 10.3 Rio packages\d103\dmvcframework_group.groupproj
Delphi 10.2 Tokyo packages\d102\dmvcframework_group.groupproj
Delphi 10.1 Berlin packages\d101\dmvcframework_group.groupproj
Delphi 10.0 Seattle packages\d100\dmvcframework_group.groupproj

Breaking Changes in 3.2.0-boron

  • In MVCActiveRecord attribute MVCPrimaryKey has been removed and merged with MVCTableField, so now TMVCActiveRecordFieldOption is a set of foPrimaryKey, foAutoGenerated, foTransient (check activerecord_showcase.dproj sample).

  • Middleware OnAfterControllerAction are now invoked in the same order of OnBeforeControllerAction (previously were invoked in reversed order).

  • TMVCEngine is no more responsible for static file serving. If you need static files used the new TMVCStaticFilesMiddleware (check the sample). As consequence TMVCConfigKey.DocumentRoot, TMVCConfigKey.IndexDocument and TMVCConfigKey.FallbackResource are no more available.

  • TMVCEngine.Config property is now read-only. Can be changed only in the anonymous method injected in the constructor.

    // This is valid
    ////////////////////////////////////////
    FMVC := TMVCEngine.Create(Self,
      procedure(Config: TMVCConfig)
      begin
        // session timeout (0 means session cookie)
        Config[TMVCConfigKey.SessionTimeout] := '0';
        //Other Configurations
      end);
    FMVC.AddController(TMyController);
    
    
    // This is not valid (exception is raised)
    /////////////////////////////////////////
    
    FMVC := TMVCEngine.Create(Self);,
    FMVC.Config[TMVCConfigKey.SessionTimeout] := '0'; {run-time error here}
    FMVC.AddController(TMyController);
    

Bug Fixes in 3.2.0-boron

What's New in 3.1.0-lithium

  • TMVCActiveRecord framework
  • TMVCActiveRecordController with automatic RESTful interface generation and permissions handling
  • EntityProcessor for TMVCActiveRecordController to handle complex cases
  • JSON-RPC executor allows to configure HTTP headers for JSON-RPC requests and notifications.
  • TDataSetHolder
  • 404 and 500 status code returns always a text/plain content-type
  • Speed improvement!
  • MAX_REQUEST_SIZE can now limit the size of the incoming HTTP requests.
  • TMVCResponse can handle generic (non error) responses
  • gzip compression support in addition to deflate in TCompressionMiddleware
  • TCompressionMiddleware has been renamed in TMVCCompressionMiddleware
  • Support for Spring4d nullable types (check samples\renders_spring4d_nullables)
  • TMVCJSONRPCPublisher allows to easily expose plain Delphi objects (and even data modules) through a JSON-RPC 2.0 interface!
  • Breaking Change! The JSON RPC Client layer is now interface based.

What's New in 3.0.0-hydrogen

  • First release of the 3.0.0 version

What's New in 2.1.3-lithium

  • FIX #64
  • Added unit tests to avoid regressions

What's New in 2.1.2-helium

  • FIX for Delphi versions who don't have TJSONBool (Delphi XE8 or older)
  • Added new conditional define in dmvcframework.inc: JSONBOOL (defined for Delphi Seattle+)

What's New in 2.1.1-hydrogen

  • Updated the IDE Expert to show the current version of the framework
  • FIX to the mapper about the datasets null values (needs to be checked in old Delphi versions)
  • ADDED support for Boolean values in datasets serialization
  • ADDED unit tests about Mapper and dataset fields nullability
  • The current version is available in constant DMVCFRAMEWORK_VERSION defined in MVCFramework.Commons.pas

Roadmap

DelphiMVCFramework roadmap is always updated as-soon-as the features planned are implemented. Check the roadmap here.

Trainings, consultancy or custom development service

As you know, good support on open source software is a must for professional users. If you need trainings, consultancy or custom developments on DelphiMVCFramework, send an email to dmvcframework at bittime dot it. Alternatively you can send a request using the contacts forms on bit Time Professionals website. bit Time Professionals is the company behind DelphiMVCFramework, the lead developer works there.

Samples and documentation

DMVCFramework is provided with a lot of examples focused on specific functionality. All samples are in Samples folder.

Getting Started: 5 minutes guide

DMVCFramework allows to create powerful RESTful servers without effort. You can create a full-flagged RESTful server in a couple of clicks.

DelphiMVCFramework Installation

  • DMVCFramework must be installed using the Github release. Download the zip file

  • Unzip it the release zip in a folder named C:\dmvc (or where you prefer).

  • Launch RAD Studio and open C:\dmvc\packages\d104\dmvcframework_group.groupproj

    WARNING! In the last path shown "d104" is for Delphi 10.4 Sydney. Use the correct package for your Delphi version.

  • Install the package and close all

  • Now, DMVCFramework expert is installed and you are able to create DMVCFramework project. Go to go to File->New->Other select Delphi Project->DMVC->DelphiMVCFramework Project

  • From the resultant dialog, leave all the default settings and click OK

  • If you try to compile the project now, you will get compiler errors because we've to configure the library paths to let the compiler finds the needed source files

  • go to Tools->Options->Language->Delphi->Library and add in the Library Path the following paths:

    • C:\DMVC\sources
    • C:\DMVC\lib\dmustache
    • C:\DMVC\lib\loggerpro
    • C:\DMVC\lib\swagdoc\Source
  • Run the project (F9)

  • Now, a new console application is running serving you first DMVCFramework server.

  • Simple, isn't it?

  • The wizard generated controller shown some basic setup and some actions. You can start from here to create your application. Use the huge number of sample to understand how each DMVCFramwork feature work.

Sample Controller

Below a basic sample of a DMVCFramework controller with 2 action

unit UsersControllerU;
  
interface
  
uses 
  MVCFramework;
 
type 
   [MVCPath('/users')]
   TUsersController = class(TMVCController)
   public

    //The following action will be with a GET request like the following
    //http://myserver.com/users/3
    [MVCPath('/($id)')]
    [MVCProduces('application/json')]
    [MVCHTTPMethod([httpGET])]
    [MVCDoc('Returns a user as a JSON object')]
    procedure GetUser(id: Integer);

    
    //The following action will be with a GET request like the following
    //http://myserver.com/users
    [MVCPath('/')]
    [MVCProduces('application/json')]
    [MVCHTTPMethod([httpGET])]
    [MVCDoc('Returns the users list as a JSON Array of JSON Objects')]
    procedure GetUsers;

    //The following action will be with a PUT request like the following
    //http://myserver.com/users/3
    //and in the request body there should be a serialized TUser
    [MVCPath('/($id)')]
    [MVCProduce('application/json')]
    [MVCHTTPMethod([httpPUT])]
    [MVCDoc('Update a user')]    
    procedure UpdateUser(id: Integer);

    //The following action will respond to a POST request like the following
    //http://myserver.com/users
    //and in the request body there should be the new user to create as json
    [MVCPath]
    [MVCProduce('application/json')]
    [MVCHTTPMethod([httpPOST])]
    [MVCDoc('Create a new user, returns the id of the new user')]
    procedure CreateUser;

  end;
 
implementation

uses
  MyTransactionScript; //contains actual data access code
  
{ TUsersController }

procedure TUsersController.GetUsers;
var
  Users: TObjectList<TUser>;
begin
  Users := GetUsers;
  Render(Users);
end;
 
procedure TUsersController.GetUser(id: Integer);
var
  User: TUser;
begin
  User := GetUserById(id);
  Render(User);
end;

procedure TUsersController.UpdateUser(id: Integer);
var
  User: TUser;
begin
  User := Context.Request.BodyAs<TUser>;
  UpdateUser(id, User);
  Render(User);
end;	
  
procedure TUsersController.CreateUser;
var
  User: TUser;
begin
  User := Context.Request.BodyAs<TUser>;
  CreateUser(User);
  Render(User);
end;	
  
end.

Now you have a performant RESTful server wich respond to the following URLs:

  • GET /users/($id) (eg. /users/1, /users/45 etc)
  • PUT /users/($id) (eg. /users/1, /users/45 etc with the JSON data in the request body)
  • POST /users (the JSON data must be in the request body)

How to create a dmvcframework servers container

If you don't plan to deploy your DMVCFramework server behind a webserver (apache or IIS) you can also pack more than one listener application server into one single executable. In this case, the process is a bit different and involves the creation of a listener context. However, create a new server is a simple task:

uses
  MVCFramework.Server,
  MVCFramework.Server.Impl;

var
  LServerListener: IMVCListener;
begin
  LServerListener := TMVCListener.Create(TMVCListenerProperties.New
	 .SetName('Listener1')
	 .SetPort(5000)
	 .SetMaxConnections(1024)
	 .SetWebModuleClass(YourServerWebModuleClass)
   );  

  LServerListener.Start;
  LServerListener.Stop;
end;

If you want to add a layer of security (in its WebModule you should add the security middleware):

uses
  MVCFramework.Server,
  MVCFramework.Server.Impl,
  MVCFramework.Middleware.Authentication;

procedure TTestWebModule.WebModuleCreate(Sender: TObject);
begin
  FMVCEngine := TMVCEngine.Create(Self);
	
  // Add Yours Controllers
  FMVCEngine.AddController(TYourController);
	
  // Add Security Middleware
  FMVCEngine.AddMiddleware(TMVCBasicAuthenticationMiddleware.Create(
    TMVCDefaultAuthenticationHandler.New
    .SetOnAuthentication(
		procedure(const AUserName, APassword: string;
		  AUserRoles: TList<string>; var IsValid: Boolean; 
		  const ASessionData: TDictionary<String, String>)
		begin
		  IsValid := AUserName.Equals('dmvc') and APassword.Equals('123');
		end
		)
    ));
end;  

In stand alone mode you can work with a context that supports multiple listeners servers:

uses
  MVCFramework.Server,
  MVCFramework.Server.Impl;

var
  LServerListenerCtx: IMVCListenersContext;

begin
  LServerListenerCtx := TMVCListenersContext.Create;

  LServerListenerCtx.Add(TMVCListenerProperties.New
    .SetName('Listener1')
    .SetPort(6000)
    .SetMaxConnections(1024)
    .SetWebModuleClass(WebModuleClass1)
    );

  LServerListenerCtx.Add(TMVCListenerProperties.New
    .SetName('Listener2')
    .SetPort(7000)
    .SetMaxConnections(1024)
    .SetWebModuleClass(WebModuleClass2)
    );

  LServerListenerCtx.StartAll;
end;  

RQL Introduction

Resource Query Language (RQL) is a query language designed for use in URIs with object style data structures. DMVCFramework supports RQL natively and the included MVCActiveRecord micro-framework, implement a large subset of the RQL specs.

RQL can be thought as basically a set of nestable named operators which each have a set of arguments. RQL is designed to have an extremely simple, but extensible grammar that can be written in a URL friendly query string. A simple RQL query with a single operator that indicates a search for any resources with a property of "foo" that has value of 5 could be written:

eq(foo,5)

A more complex filter can include an arbitrary number of chained functions

or(and(eq(name,"daniele"),eq(surname,"teti")),and(eq(name,"peter"),eq(surname,"parker"));sort(+name)

Which is translated (details depends from the RDBMS) in the following SQL.

select 
	name, surname {other fields} 
from 
	people
where
  (name = "daniele" and surname = "teti") 
  	or 
  (name="peter" and surname = "parker")
order by
  name asc

RQL as Implemented by DMVCFramework

RQL is designed for modern application development. It is built for the web, ready for NoSQL, and highly extensible with simple syntax.

Here is a definition of the common operators as implemented in DMVCFramework' ActiveRecord:

eq(<property>,<value>) - Filters for objects where the specified property's value is equal to the provided value
lt(<property>,<value>) - Filters for objects where the specified property's value is less than the provided value
le(<property>,<value>) - Filters for objects where the specified property's value is less than or equal to the provided value
gt(<property>,<value>) - Filters for objects where the specified property's value is greater than the provided value
ge(<property>,<value>) - Filters for objects where the specified property's value is greater than or equal to the provided value
ne(<property>,<value>) - Filters for objects where the specified property's value is not equal to the provided value
and(<query>,<query>,...) - Applies all the given queries
or(<query>,<query>,...) - The union of the given queries
sort(<+|-><property) - Sorts by the given property in order specified by the prefix (+ for ascending, - for descending)
limit(count,start,maxCount) - Returns the given range of objects from the result set
contains(<property>,<value | expression>) - Filters for objects where the specified property's value is an array and the array contains any value that equals the provided value or satisfies the provided expression.
in(<property>,<array-of-values>) - Filters for objects where the specified property's value is in the provided array
out(<property>,<array-of-values>) - Filters for objects where the specified property's value is not in the provided array

Not Yet Availables

select(<property>,<property>,...) - Trims each object down to the set of properties defined in the arguments
values(<property>) - Returns an array of the given property value for each object
aggregate(<property|function>,...) - Aggregates the array, grouping by objects that are distinct for the provided properties, and then reduces the remaining other property values using the provided functions
distinct() - Returns a result set with duplicates removed
excludes(<property>,<value | expression>) - Filters for objects where the specified property's value is an array and the array does not contain any of value that equals the provided value or satisfies the provided expression.
rel(<relation name?>,<query>) - Applies the provided query against the linked data of the provided relation name.
sum(<property?>) - Finds the sum of every value in the array or if the property argument is provided, returns the sum of the value of property for every object in the array
mean(<property?>) - Finds the mean of every value in the array or if the property argument is provided, returns the mean of the value of property for every object in the array
max(<property?>) - Finds the maximum of every value in the array or if the property argument is provided, returns the maximum of the value of property for every object in the array
min(<property?>) - Finds the minimum of every value in the array or if the property argument is provided, returns the minimum of the value of property for every object in the array
recurse(<property?>) - Recursively searches, looking in children of the object as objects in arrays in the given property value
first() - Returns the first record of the query's result set
one() - Returns the first and only record of the query's result set, or produces an error if the query's result set has more or less than one record in it.
count() - Returns the count of the number of records in the query's result set

dotEnv syntax

Since 3.4.0-neon dmvcframework supports dotEnv configuration files.

TL:DR "Read key-value pairs from a .env file and set them as environment variables"

The format is not formally specified and still improves over time. That being said, .env files should mostly look like Bash files.

Keys can be unquoted or single-quoted. Values can be unquoted, single- or double-quoted. Spaces before and after keys, equal signs, and values are ignored. Values can be followed by a comment.

Variable expansion dmvcframework' dotEnv can interpolate variables using POSIX variable expansion.

This is a valid .env file:

############
# ENV FILE #
############

mode=dev

#DB Name
dbhostname=my_product_db_dev

#The DB username
dbuser=my_user

#The DB password (in this example is read from an EnvVariable)
dbpassword="XYZ${USERNAME}!$"

#DB Hostname
dbhostname="127.0.0.1"

#user preferences
user_preferences_path=${APPDATA}

email_template="This is a ${mode} email template
second template email line
third template email line"

Utilization

 var dotEnv := NewDotEnv
    .WithStrategy(TMVCDotEnvPriority.EnvThenFile)
    .UseProfile('prod')
    .Build();
  mmVars.Clear;
  mmVars.Lines.AddStrings(dotEnv.ToArray);

Links

Feel free to ask questions on the "Delphi MVC Framework" facebook group (https://www.facebook.com/groups/delphimvcframework).

delphimvcframework's People

Contributors

airtonjs avatar andreaciotti avatar angelosobreira avatar azapater avatar danieleteti avatar darnocian avatar dependabot[bot] avatar dsonda avatar ezequieljuliano avatar fastbike avatar geoffsmith82 avatar gmurt avatar joaoduarte19 avatar juliomar avatar landrix avatar leogregianin avatar marcelojaloto avatar marcelologica avatar microsys-sistemas avatar nickhodges avatar pedrooliveira01 avatar petdr avatar radexpol avatar regyssilveira avatar rjantz2 avatar sandrolborges avatar spinettaro avatar viniciussanchez avatar vitao-jose avatar zaniniflz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

delphimvcframework's Issues

Needed unit not found

There is in MVCFramework.pas used unit 'StompTypes'. Now it is gone. At least in my last update (I'm not sure how long I had it) there was a Folder 'delphistompclient'. Now this is no more there too, but MVCFramework.pas need it...

I just wonder how tests passt!? What must I make to compile MVCFramework?

Does not compile in Delphi Seattle

I've updated the framework to the last version and now it's not compiling any more.
It seems to be after commit 03d9041.
I'm using Delphi 10 Seattle.

Errors:
[dcc32 Error] MVCFramework.pas(1650): E2010 Incompatible types: 'Byte' and 'AnsiChar'
[dcc32 Error] MVCFramework.pas(1656): E2250 There is no overloaded version of 'GetString' that can be called with these arguments

At unit MVCFramework.pas:

function TMVCWebRequest.Body: string;
var
Encoding: TEncoding;
Buffer: TArray;
I: Integer;
begin
if (FBody = '') then
begin
if (FCharset = '') then
begin
SetLength(Buffer, 10);
for I := 0 to 9 do
Buffer[I] := FWebRequest.RawContent[I];
TEncoding.GetBufferEncoding(Buffer, Encoding, TEncoding.Default);
SetLength(Buffer, 0);
end
else
Encoding := TEncoding.GetEncoding(FCharset);
FBody := Encoding.GetString(FWebRequest.RawContent);
end;
Result := FBody;
end;

CustomLoggerSample - AnsiString

I can't compile the CustomLoggerSample demo

Error on lCookie.Name.ToLower. Here I'm getting that lCookie.Name is Ansistring.
I'm working with Seattle 10. Must I change settings?

To compile If changeed

lCookie.Name.ToLower  into LowerCase(lCookie.Name)

class procedure TMVCEngine.ClearSessionCookiesAlreadySet( aCookies: TCookieCollection); var I: Integer; lSessCookieName: string; lCookie: TCookie; begin lSessCookieName := TMVCConstants.SESSION_TOKEN_NAME.ToLower; I := 0; while true do begin if I = aCookies.Count then Break; lCookie := aCookies[I]; if lCookie.Name.ToLower = lSessCookieName then begin aCookies.Delete(I); end else Inc(I); end; end;

AV when json string is invalid

ObjectsMapper.pas

class procedure Mapper.LoadJSONObjectFieldsStringToObject(AJSONObjectString: string;
AObject: TObject);
var
lJSON: TJSONObject;
begin
lJSON := TJSONObject.ParseJSONValue(AJSONObjectString) as TJSONObject;
try
InternalJSONObjectFieldsToObject(ctx, lJSON, AObject);
finally
lJSON.Free;
end;
end;

change to:
class procedure Mapper.LoadJSONObjectFieldsStringToObject(AJSONObjectString: string;
AObject: TObject);
var
lJSON: TJSONObject;
begin
lJSON := TJSONObject.ParseJSONValue(AJSONObjectString) as TJSONObject;
if Assigned(IJSON) then
try
InternalJSONObjectFieldsToObject(ctx, lJSON, AObject);
finally
lJSON.Free;
end;
end;

Problem with TMVCWebRequest.BodyAsListOf <T>

I created a controller with a POST method that processes a list of Users.

procedure TAppController.PostUsers(ctx: TWebContext);
var
  vUsers: TObjectList<TUser>;
begin
  vUsers := ctx.Request.BodyAsListOf<TUser>();
  vUsers.OwnsObjects := True;

  if (vUsers.Count > 0) then
    Render('Sucess!')
  else
    Render('Error!');

  FreeAndNil(vUsers);
end;


In this condition the destructor method is called TMVCWebRequest.Destroy causes 
an Access Violation error in FreeAndNil(FBodyAsJSONValue).

Changing the TMVCWebRequest.BodyAsListOf <T> method could solve the problem:


function TMVCWebRequest.BodyAsListOf<T>(const RootProperty: string)
  : TObjectList<T>;
var
  S: string;
begin
  if ContentType.Equals(TMVCMimeType.APPLICATION_JSON) then
  begin
    if RootProperty = '' then
      Result := Mapper.JSONArrayToObjectList<T>((BodyAsJSONValue as TJSONArray), False, True) //Ezequiel J. Mรผller
    else
    begin
      S := Mapper.GetStringDef(BodyAsJSONObject, RootProperty, '');
      if not S.IsEmpty then
        Result := Mapper.JSONArrayToObjectList<T>((BodyAsJSONObject.Get(S).JsonValue as TJSONArray), False, True) //Ezequiel J. Mรผller
      else
        raise EMVCException.CreateFmt('Body property %s not valid',
          [RootProperty]);
    end;
  end
  else
    raise EMVCException.CreateFmt('Body ContentType %s not supported',
      [ContentType]);
end;

Original issue reported on code.google.com by [email protected] on 21 Oct 2014 at 11:39

got an error if I try to download the current version

git clone --recursive https://github.com/danieleteti/delphimvcframework.git
Cloning into 'delphimvcframework'...
remote: Counting objects: 5935, done.
remote: Total 5935 (delta 0), reused 0 (delta 0), pack-reused 5935
Receiving objects: 100% (5935/5935), 59.23 MiB | 2.75 MiB/s, done.
Resolving deltas: 100% (3608/3608), done.
Checking out files: 100% (1811/1811), done.
Submodule 'lib/delphistompclient' (https://github.com/danieleteti/delphistompclient.git) registered for path 'lib/delphistompclient'
Submodule 'lib/dmustache' (https://github.com/synopse/dmustache.git) registered for path 'lib/dmustache'
Submodule 'lib/loggerpro' (https://github.com/danieleteti/loggerpro.git) registered for path 'lib/loggerpro'
Cloning into 'E:/02_Entwicklung/DelphiXE5/lib/delphimvcframework/lib/delphistompclient'...
Cloning into 'E:/02_Entwicklung/DelphiXE5/lib/delphimvcframework/lib/dmustache'...
Cloning into 'E:/02_Entwicklung/DelphiXE5/lib/delphimvcframework/lib/loggerpro'...
error: no such remote ref 6724ff46bbfae41129e5c54bd4a7fc991de55129
Fetched in submodule path 'lib/delphistompclient', but it did not contain 6724ff46bbfae41129e5c54bd4a7fc991de55129. Direct fetching of that commit failed.

Client Wrappers for REST using Mustache templates ?

Would it be possible to add Client Wrappers for REST using Mustache templates to the roadmap ?

Below is a blog entry in which mORMot talks about using Mustache templates to generate client side
code for their server:

http://blog.synopse.info/post/2014/08/11/CrossPlatform-Clients/Generate-Code

They provide templates in the Croisplatformtemplates folder for:

CrossPlatform.pas.mustache Delphi / FPC SynCrossPlatform* units
Delphi.pas.mustache Delphi Win32/Win64 mORMot units
SmartMobileStudio.pas.mustache Smart Mobile Studio 2.1

Automated/Generated client side using a similar technique for Delphi MVC would be a nice feature.

Not render JSON empty string or null properties

Hi,

my table contests

| column1 | "this is string" |
| column2 | "" |
| column3 | NULL |

but when call Render(Table) for JSON

the responde only content properties with value

{
"column1": "this is a string"
}

I always need all the properties

{
"column1": "this is a string",
"column2": "",
"column3": null
}

exist any option for this? thanks

AJSONValue.ToJSON is Encoding use TEncoding.Default (Unicode)

With the TEncode.Default Korean is broken because Encode.

unit MVCFrameWork
InternalRender

{$IF CompilerVersion <= 27}
JString := AJSONValue.ToString; // requires the patch
{$ELSE}
JString := AJSONValue.ToJSON; // since XE7 it works using ToJSON
{$ENDIF}

ToString is Well

missed code

I didn't find dmvcframework.inc from MVCFramework.Commons . Where must it be?

Also it can not be compiled for now. There is also Error in

function B64Encode(const Value: String): String;
overload
// var
// lB64: TBase64Encoding;
begin
Result := TIdEncoderMIME.EncodeString(Value);

Suppose after overload must be ';'

Linux Support

Given the upcoming release of the Delphi compiler for Linux, do you think the framework will compile for deployment under Apache2 on Linux ?

[MVCProduce] or [MVCProduces]

Being new to DMVCFW I'm having a look at the samples.
(Downloaded via svn Aug 13, 2014.)

I'm using Delphi XE6 Pro

1) Started with BasicDemo 
-> all good

2) Moved on to routingsample
-> Request to / (root) works
-> Request to all others /search, /people, etc. did *not* work

I then noticed the code snippet on the project home page has [MVCProduce()] 
where as RoutingSampleControllerU.pas has [MVCProduces()].

After removing the 's' it worked fine.

Seems that other samples have [MVCProduces()] as well, including the unit 
tests, so perhaps that is the required name. What am I missing? A setting in 
Delphi XE6? (I'm not that familiar with attributes.)

I'm also trying to select each demo in order of relative difficulty. If you 
have any pointers in this regard that would be appreciated. Some samples have 
invalid library search paths, but will endeavour to work through that.

I can progress from here, but just wanted to let you know.


Framework looks promising for my needs, thank you.

-- 
Ian

Original issue reported on code.google.com by [email protected] on 14 Aug 2014 at 2:59

TWebSessionMemory

There is possible error in function TWebSessionMemory.ToString. Now it is so that only last from FData.Keys is returned as result. I suppose it must be so:

function TWebSessionMemory.ToString: string;
var
Key: string;
begin
Result := '';
for Key in FData.Keys do
begin
Result := Result + Key + '=' + QuotedStr(FData.Items[Key]) + sLineBreak;
end;
end;

Error in TMVCCustomAuthenticationMiddleware.SendResponse

In MVCFramework.Middleware.Authentication.pas at line 376 you are passing a parameter of type word to the format. The following line with error and with the solution.

Error: Context.Response.RawWebResponse.Content := Format(CONTENT_HTML_FORMAT, [HTTPStatus, Context.Config[TMVCConfigKey.ServerName]]);

Solution: Context.Response.RawWebResponse.Content := Format(CONTENT_HTML_FORMAT, [IntToStr(HTTPStatus), Context.Config[TMVCConfigKey.ServerName]]);

Request.Body encoding bug

example data, charset utf-8
[{"barcode":"8801062318490","company_code":"๋ฏผ","quantity":5,"date":"2016-03-23","kind":"1"}]

"๋ฏผ" is korean.

error message
[EEncodingError] No mapping for the Unicode character exists in the target multi-byte code page

> original code
function TMVCWebRequest.Body: string;
....
  try
    Result := InEnc.GetString(TEncoding.ANSI.GetBytes(FWebRequest.RawContent));
  finally
    InEnc.Free;
  end
....

> my code
function TMVCWebRequest.Body: string;
....
  try
    SetLength(Buffer, FWebRequest.ContentLength);
    FWebRequest.ReadClient(Buffer[0], FWebRequest.ContentLength);

    Result := InEnc.GetString(Buffer);
  finally
    InEnc.Free;
  end

timeout

i've set
RESTClient.ConnectionTimeout := 15000;
RESTClient.ReadTimeout := 15000;
but i still get the socket connection error after 2 seconds


Original issue reported on code.google.com by [email protected] on 28 Aug 2014 at 8:20

SSL and Compression

Hello Daniele 

I made โ€‹โ€‹some small changes to work with SSL and Compression in RESTClient. 

Added the .pas attached, analyze it and if possible add to the main sources.

Original issue reported on code.google.com by [email protected] on 21 Oct 2014 at 11:56

Attachments:

delphimvcframework without javascript?

Here is my question:
Can delphimvcframework be used, if the user has
deactivated javascript?
Or which parts could be used with deactivated
javascript?
Thanks for your answer,
Michael

Changes for XE3 to compile

Hi Daniele:

If you make the following change in the RTTIUtilsU.pas file it will compile for 
XE3 as well.

In this method:
class procedure TRTTIUtils.CopyObjectAS<T>(SourceObj, TargetObj: TObject);

Replace
_ARttiTypeTarget := ctx.GetType(T);
with
_ARttiTypeTarget := ctx.GetType(TClass(T));

Great framework by the way - thin and very easy to use. 

How about being able to use Camel Case (lower) for the JSON keys?
TJSONNameCase = (JSONNameUpperCase, JSONNameLowerCase, JSONNameLowerCamelCase);

Regards,
Gerhard

Original issue reported on code.google.com by [email protected] on 24 Feb 2014 at 4:36

Problem with InternalRender

In unit MVCFramework.pas exists the following method:

procedure InternalRender(aJSONValue: TJSONValue;
  ContentType, ContentEncoding: string; Context: TWebContext;
  aInstanceOwner: Boolean);
var
  OutEncoding: TEncoding;
  JString: string;
begin
{$IF CompilerVersion <= 27}
  JString := aJSONValue.ToString; // requires the patch
{$ELSE}
  JString := aJSONValue.ToJSON; // since XE7 it works using ToJSON
{$ENDIF}
  // first set the ContentType; because of this bug:
  // http://qc.embarcadero.com/wc/qcmain.aspx?d=67350
  Context.Response.RawWebResponse.ContentType := ContentType + '; charset=' +
    ContentEncoding;

  OutEncoding := TEncoding.GetEncoding(ContentEncoding);
  try
    Context.Response.RawWebResponse.Content :=
      OutEncoding.GetString(TEncoding.Convert(TEncoding.Default, OutEncoding,
      TEncoding.Default.GetBytes(JString)));
  finally
    OutEncoding.Free;
  end;

  if aInstanceOwner then
    FreeAndNil(aJSONValue)
end;

When an exception is raised on my server (the error message contains special characters) the line
JString := aJSONValue.ToJSON; (My case I'm with X7) It is not right encoding the message.
If I use JString := aJSONValue.ToString; The conversion is done correctly.

For example. The following error message is generated on the server:
'{"status":"error","classname":"EACBrNFeException","message":"Falha na validaรงรฃo dos dados da nota: 0'#$D#$A'TAG: ID:B04/natOp(Descriรงรฃo da Natureza da Operaรงรฃo) - Nenhum valor informado.'#$D#$A'TAG: ID:B12/cMunFG(Cรณdigo do Municรญpio FG) - Conteรบdo invรกlido.'#$D#$A'TAG: ID:B04/natOp(Descriรงรฃo da Natureza da Operaรงรฃo) - Nenhum valor informado.'#$D#$A'TAG: ID:B12/cMunFG(Cรณdigo do Municรญpio FG) - Conteรบdo invรกlido.'#$D#$A#$D#$A''''' violates pattern constraint of ''[!-รฟ]{1}[ -รฟ]{0,}[!-รฟ]{1}|[!-รฟ]{1}''.'#$D#$A'The element ''{http://www.portalfiscal.inf.br/nfe}natOp'' with value '''' failed to parse.'#$D#$A'","http_error":417}'

When the system crashes in the JString := aJSONValue.ToJSON; message is like:
'{"status":"error","classname":"EACBrNFeException","message":"Falha na valida\u00E7\u00E3o dos dados da nota: 0\r\nTAG: ID:B04/natOp(Descri\u00E7\u00E3o da Natureza da Opera\u00E7\u00E3o) - Nenhum valor informado.\r\nTAG: ID:B12/cMunFG(C\u00F3digo do Munic\u00EDpio FG) - Conte\u00FAdo inv\u00E1lido.\r\nTAG: ID:B04/natOp(Descri\u00E7\u00E3o da Natureza da Opera\u00E7\u00E3o) - Nenhum valor informado.\r\nTAG: ID:B12/cMunFG(C\u00F3digo do Munic\u00EDpio FG) - Conte\u00FAdo inv\u00E1lido.\r\n\r\n'''' violates pattern constraint of ''[!-\u00FF]{1}[ -\u00FF]{0,}[!-\u00FF]{1}|[!-\u00FF]{1}''.\r\nThe element ''{http://www.portalfiscal.inf.br/nfe}natOp'' with value '''' failed to parse.\r\n","http_error":417}'

If I leave the only JString := aJSONValue.ToString; the client receives the message correctly.

My question is whether this compilation directive is really necessary. I would not to leave only JString := aJSONValue.ToString;

StompTypes.dcu not found

image

The subfolder delphistompclient is empty.

I tried both the github zip file and also doing a clone of the github repository.

I see a closed issue with the same error message. I don't understand the response to the issue.

TRESTClient : EConvertError with message ''$s/'

If I use the TRESTClient and send to the server

lResp := lClt.doGET('/users/search/username/%s', [self.edtUserName.Text]);

I get an error like:
raised exception class EConvertError with message ''$s/' is not a valid integer value'.

stack

But this work:

lResp := lClt.doGET(Format('/users/search/username/%s', [self.edtUserName.Text]), []);

Any Idea what's the problem?

now WebRequestPathInfo is One More Decoded

When You Call procedure "/customers/($id)" In the Render Sample
example) localhost:8080/customers/($id) === localhost:8080/customers/๊ถŒ (๊ถŒ is korean word)

== i solved (i don't know this Code ใ… ใ… )
MVCFramework.Router Unit 97 Line

this is
// daniele
LWebRequestPathInfo := TIdURI.URLDecode(LWebRequestPathInfo);

// Change
LWebRequestPathInfo := TIdURI.PathEncode(LWebRequestPathInfo);

Customizable/pluggable mapper

Update Mapper framework to make it extensible and configurable

  • The default mapper interface will be the same as the current version so that no breaking changes happend
  • Will be possible to register a specific serializer/deserializer engine for each type or property name
  • There will be a mappers registry and at each "Render" call is created (or recicled) the correct mapper based on current controller content-type.
  • NTH: Put the created serializer instances in an objects pool

This is an item of the roadmap.

Development branch: pluggable_mapper

TMVCConstants not found

in unit MVCFramework.RESTClient the TMVCConstants is not recognised.

I've change {$IF CompilerVersion > 30} into {$IF CompilerVersion >= 30}

Redirect to another controller

Hi, Is the following possible

2 controllers
/customers
/orders

Could the customer controller be redirected to order controller
eg
/customer/3/orders

Tristan

Standardization with a coding style guide

Hello Daniele.

I believe it would be good we ride a programming style guide, defining variable names, parameters, methods, classes, namespaces units etc. ..

So all who contribute will be following the same form of programming, leaving more organized the project.

Do not need much documentation, the basics is necessary.

I can help in the assembly and refactoring the code later.

Authentification

Using basic authentification middleware is buggy
On debug mode it works like 95% of the time, on release never
I narrowed it down to this, Code starting at line 197 of MVCFramework.Middleware.Authentification
` finally
LRoles.Free;
end;
end;

// authorization
LIsAuthorized := False;
if LIsValid then
begin
FMVCAuthenticationHandler.OnAuthorization(Context.LoggedUser.Roles,
AControllerQualifiedClassName, AActionName, LIsAuthorized);
end;`

The problem is LIsValid is never set if the Context.LoggedUser.IsValid is set

this code fixes this issue

` finally
LRoles.Free;
end;
end;

if Context.LoggedUser.IsValid then
LIsValid:= True
else
LIsValid:= False;

// authorization
LIsAuthorized := False;
if LIsValid then
begin
FMVCAuthenticationHandler.OnAuthorization(Context.LoggedUser.Roles,
AControllerQualifiedClassName, AActionName, LIsAuthorized);
end;`

It is my first time posting something on guthub, any suggestions are welcome.

Problem with update/insert with Json = null to foreign

I tried to pass a json with some columns that are foreign to the value NULL, but even though I omit even the column, the component is putting value to it and is resulting in foreign error. Where should I deal with this in Model?

TPath.GetPublicPath does not exist in Delphi XE3

What steps will reproduce the problem?
Cant compile with XE3.

What is the expected output? What do you see instead?
It should compile.

What version of the product are you using? On what operating system?
XE3, Windows 7, 64bit.

Please provide any additional information below.

Message:
uGlobalVars.pas(21): E2003 Undeclared identifier: 'GetPublicPath'

Line:
gAppPath := IncludeTrailingPathDelimiter(TPath.GetPublicPath)



Original issue reported on code.google.com by [email protected] on 14 May 2014 at 1:25

Install of DMVC fails -

I follow the easy install 5 minutes guide.

When I press install I get error message "required package expertscreators not found".

Why don't people test things these days ???

image

Version R57 does not compile

Unable to compile a sample project after checking out revision 57.

In the ObjectsMappers.pas file the DuctListU appears inside of the defined 
block. I assume you meant only to have the FireDAC units in the block? 
When I remove it and place it before the defined block it compiles without any 
issues.

{$IF Defined(VER260)}
    , DuckListU
    , FireDAC.Comp.Client
    , FireDAC.Stan.Param
{$IFEND};

Original issue reported on code.google.com by [email protected] on 25 Feb 2014 at 3:45

User authentication and encryption

I started doing some testing with DMVCFramework and found it very good. Easy to 
work with and a very acceptable performance.

I only have a few questions:

1 - What is the best way to work with user authentication?
2 - Are there mechanisms and SSL encryption?


Original issue reported on code.google.com by [email protected] on 22 Nov 2013 at 11:29

Make all JWT custom claims data available in the context

Make all JWT custom claims data available in the context

Like:

Context.LoggedUser.UserName := lJWT.CustomClaims['username'];
Context.LoggedUser.Roles.AddRange(lJWT.CustomClaims['roles'].Split([',']));
Context.LoggedUser.LoggedSince := lJWT.Claims.IssuedAt;

So I do not need to unpack the token a second time in the controller procedure.

IsValidToken doesn't work with TJWTCheckableClaim.IssuedAt

Add code to

procedure TMVCJwtAuthenticationMiddleware.OnBeforeRouting
...
lJWT.Claims.Issuer := 'Delphi MVC Framework';
lJWT.Claims.ExpirationTime := Now + OneHour; // todo: customize
lJWT.Claims.NotBefore := Now - OneMinute * 5; // todo: customize
lJWT.Claims.IssuedAt := Now; // Add this line todo: customize
...

Problem with ObjectsMappers - Duplicates not allowed

When I try map the json below with model, I have a error = duplicates not allowed:

{
"id": 11049,
"genero": "M",
"regime": "0",
"nome": " FULANO DE TAL",
"nome_fantasia": null,
"cnpj": "111111111",
"ie": null,
"cep": "37550000",
"endereco": "XXXXXX",
"numero": null,
"complemento": null,
"bairro": "CHAVES",
"telefone": "11111111111",
"fax": null,
"celular": "35 ",
"motivo_status": null,
"status": "A",
"grupo_pessoa_id": null,
"uf": "MG",
"cidade_id": 3152501,
"login": null,
"senha": null,
"dt_cadastro": "2015-09-29",
"dt_nascimento": null,
"contato": null,
"ref_01": null,
"ref_02": null,
"ref_03": null,
"ref_04": null,
"ref_entrega": "XXXXXXX",
"email_principal": null,
"limite_credito": 50000,
"spc": null,
"dt_consultaspc": null,
"vendedorpadrao_id": null,
"observacoes": null,
"codigo_interno": null,
"tipo_cliente": "S",
"tipo_fornecedor": "N",
"tipo_transportadora": "N",
"tipo_funcionario": "N",
"tipo_vendedor": "N",
"tipo_usuario": "N",
"tipo_outros": "N",
"tipo_outros_descricao": null,
"grupousuario_id": null,
"salario": null,
"dt_registro": null,
"cargo": null,
"refcontato": null,
"tipo_tecnico": "N",
"tipo_locador": "N",
"tipo_locatario": "N",
"regimetributario_descricao": "PESSOA FรSICA",
"cnae": null,
"codigo_externo": null,
"ativar_agenda": null,
"codigo_vendedor": null,
"transportadora_uf_placa": null,
"transportadora_placa": null,
"tipo_revenda": "N",
"transportadora_padrao_id": null,
"segmento_id": null,
"media_volume": null,
"media_valor": null,
"media_afericao": null,
"media_periodo_inicial": null,
"media_periodo_final": null,
"media_qtde_movimentacoes": null,
"sincronizado": "N",
"administradora_cartao": "N",
"pai": null,
"mae": null,
"conjuge": null,
"conjuge_cpf": null,
"conjuge_cel": null,
"conjuge_empresa": null,
"local_trabalho": null,
"dt_ultimamov": null,
"vendedor_comissao": null,
"ext_codigo_cliente": null,
"ext_codigo_fornecedor": null,
"ext_codigo_vendedor": null,
"liberar_venda_prazo": null,
"acesso_grupo_id": null,
"administrador": null,
"pessoa_avatar": null,
"acesso_datahora": null,
"acesso_ip": null,
"cobranca_endereco": null,
"cobranca_numero": null,
"cobranca_complemento": null,
"cobranca_bairro": null,
"cobranca_telefone1": null,
"cobranca_telefone2": null,
"cobranca_telefone3": null,
"cobranca_contato": null,
"cobranca_email": null,
"cobranca_cep": null,
"cobranca_uf": null,
"cobranca_cidade_id": null,
"cod_cnae_principal": null,
"sf_capitalsocial": null,
"sf_capitalintegralizado": null,
"sf_capitalgiro": null,
"sf_imobilizado": null,
"cobranca_ref_entrega": null,
"url": null,
"config_email_smtp": null,
"config_email_smtp_porta": null,
"config_email_usuario": null,
"config_email_senha": null,
"config_email_pop": null,
"config_email_pop_porta": null,
"config_email_smtp_ssl": null,
"config_email_pop_ssl": null,
"config_email_pop_usuario": null,
"config_email_pop_senha": null,
"incentivador_cultural": null,
"inscricao_municipal": null,
"optante_simplesnacional": null,
"reter_iss": null,
"regiao_id": null,
"pessoa_classificacao_id": null,
"qualificacao_financeira": null,
"latitude": null,
"longitude": null,
"latitude_cobranca": null,
"longitude_cobranca": null,
"ck_geo_principal_ok": null,
"ck_geo_cobranca_ok": null,
"dt_status": null,
"dt_revisao_cadastro": null,
"cnae_descricao": null,
"situacao_receita": null,
"natureza_juridica": null,
"tipo": null,
"cnae_fiscal": null,
"roadmap_mostrado": null,
"liberar_bi": null,
"bloquear_automatico": "S",
"bloqueado_automatico": "N",
"agenda_workstart": null,
"agenda_workfinish": null,
"agenda_workdays_dsunday": "N",
"agenda_workdays_dmonday": "S",
"agenda_workdays_dtuesday": "S",
"agenda_workdays_dtwednesday": "S",
"agenda_workdays_dthursday": "S",
"agenda_workdays_dfriday": "S",
"agenda_workdays_dsaturday": "N",
"codigo_importacao": null,
"codigo_restaurante": null,
"restaurante_nivel_acesso": "1",
"ultima_notificacao_email": null,
"empresa_padrao_id": null,
"dia_vencimento_carteira": null,
"ws_map_id": null,
"contrato_nivel_acesso": null,
"boleto_protestar": "N",
"pessoa_tabela_desconto_id": 1
}

The model is below:

unit uPessoaModel;

interface

uses
ObjectsMappers, System.SysUtils;

type
TBaseBO = class
private
FID: Integer;
procedure SetID(const Value: Integer);
public
procedure CheckInsert; virtual;
procedure CheckUpdate; virtual;
procedure CheckDelete; virtual;
property ID: Integer read FID write SetID;
end;

[MapperJSONNaming(JSONNameLowerCase)]
TPessoaModel = class(TBaseBO)

private

FId  : Integer;
FGenero  : Integer;
FRegime  : String;
FNome  : String;
FNome_fantasia  : String;
FCnpj  : String;
FIe  : String;
FCep  : String;
FEndereco  : String;
FNumero  : String;
FComplemento  : String;
FBairro  : String;
FTelefone  : String;
FFax  : String;
FCelular  : String;
FMotivo_status  : String;
FStatus  : String;
FGrupo_pessoa_id  : Integer;
FUf  : String;
FCidade_id  : Integer;
FLogin  : String;
FSenha  : String;
FDt_cadastro  : TDate;
FDt_nascimento  : TDate;
FContato  : String;
FRef_01  : String;
FRef_02  : String;
FRef_03  : String;
FRef_04  : String;
FRef_entrega  : String;
FEmail_principal  : String;
FLimite_credito  : Integer;
FSpc  : String;
FDt_consultaspc  : TDate;
FVendedorpadrao_id  : Integer;
FObservacoes  : String;
FCodigo_interno  : String;
FTipo_cliente  : String;
FTipo_fornecedor  : String;
FTipo_transportadora  : String;
FTipo_funcionario  : String;
FTipo_vendedor  : String;
FTipo_usuario  : String;
FTipo_outros  : String;
FTipo_outros_descricao  : String;
FGrupousuario_id  : Integer;
FSalario  : Integer;
FDt_registro  : TDate;
FCargo  : String;
FRefcontato  : String;
FTipo_tecnico  : String;
FTipo_locador  : String;
FTipo_locatario  : String;
FRegimetributario_descricao  : String;
FCnae  : Integer;
FCodigo_externo  : Integer;
FAtivar_agenda  : String;
FCodigo_vendedor  : Integer;
FTransportadora_uf_placa  : String;
FTransportadora_placa  : String;
FTipo_revenda  : String;
FTransportadora_padrao_id  : Integer;
FSegmento_id  : Integer;
FMedia_volume  : Integer;
FMedia_valor  : Integer;
FMedia_afericao  : TDate;
FMedia_periodo_inicial  : TDate;
FMedia_periodo_final  : TDate;
FMedia_qtde_movimentacoes  : Integer;
FSincronizado  : String;
FAdministradora_cartao  : String;
FPai  : String;
FMae  : String;
FConjuge  : String;
FConjuge_cpf  : String;
FConjuge_cel  : String;
FConjuge_empresa  : String;
FLocal_trabalho  : String;
FDt_ultimamov  : TDate;
FVendedor_comissao  : Double;
FExt_codigo_cliente  : Integer;
FExt_codigo_fornecedor  : Integer;
FExt_codigo_vendedor  : Integer;
FLiberar_venda_prazo  : String;
FAcesso_grupo_id  : Integer;
FAdministrador  : String;
FPessoa_avatar  : String;
FAcesso_datahora  : TDateTime;
FAcesso_ip  : String;
FCobranca_endereco  : String;
FCobranca_numero  : String;
FCobranca_complemento  : String;
FCobranca_bairro  : String;
FCobranca_telefone1  : String;
FCobranca_telefone2  : String;
FCobranca_telefone3  : String;
FCobranca_contato  : String;
FCobranca_email  : String;
FCobranca_cep  : String;
FCobranca_uf  : String;
FCobranca_cidade_id  : Integer;
FCod_cnae_principal  : String;
FSf_capitalsocial  : Integer;
FSf_capitalintegralizado  : Integer;
FSf_capitalgiro  : Integer;
FSf_imobilizado  : Integer;
FCobranca_ref_entrega  : String;
FUrl  : String;
FConfig_email_smtp  : String;
FConfig_email_smtp_porta  : Integer;
FConfig_email_usuario  : String;
FConfig_email_senha  : String;
FConfig_email_pop  : String;
FConfig_email_pop_porta  : Smallint;
FConfig_email_smtp_ssl  : String;
FConfig_email_pop_ssl  : String;
FConfig_email_pop_usuario  : String;
FConfig_email_pop_senha  : String;
FIncentivador_cultural  : String;
FInscricao_municipal  : String;
FOptante_simplesnacional  : String;
FReter_iss  : String;
FRegiao_id  : Integer;
FPessoa_classificacao_id  : Integer;
FQualificacao_financeira  : String;
FLatitude  : Double;
FLongitude  : Double;
FLatitude_cobranca  : Double;
FLongitude_cobranca  : Double;
FCk_geo_principal_ok  : String;
FCk_geo_cobranca_ok  : String;
FDt_status  : TDate;
FDt_revisao_cadastro  : TDate;
FCnae_descricao  : String;
FSituacao_receita  : String;
FNatureza_juridica  : String;
FTipo  : String;
FCnae_fiscal  : String;
FRoadmap_mostrado  : String;
FLiberar_bi  : String;
FBloquear_automatico  : String;
FBloqueado_automatico  : String;
FAgenda_workstart  : TTime;
FAgenda_workfinish  : TTime;
FAgenda_workdays_dsunday  : String;
FAgenda_workdays_dmonday  : String;
FAgenda_workdays_dtuesday  : String;
FAgenda_workdays_dtwednesday  : String;
FAgenda_workdays_dthursday  : String;
FAgenda_workdays_dfriday  : String;
FAgenda_workdays_dsaturday  : String;
FCodigo_importacao  : Integer;
FCodigo_restaurante  : Integer;
FRestaurante_nivel_acesso  : String;
FUltima_notificacao_email  : TDate;
FEmpresa_padrao_id  : Integer;
FDia_vencimento_carteira  : Smallint;
FWs_map_id  : Integer;
FContrato_nivel_acesso  : Integer;
FBoleto_protestar  : String;
FPessoa_tabela_desconto_id  : Integer;

public
procedure CheckInsert; override;
procedure CheckUpdate; override;
procedure CheckDelete; override;

procedure SetId(const Value: Integer);

procedure SetGenero(const Value: Integer);

procedure SetRegime(const Value: String);

procedure SetNome(const Value: String);

procedure SetNome_fantasia(const Value: String);

procedure SetCnpj(const Value: String);

procedure SetIe(const Value: String);

procedure SetCep(const Value: String);

procedure SetEndereco(const Value: String);

procedure SetNumero(const Value: String);

procedure SetComplemento(const Value: String);

procedure SetBairro(const Value: String);

procedure SetTelefone(const Value: String);

procedure SetFax(const Value: String);

procedure SetCelular(const Value: String);

procedure SetMotivo_status(const Value: String);

procedure SetStatus(const Value: String);

procedure SetGrupo_pessoa_id(const Value: Integer);

procedure SetUf(const Value: String);

procedure SetCidade_id(const Value: Integer);

procedure SetLogin(const Value: String);

procedure SetSenha(const Value: String);

procedure SetDt_cadastro(const Value: TDate);

procedure SetDt_nascimento(const Value: TDate);

procedure SetContato(const Value: String);

procedure SetRef_01(const Value: String);

procedure SetRef_02(const Value: String);

procedure SetRef_03(const Value: String);

procedure SetRef_04(const Value: String);

procedure SetRef_entrega(const Value: String);

procedure SetEmail_principal(const Value: String);

procedure SetLimite_credito(const Value: Integer);

procedure SetSpc(const Value: String);

procedure SetDt_consultaspc(const Value: TDate);

procedure SetVendedorpadrao_id(const Value: Integer);

procedure SetObservacoes(const Value: String);

procedure SetCodigo_interno(const Value: String);

procedure SetTipo_cliente(const Value: String);

procedure SetTipo_fornecedor(const Value: String);

procedure SetTipo_transportadora(const Value: String);

procedure SetTipo_funcionario(const Value: String);

procedure SetTipo_vendedor(const Value: String);

procedure SetTipo_usuario(const Value: String);

procedure SetTipo_outros(const Value: String);

procedure SetTipo_outros_descricao(const Value: String);

procedure SetGrupousuario_id(const Value: Integer);

procedure SetSalario(const Value: Integer);

procedure SetDt_registro(const Value: TDate);

procedure SetCargo(const Value: String);

procedure SetRefcontato(const Value: String);

procedure SetTipo_tecnico(const Value: String);

procedure SetTipo_locador(const Value: String);

procedure SetTipo_locatario(const Value: String);

procedure SetRegimetributario_descricao(const Value: String);

procedure SetCnae(const Value: Integer);

procedure SetCodigo_externo(const Value: Integer);

procedure SetAtivar_agenda(const Value: String);

procedure SetCodigo_vendedor(const Value: Integer);

procedure SetTransportadora_uf_placa(const Value: String);

procedure SetTransportadora_placa(const Value: String);

procedure SetTipo_revenda(const Value: String);

procedure SetTransportadora_padrao_id(const Value: Integer);

procedure SetSegmento_id(const Value: Integer);

procedure SetMedia_volume(const Value: Integer);

procedure SetMedia_valor(const Value: Integer);

procedure SetMedia_afericao(const Value: TDate);

procedure SetMedia_periodo_inicial(const Value: TDate);

procedure SetMedia_periodo_final(const Value: TDate);

procedure SetMedia_qtde_movimentacoes(const Value: Integer);

procedure SetSincronizado(const Value: String);

procedure SetAdministradora_cartao(const Value: String);

procedure SetPai(const Value: String);

procedure SetMae(const Value: String);

procedure SetConjuge(const Value: String);

procedure SetConjuge_cpf(const Value: String);

procedure SetConjuge_cel(const Value: String);

procedure SetConjuge_empresa(const Value: String);

procedure SetLocal_trabalho(const Value: String);

procedure SetDt_ultimamov(const Value: TDate);

procedure SetVendedor_comissao(const Value: Double);

procedure SetExt_codigo_cliente(const Value: Integer);

procedure SetExt_codigo_fornecedor(const Value: Integer);

procedure SetExt_codigo_vendedor(const Value: Integer);

procedure SetLiberar_venda_prazo(const Value: String);

procedure SetAcesso_grupo_id(const Value: Integer);

procedure SetAdministrador(const Value: String);

procedure SetPessoa_avatar(const Value: String);

procedure SetAcesso_datahora(const Value: TDateTime);

procedure SetAcesso_ip(const Value: String);

procedure SetCobranca_endereco(const Value: String);

procedure SetCobranca_numero(const Value: String);

procedure SetCobranca_complemento(const Value: String);

procedure SetCobranca_bairro(const Value: String);

procedure SetCobranca_telefone1(const Value: String);

procedure SetCobranca_telefone2(const Value: String);

procedure SetCobranca_telefone3(const Value: String);

procedure SetCobranca_contato(const Value: String);

procedure SetCobranca_email(const Value: String);

procedure SetCobranca_cep(const Value: String);

procedure SetCobranca_uf(const Value: String);

procedure SetCobranca_cidade_id(const Value: Integer);

procedure SetCod_cnae_principal(const Value: String);

procedure SetSf_capitalsocial(const Value: Integer);

procedure SetSf_capitalintegralizado(const Value: Integer);

procedure SetSf_capitalgiro(const Value: Integer);

procedure SetSf_imobilizado(const Value: Integer);

procedure SetCobranca_ref_entrega(const Value: String);

procedure SetUrl(const Value: String);

procedure SetConfig_email_smtp(const Value: String);

procedure SetConfig_email_smtp_porta(const Value: Integer);

procedure SetConfig_email_usuario(const Value: String);

procedure SetConfig_email_senha(const Value: String);

procedure SetConfig_email_pop(const Value: String);

procedure SetConfig_email_pop_porta(const Value: Smallint);

procedure SetConfig_email_smtp_ssl(const Value: String);

procedure SetConfig_email_pop_ssl(const Value: String);

procedure SetConfig_email_pop_usuario(const Value: String);

procedure SetConfig_email_pop_senha(const Value: String);

procedure SetIncentivador_cultural(const Value: String);

procedure SetInscricao_municipal(const Value: String);

procedure SetOptante_simplesnacional(const Value: String);

procedure SetReter_iss(const Value: String);

procedure SetRegiao_id(const Value: Integer);

procedure SetPessoa_classificacao_id(const Value: Integer);

procedure SetQualificacao_financeira(const Value: String);

procedure SetLatitude(const Value: Double);

procedure SetLongitude(const Value: Double);

procedure SetLatitude_cobranca(const Value: Double);

procedure SetLongitude_cobranca(const Value: Double);

procedure SetCk_geo_principal_ok(const Value: String);

procedure SetCk_geo_cobranca_ok(const Value: String);

procedure SetDt_status(const Value: TDate);

procedure SetDt_revisao_cadastro(const Value: TDate);

procedure SetCnae_descricao(const Value: String);

procedure SetSituacao_receita(const Value: String);

procedure SetNatureza_juridica(const Value: String);

procedure SetTipo(const Value: String);

procedure SetCnae_fiscal(const Value: String);

procedure SetRoadmap_mostrado(const Value: String);

procedure SetLiberar_bi(const Value: String);

procedure SetBloquear_automatico(const Value: String);

procedure SetBloqueado_automatico(const Value: String);

procedure SetAgenda_workstart(const Value: TTime);

procedure SetAgenda_workfinish(const Value: TTime);

procedure SetAgenda_workdays_dsunday(const Value: String);

procedure SetAgenda_workdays_dmonday(const Value: String);

procedure SetAgenda_workdays_dtuesday(const Value: String);

procedure SetAgenda_workdays_dtwednesday(const Value: String);

procedure SetAgenda_workdays_dthursday(const Value: String);

procedure SetAgenda_workdays_dfriday(const Value: String);

procedure SetAgenda_workdays_dsaturday(const Value: String);

procedure SetCodigo_importacao(const Value: Integer);

procedure SetCodigo_restaurante(const Value: Integer);

procedure SetRestaurante_nivel_acesso(const Value: String);

procedure SetUltima_notificacao_email(const Value: TDate);

procedure SetEmpresa_padrao_id(const Value: Integer);

procedure SetDia_vencimento_carteira(const Value: Smallint);

procedure SetWs_map_id(const Value: Integer);

procedure SetContrato_nivel_acesso(const Value: Integer);

procedure SetBoleto_protestar(const Value: String);

procedure SetPessoa_tabela_desconto_id(const Value: Integer);

[MapperColumn('ID')]
property Id : Integer read FId  write SetId;

[MapperColumn('GENERO')]
property Genero : Integer read FGenero  write SetGenero;

[MapperColumn('REGIME')]
property Regime : String read FRegime  write SetRegime;

[MapperColumn('NOME')]
property Nome : String read FNome  write SetNome;

[MapperColumn('NOME_FANTASIA')]
property Nome_fantasia : String read FNome_fantasia  write SetNome_fantasia;

[MapperColumn('CNPJ')]
property Cnpj : String read FCnpj  write SetCnpj;

[MapperColumn('IE')]
property Ie : String read FIe  write SetIe;

[MapperColumn('CEP')]
property Cep : String read FCep  write SetCep;

[MapperColumn('ENDERECO')]
property Endereco : String read FEndereco  write SetEndereco;

[MapperColumn('NUMERO')]
property Numero : String read FNumero  write SetNumero;

[MapperColumn('COMPLEMENTO')]
property Complemento : String read FComplemento  write SetComplemento;

[MapperColumn('BAIRRO')]
property Bairro : String read FBairro  write SetBairro;

[MapperColumn('TELEFONE')]
property Telefone : String read FTelefone  write SetTelefone;

[MapperColumn('FAX')]
property Fax : String read FFax  write SetFax;

[MapperColumn('CELULAR')]
property Celular : String read FCelular  write SetCelular;

[MapperColumn('MOTIVO_STATUS')]
property Motivo_status : String read FMotivo_status  write SetMotivo_status;

[MapperColumn('STATUS')]
property Status : String read FStatus  write SetStatus;

[MapperColumn('GRUPO_PESSOA_ID')]
property Grupo_pessoa_id : Integer read FGrupo_pessoa_id  write SetGrupo_pessoa_id;

[MapperColumn('UF')]
property Uf : String read FUf  write SetUf;

[MapperColumn('CIDADE_ID')]
property Cidade_id : Integer read FCidade_id  write SetCidade_id;

[MapperColumn('LOGIN')]
property Login : String read FLogin  write SetLogin;

[MapperColumn('SENHA')]
property Senha : String read FSenha  write SetSenha;

[MapperColumn('DT_CADASTRO')]
property Dt_cadastro : TDate read FDt_cadastro  write SetDt_cadastro;

[MapperColumn('DT_NASCIMENTO')]
property Dt_nascimento : TDate read FDt_nascimento  write SetDt_nascimento;

[MapperColumn('CONTATO')]
property Contato : String read FContato  write SetContato;

[MapperColumn('REF_01')]
property Ref_01 : String read FRef_01  write SetRef_01;

[MapperColumn('REF_02')]
property Ref_02 : String read FRef_02  write SetRef_02;

[MapperColumn('REF_03')]
property Ref_03 : String read FRef_03  write SetRef_03;

[MapperColumn('REF_04')]
property Ref_04 : String read FRef_04  write SetRef_04;

[MapperColumn('REF_ENTREGA')]
property Ref_entrega : String read FRef_entrega  write SetRef_entrega;

[MapperColumn('EMAIL_PRINCIPAL')]
property Email_principal : String read FEmail_principal  write SetEmail_principal;

[MapperColumn('LIMITE_CREDITO')]
property Limite_credito : Integer read FLimite_credito  write SetLimite_credito;

[MapperColumn('SPC')]
property Spc : String read FSpc  write SetSpc;

[MapperColumn('DT_CONSULTASPC')]
property Dt_consultaspc : TDate read FDt_consultaspc  write SetDt_consultaspc;

[MapperColumn('VENDEDORPADRAO_ID')]
property Vendedorpadrao_id : Integer read FVendedorpadrao_id  write SetVendedorpadrao_id;

[MapperColumn('OBSERVACOES')]
property Observacoes : String read FObservacoes  write SetObservacoes;

[MapperColumn('CODIGO_INTERNO')]
property Codigo_interno : String read FCodigo_interno  write SetCodigo_interno;

[MapperColumn('TIPO_CLIENTE')]
property Tipo_cliente : String read FTipo_cliente  write SetTipo_cliente;

[MapperColumn('TIPO_FORNECEDOR')]
property Tipo_fornecedor : String read FTipo_fornecedor  write SetTipo_fornecedor;

[MapperColumn('TIPO_TRANSPORTADORA')]
property Tipo_transportadora : String read FTipo_transportadora  write SetTipo_transportadora;

[MapperColumn('TIPO_FUNCIONARIO')]
property Tipo_funcionario : String read FTipo_funcionario  write SetTipo_funcionario;

[MapperColumn('TIPO_VENDEDOR')]
property Tipo_vendedor : String read FTipo_vendedor  write SetTipo_vendedor;

[MapperColumn('TIPO_USUARIO')]
property Tipo_usuario : String read FTipo_usuario  write SetTipo_usuario;

[MapperColumn('TIPO_OUTROS')]
property Tipo_outros : String read FTipo_outros  write SetTipo_outros;

[MapperColumn('TIPO_OUTROS_DESCRICAO')]
property Tipo_outros_descricao : String read FTipo_outros_descricao  write SetTipo_outros_descricao;

[MapperColumn('GRUPOUSUARIO_ID')]
property Grupousuario_id : Integer read FGrupousuario_id  write SetGrupousuario_id;

[MapperColumn('SALARIO')]
property Salario : Integer read FSalario  write SetSalario;

[MapperColumn('DT_REGISTRO')]
property Dt_registro : TDate read FDt_registro  write SetDt_registro;

[MapperColumn('CARGO')]
property Cargo : String read FCargo  write SetCargo;

[MapperColumn('REFCONTATO')]
property Refcontato : String read FRefcontato  write SetRefcontato;

[MapperColumn('TIPO_TECNICO')]
property Tipo_tecnico : String read FTipo_tecnico  write SetTipo_tecnico;

[MapperColumn('TIPO_LOCADOR')]
property Tipo_locador : String read FTipo_locador  write SetTipo_locador;

[MapperColumn('TIPO_LOCATARIO')]
property Tipo_locatario : String read FTipo_locatario  write SetTipo_locatario;

[MapperColumn('REGIMETRIBUTARIO_DESCRICAO')]
property Regimetributario_descricao : String read FRegimetributario_descricao  write SetRegimetributario_descricao;

[MapperColumn('CNAE')]
property Cnae : Integer read FCnae  write SetCnae;

[MapperColumn('CODIGO_EXTERNO')]
property Codigo_externo : Integer read FCodigo_externo  write SetCodigo_externo;

[MapperColumn('ATIVAR_AGENDA')]
property Ativar_agenda : String read FAtivar_agenda  write SetAtivar_agenda;

[MapperColumn('CODIGO_VENDEDOR')]
property Codigo_vendedor : Integer read FCodigo_vendedor  write SetCodigo_vendedor;

[MapperColumn('TRANSPORTADORA_UF_PLACA')]
property Transportadora_uf_placa : String read FTransportadora_uf_placa  write SetTransportadora_uf_placa;

[MapperColumn('TRANSPORTADORA_PLACA')]
property Transportadora_placa : String read FTransportadora_placa  write SetTransportadora_placa;

[MapperColumn('TIPO_REVENDA')]
property Tipo_revenda : String read FTipo_revenda  write SetTipo_revenda;

[MapperColumn('TRANSPORTADORA_PADRAO_ID')]
property Transportadora_padrao_id : Integer read FTransportadora_padrao_id  write SetTransportadora_padrao_id;

[MapperColumn('SEGMENTO_ID')]
property Segmento_id : Integer read FSegmento_id  write SetSegmento_id;

[MapperColumn('MEDIA_VOLUME')]
property Media_volume : Integer read FMedia_volume  write SetMedia_volume;

[MapperColumn('MEDIA_VALOR')]
property Media_valor : Integer read FMedia_valor  write SetMedia_valor;

[MapperColumn('MEDIA_AFERICAO')]
property Media_afericao : TDate read FMedia_afericao  write SetMedia_afericao;

[MapperColumn('MEDIA_PERIODO_INICIAL')]
property Media_periodo_inicial : TDate read FMedia_periodo_inicial  write SetMedia_periodo_inicial;

[MapperColumn('MEDIA_PERIODO_FINAL')]
property Media_periodo_final : TDate read FMedia_periodo_final  write SetMedia_periodo_final;

[MapperColumn('MEDIA_QTDE_MOVIMENTACOES')]
property Media_qtde_movimentacoes : Integer read FMedia_qtde_movimentacoes  write SetMedia_qtde_movimentacoes;

[MapperColumn('SINCRONIZADO')]
property Sincronizado : String read FSincronizado  write SetSincronizado;

[MapperColumn('ADMINISTRADORA_CARTAO')]
property Administradora_cartao : String read FAdministradora_cartao  write SetAdministradora_cartao;

[MapperColumn('PAI')]
property Pai : String read FPai  write SetPai;

[MapperColumn('MAE')]
property Mae : String read FMae  write SetMae;

[MapperColumn('CONJUGE')]
property Conjuge : String read FConjuge  write SetConjuge;

[MapperColumn('CONJUGE_CPF')]
property Conjuge_cpf : String read FConjuge_cpf  write SetConjuge_cpf;

[MapperColumn('CONJUGE_CEL')]
property Conjuge_cel : String read FConjuge_cel  write SetConjuge_cel;

[MapperColumn('CONJUGE_EMPRESA')]
property Conjuge_empresa : String read FConjuge_empresa  write SetConjuge_empresa;

[MapperColumn('LOCAL_TRABALHO')]
property Local_trabalho : String read FLocal_trabalho  write SetLocal_trabalho;

[MapperColumn('DT_ULTIMAMOV')]
property Dt_ultimamov : TDate read FDt_ultimamov  write SetDt_ultimamov;

[MapperColumn('VENDEDOR_COMISSAO')]
property Vendedor_comissao : Double read FVendedor_comissao  write SetVendedor_comissao;

[MapperColumn('EXT_CODIGO_CLIENTE')]
property Ext_codigo_cliente : Integer read FExt_codigo_cliente  write SetExt_codigo_cliente;

[MapperColumn('EXT_CODIGO_FORNECEDOR')]
property Ext_codigo_fornecedor : Integer read FExt_codigo_fornecedor  write SetExt_codigo_fornecedor;

[MapperColumn('EXT_CODIGO_VENDEDOR')]
property Ext_codigo_vendedor : Integer read FExt_codigo_vendedor  write SetExt_codigo_vendedor;

[MapperColumn('LIBERAR_VENDA_PRAZO')]
property Liberar_venda_prazo : String read FLiberar_venda_prazo  write SetLiberar_venda_prazo;

[MapperColumn('ACESSO_GRUPO_ID')]
property Acesso_grupo_id : Integer read FAcesso_grupo_id  write SetAcesso_grupo_id;

[MapperColumn('ADMINISTRADOR')]
property Administrador : String read FAdministrador  write SetAdministrador;

[MapperColumn('PESSOA_AVATAR')]
property Pessoa_avatar : String read FPessoa_avatar  write SetPessoa_avatar;

[MapperColumn('ACESSO_DATAHORA')]
property Acesso_datahora : TDateTime read FAcesso_datahora  write SetAcesso_datahora;

[MapperColumn('ACESSO_IP')]
property Acesso_ip : String read FAcesso_ip  write SetAcesso_ip;

[MapperColumn('COBRANCA_ENDERECO')]
property Cobranca_endereco : String read FCobranca_endereco  write SetCobranca_endereco;

[MapperColumn('COBRANCA_NUMERO')]
property Cobranca_numero : String read FCobranca_numero  write SetCobranca_numero;

[MapperColumn('COBRANCA_COMPLEMENTO')]
property Cobranca_complemento : String read FCobranca_complemento  write SetCobranca_complemento;

[MapperColumn('COBRANCA_BAIRRO')]
property Cobranca_bairro : String read FCobranca_bairro  write SetCobranca_bairro;

[MapperColumn('COBRANCA_TELEFONE1')]
property Cobranca_telefone1 : String read FCobranca_telefone1  write SetCobranca_telefone1;

[MapperColumn('COBRANCA_TELEFONE2')]
property Cobranca_telefone2 : String read FCobranca_telefone2  write SetCobranca_telefone2;

[MapperColumn('COBRANCA_TELEFONE3')]
property Cobranca_telefone3 : String read FCobranca_telefone3  write SetCobranca_telefone3;

[MapperColumn('COBRANCA_CONTATO')]
property Cobranca_contato : String read FCobranca_contato  write SetCobranca_contato;

[MapperColumn('COBRANCA_EMAIL')]
property Cobranca_email : String read FCobranca_email  write SetCobranca_email;

[MapperColumn('COBRANCA_CEP')]
property Cobranca_cep : String read FCobranca_cep  write SetCobranca_cep;

[MapperColumn('COBRANCA_UF')]
property Cobranca_uf : String read FCobranca_uf  write SetCobranca_uf;

[MapperColumn('COBRANCA_CIDADE_ID')]
property Cobranca_cidade_id : Integer read FCobranca_cidade_id  write SetCobranca_cidade_id;

[MapperColumn('COD_CNAE_PRINCIPAL')]
property Cod_cnae_principal : String read FCod_cnae_principal  write SetCod_cnae_principal;

[MapperColumn('SF_CAPITALSOCIAL')]
property Sf_capitalsocial : Integer read FSf_capitalsocial  write SetSf_capitalsocial;

[MapperColumn('SF_CAPITALINTEGRALIZADO')]
property Sf_capitalintegralizado : Integer read FSf_capitalintegralizado  write SetSf_capitalintegralizado;

[MapperColumn('SF_CAPITALGIRO')]
property Sf_capitalgiro : Integer read FSf_capitalgiro  write SetSf_capitalgiro;

[MapperColumn('SF_IMOBILIZADO')]
property Sf_imobilizado : Integer read FSf_imobilizado  write SetSf_imobilizado;

[MapperColumn('COBRANCA_REF_ENTREGA')]
property Cobranca_ref_entrega : String read FCobranca_ref_entrega  write SetCobranca_ref_entrega;

[MapperColumn('URL')]
property Url : String read FUrl  write SetUrl;

[MapperColumn('CONFIG_EMAIL_SMTP')]
property Config_email_smtp : String read FConfig_email_smtp  write SetConfig_email_smtp;

[MapperColumn('CONFIG_EMAIL_SMTP_PORTA')]
property Config_email_smtp_porta : Integer read FConfig_email_smtp_porta  write SetConfig_email_smtp_porta;

[MapperColumn('CONFIG_EMAIL_USUARIO')]
property Config_email_usuario : String read FConfig_email_usuario  write SetConfig_email_usuario;

[MapperColumn('CONFIG_EMAIL_SENHA')]
property Config_email_senha : String read FConfig_email_senha  write SetConfig_email_senha;

[MapperColumn('CONFIG_EMAIL_POP')]
property Config_email_pop : String read FConfig_email_pop  write SetConfig_email_pop;

[MapperColumn('CONFIG_EMAIL_POP_PORTA')]
property Config_email_pop_porta : Smallint read FConfig_email_pop_porta  write SetConfig_email_pop_porta;

[MapperColumn('CONFIG_EMAIL_SMTP_SSL')]
property Config_email_smtp_ssl : String read FConfig_email_smtp_ssl  write SetConfig_email_smtp_ssl;

[MapperColumn('CONFIG_EMAIL_POP_SSL')]
property Config_email_pop_ssl : String read FConfig_email_pop_ssl  write SetConfig_email_pop_ssl;

[MapperColumn('CONFIG_EMAIL_POP_USUARIO')]
property Config_email_pop_usuario : String read FConfig_email_pop_usuario  write SetConfig_email_pop_usuario;

[MapperColumn('CONFIG_EMAIL_POP_SENHA')]
property Config_email_pop_senha : String read FConfig_email_pop_senha  write SetConfig_email_pop_senha;

[MapperColumn('INCENTIVADOR_CULTURAL')]
property Incentivador_cultural : String read FIncentivador_cultural  write SetIncentivador_cultural;

[MapperColumn('INSCRICAO_MUNICIPAL')]
property Inscricao_municipal : String read FInscricao_municipal  write SetInscricao_municipal;

[MapperColumn('OPTANTE_SIMPLESNACIONAL')]
property Optante_simplesnacional : String read FOptante_simplesnacional  write SetOptante_simplesnacional;

[MapperColumn('RETER_ISS')]
property Reter_iss : String read FReter_iss  write SetReter_iss;

[MapperColumn('REGIAO_ID')]
property Regiao_id : Integer read FRegiao_id  write SetRegiao_id;

[MapperColumn('PESSOA_CLASSIFICACAO_ID')]
property Pessoa_classificacao_id : Integer read FPessoa_classificacao_id  write SetPessoa_classificacao_id;

[MapperColumn('QUALIFICACAO_FINANCEIRA')]
property Qualificacao_financeira : String read FQualificacao_financeira  write SetQualificacao_financeira;

[MapperColumn('LATITUDE')]
property Latitude : Double read FLatitude  write SetLatitude;

[MapperColumn('LONGITUDE')]
property Longitude : Double read FLongitude  write SetLongitude;

[MapperColumn('LATITUDE_COBRANCA')]
property Latitude_cobranca : Double read FLatitude_cobranca  write SetLatitude_cobranca;

[MapperColumn('LONGITUDE_COBRANCA')]
property Longitude_cobranca : Double read FLongitude_cobranca  write SetLongitude_cobranca;

[MapperColumn('CK_GEO_PRINCIPAL_OK')]
property Ck_geo_principal_ok : String read FCk_geo_principal_ok  write SetCk_geo_principal_ok;

[MapperColumn('CK_GEO_COBRANCA_OK')]
property Ck_geo_cobranca_ok : String read FCk_geo_cobranca_ok  write SetCk_geo_cobranca_ok;

[MapperColumn('DT_STATUS')]
property Dt_status : TDate read FDt_status  write SetDt_status;

[MapperColumn('DT_REVISAO_CADASTRO')]
property Dt_revisao_cadastro : TDate read FDt_revisao_cadastro  write SetDt_revisao_cadastro;

[MapperColumn('CNAE_DESCRICAO')]
property Cnae_descricao : String read FCnae_descricao  write SetCnae_descricao;

[MapperColumn('SITUACAO_RECEITA')]
property Situacao_receita : String read FSituacao_receita  write SetSituacao_receita;

[MapperColumn('NATUREZA_JURIDICA')]
property Natureza_juridica : String read FNatureza_juridica  write SetNatureza_juridica;

[MapperColumn('TIPO')]
property Tipo : String read FTipo  write SetTipo;

[MapperColumn('CNAE_FISCAL')]
property Cnae_fiscal : String read FCnae_fiscal  write SetCnae_fiscal;

[MapperColumn('ROADMAP_MOSTRADO')]
property Roadmap_mostrado : String read FRoadmap_mostrado  write SetRoadmap_mostrado;

[MapperColumn('LIBERAR_BI')]
property Liberar_bi : String read FLiberar_bi  write SetLiberar_bi;

[MapperColumn('BLOQUEAR_AUTOMATICO')]
property Bloquear_automatico : String read FBloquear_automatico  write SetBloquear_automatico;

[MapperColumn('BLOQUEADO_AUTOMATICO')]
property Bloqueado_automatico : String read FBloqueado_automatico  write SetBloqueado_automatico;

[MapperColumn('AGENDA_WORKSTART')]
property Agenda_workstart : TTime read FAgenda_workstart  write SetAgenda_workstart;

[MapperColumn('AGENDA_WORKFINISH')]
property Agenda_workfinish : TTime read FAgenda_workfinish  write SetAgenda_workfinish;

[MapperColumn('AGENDA_WORKDAYS_DSUNDAY')]
property Agenda_workdays_dsunday : String read FAgenda_workdays_dsunday  write SetAgenda_workdays_dsunday;

[MapperColumn('AGENDA_WORKDAYS_DMONDAY')]
property Agenda_workdays_dmonday : String read FAgenda_workdays_dmonday  write SetAgenda_workdays_dmonday;

[MapperColumn('AGENDA_WORKDAYS_DTUESDAY')]
property Agenda_workdays_dtuesday : String read FAgenda_workdays_dtuesday  write SetAgenda_workdays_dtuesday;

[MapperColumn('AGENDA_WORKDAYS_DTWEDNESDAY')]
property Agenda_workdays_dtwednesday : String read FAgenda_workdays_dtwednesday  write SetAgenda_workdays_dtwednesday;

[MapperColumn('AGENDA_WORKDAYS_DTHURSDAY')]
property Agenda_workdays_dthursday : String read FAgenda_workdays_dthursday  write SetAgenda_workdays_dthursday;

[MapperColumn('AGENDA_WORKDAYS_DFRIDAY')]
property Agenda_workdays_dfriday : String read FAgenda_workdays_dfriday  write SetAgenda_workdays_dfriday;

[MapperColumn('AGENDA_WORKDAYS_DSATURDAY')]
property Agenda_workdays_dsaturday : String read FAgenda_workdays_dsaturday  write SetAgenda_workdays_dsaturday;

[MapperColumn('CODIGO_IMPORTACAO')]
property Codigo_importacao : Integer read FCodigo_importacao  write SetCodigo_importacao;

[MapperColumn('CODIGO_RESTAURANTE')]
property Codigo_restaurante : Integer read FCodigo_restaurante  write SetCodigo_restaurante;

[MapperColumn('RESTAURANTE_NIVEL_ACESSO')]
property Restaurante_nivel_acesso : String read FRestaurante_nivel_acesso  write SetRestaurante_nivel_acesso;

[MapperColumn('ULTIMA_NOTIFICACAO_EMAIL')]
property Ultima_notificacao_email : TDate read FUltima_notificacao_email  write SetUltima_notificacao_email;

[MapperColumn('EMPRESA_PADRAO_ID')]
property Empresa_padrao_id : Integer read FEmpresa_padrao_id  write SetEmpresa_padrao_id;

[MapperColumn('DIA_VENCIMENTO_CARTEIRA')]
property Dia_vencimento_carteira : Smallint read FDia_vencimento_carteira  write SetDia_vencimento_carteira;

[MapperColumn('WS_MAP_ID')]
property Ws_map_id : Integer read FWs_map_id  write SetWs_map_id;

[MapperColumn('CONTRATO_NIVEL_ACESSO')]
property Contrato_nivel_acesso : Integer read FContrato_nivel_acesso  write SetContrato_nivel_acesso;

[MapperColumn('BOLETO_PROTESTAR')]
property Boleto_protestar : String read FBoleto_protestar  write SetBoleto_protestar;

[MapperColumn('PESSOA_TABELA_DESCONTO_ID')]
property Pessoa_tabela_desconto_id : Integer read FPessoa_tabela_desconto_id  write SetPessoa_tabela_desconto_id;

end;

implementation

{ TBaseBO }

procedure TBaseBO.CheckDelete;
begin

end;

procedure TBaseBO.CheckInsert;
begin

end;

procedure TBaseBO.CheckUpdate;
begin

end;

procedure TBaseBO.SetID(const Value: Integer);
begin
FID := Value;
end;

{ TPessoaModel }

procedure TPessoaModel.CheckDelete;
begin
inherited;
end;

procedure TPessoaModel.CheckInsert;
begin
inherited;
end;

procedure TPessoaModel.CheckUpdate;
begin
inherited;
end;

procedure TPessoaModel.SetId(const Value: Integer);
begin
FId := Value;
end;

procedure TPessoaModel.SetGenero(const Value: Integer);
begin
FGenero := Value;
end;

procedure TPessoaModel.SetRegime(const Value: String);
begin
FRegime := Value;
end;

procedure TPessoaModel.SetNome(const Value: String);
begin
FNome := Value;
end;

procedure TPessoaModel.SetNome_fantasia(const Value: String);
begin
FNome_fantasia := Value;
end;

procedure TPessoaModel.SetCnpj(const Value: String);
begin
FCnpj := Value;
end;

procedure TPessoaModel.SetIe(const Value: String);
begin
FIe := Value;
end;

procedure TPessoaModel.SetCep(const Value: String);
begin
FCep := Value;
end;

procedure TPessoaModel.SetEndereco(const Value: String);
begin
FEndereco := Value;
end;

procedure TPessoaModel.SetNumero(const Value: String);
begin
FNumero := Value;
end;

procedure TPessoaModel.SetComplemento(const Value: String);
begin
FComplemento := Value;
end;

procedure TPessoaModel.SetBairro(const Value: String);
begin
FBairro := Value;
end;

procedure TPessoaModel.SetTelefone(const Value: String);
begin
FTelefone := Value;
end;

procedure TPessoaModel.SetFax(const Value: String);
begin
FFax := Value;
end;

procedure TPessoaModel.SetCelular(const Value: String);
begin
FCelular := Value;
end;

procedure TPessoaModel.SetMotivo_status(const Value: String);
begin
FMotivo_status := Value;
end;

procedure TPessoaModel.SetStatus(const Value: String);
begin
FStatus := Value;
end;

procedure TPessoaModel.SetGrupo_pessoa_id(const Value: Integer);
begin
FGrupo_pessoa_id := Value;
end;

procedure TPessoaModel.SetUf(const Value: String);
begin
FUf := Value;
end;

procedure TPessoaModel.SetCidade_id(const Value: Integer);
begin
FCidade_id := Value;
end;

procedure TPessoaModel.SetLogin(const Value: String);
begin
FLogin := Value;
end;

procedure TPessoaModel.SetSenha(const Value: String);
begin
FSenha := Value;
end;

procedure TPessoaModel.SetDt_cadastro(const Value: TDate);
begin
FDt_cadastro := Value;
end;

procedure TPessoaModel.SetDt_nascimento(const Value: TDate);
begin
FDt_nascimento := Value;
end;

procedure TPessoaModel.SetContato(const Value: String);
begin
FContato := Value;
end;

procedure TPessoaModel.SetRef_01(const Value: String);
begin
FRef_01 := Value;
end;

procedure TPessoaModel.SetRef_02(const Value: String);
begin
FRef_02 := Value;
end;

procedure TPessoaModel.SetRef_03(const Value: String);
begin
FRef_03 := Value;
end;

procedure TPessoaModel.SetRef_04(const Value: String);
begin
FRef_04 := Value;
end;

procedure TPessoaModel.SetRef_entrega(const Value: String);
begin
FRef_entrega := Value;
end;

procedure TPessoaModel.SetEmail_principal(const Value: String);
begin
FEmail_principal := Value;
end;

procedure TPessoaModel.SetLimite_credito(const Value: Integer);
begin
FLimite_credito := Value;
end;

procedure TPessoaModel.SetSpc(const Value: String);
begin
FSpc := Value;
end;

procedure TPessoaModel.SetDt_consultaspc(const Value: TDate);
begin
FDt_consultaspc := Value;
end;

procedure TPessoaModel.SetVendedorpadrao_id(const Value: Integer);
begin
FVendedorpadrao_id := Value;
end;

procedure TPessoaModel.SetObservacoes(const Value: String);
begin
FObservacoes := Value;
end;

procedure TPessoaModel.SetCodigo_interno(const Value: String);
begin
FCodigo_interno := Value;
end;

procedure TPessoaModel.SetTipo_cliente(const Value: String);
begin
FTipo_cliente := Value;
end;

procedure TPessoaModel.SetTipo_fornecedor(const Value: String);
begin
FTipo_fornecedor := Value;
end;

procedure TPessoaModel.SetTipo_transportadora(const Value: String);
begin
FTipo_transportadora := Value;
end;

procedure TPessoaModel.SetTipo_funcionario(const Value: String);
begin
FTipo_funcionario := Value;
end;

procedure TPessoaModel.SetTipo_vendedor(const Value: String);
begin
FTipo_vendedor := Value;
end;

procedure TPessoaModel.SetTipo_usuario(const Value: String);
begin
FTipo_usuario := Value;
end;

procedure TPessoaModel.SetTipo_outros(const Value: String);
begin
FTipo_outros := Value;
end;

procedure TPessoaModel.SetTipo_outros_descricao(const Value: String);
begin
FTipo_outros_descricao := Value;
end;

procedure TPessoaModel.SetGrupousuario_id(const Value: Integer);
begin
FGrupousuario_id := Value;
end;

procedure TPessoaModel.SetSalario(const Value: Integer);
begin
FSalario := Value;
end;

procedure TPessoaModel.SetDt_registro(const Value: TDate);
begin
FDt_registro := Value;
end;

procedure TPessoaModel.SetCargo(const Value: String);
begin
FCargo := Value;
end;

procedure TPessoaModel.SetRefcontato(const Value: String);
begin
FRefcontato := Value;
end;

procedure TPessoaModel.SetTipo_tecnico(const Value: String);
begin
FTipo_tecnico := Value;
end;

procedure TPessoaModel.SetTipo_locador(const Value: String);
begin
FTipo_locador := Value;
end;

procedure TPessoaModel.SetTipo_locatario(const Value: String);
begin
FTipo_locatario := Value;
end;

procedure TPessoaModel.SetRegimetributario_descricao(const Value: String);
begin
FRegimetributario_descricao := Value;
end;

procedure TPessoaModel.SetCnae(const Value: Integer);
begin
FCnae := Value;
end;

procedure TPessoaModel.SetCodigo_externo(const Value: Integer);
begin
FCodigo_externo := Value;
end;

procedure TPessoaModel.SetAtivar_agenda(const Value: String);
begin
FAtivar_agenda := Value;
end;

procedure TPessoaModel.SetCodigo_vendedor(const Value: Integer);
begin
FCodigo_vendedor := Value;
end;

procedure TPessoaModel.SetTransportadora_uf_placa(const Value: String);
begin
FTransportadora_uf_placa := Value;
end;

procedure TPessoaModel.SetTransportadora_placa(const Value: String);
begin
FTransportadora_placa := Value;
end;

procedure TPessoaModel.SetTipo_revenda(const Value: String);
begin
FTipo_revenda := Value;
end;

procedure TPessoaModel.SetTransportadora_padrao_id(const Value: Integer);
begin
FTransportadora_padrao_id := Value;
end;

procedure TPessoaModel.SetSegmento_id(const Value: Integer);
begin
FSegmento_id := Value;
end;

procedure TPessoaModel.SetMedia_volume(const Value: Integer);
begin
FMedia_volume := Value;
end;

procedure TPessoaModel.SetMedia_valor(const Value: Integer);
begin
FMedia_valor := Value;
end;

procedure TPessoaModel.SetMedia_afericao(const Value: TDate);
begin
FMedia_afericao := Value;
end;

procedure TPessoaModel.SetMedia_periodo_inicial(const Value: TDate);
begin
FMedia_periodo_inicial := Value;
end;

procedure TPessoaModel.SetMedia_periodo_final(const Value: TDate);
begin
FMedia_periodo_final := Value;
end;

procedure TPessoaModel.SetMedia_qtde_movimentacoes(const Value: Integer);
begin
FMedia_qtde_movimentacoes := Value;
end;

procedure TPessoaModel.SetSincronizado(const Value: String);
begin
FSincronizado := Value;
end;

procedure TPessoaModel.SetAdministradora_cartao(const Value: String);
begin
FAdministradora_cartao := Value;
end;

procedure TPessoaModel.SetPai(const Value: String);
begin
FPai := Value;
end;

procedure TPessoaModel.SetMae(const Value: String);
begin
FMae := Value;
end;

procedure TPessoaModel.SetConjuge(const Value: String);
begin
FConjuge := Value;
end;

procedure TPessoaModel.SetConjuge_cpf(const Value: String);
begin
FConjuge_cpf := Value;
end;

procedure TPessoaModel.SetConjuge_cel(const Value: String);
begin
FConjuge_cel := Value;
end;

procedure TPessoaModel.SetConjuge_empresa(const Value: String);
begin
FConjuge_empresa := Value;
end;

procedure TPessoaModel.SetLocal_trabalho(const Value: String);
begin
FLocal_trabalho := Value;
end;

procedure TPessoaModel.SetDt_ultimamov(const Value: TDate);
begin
FDt_ultimamov := Value;
end;

procedure TPessoaModel.SetVendedor_comissao(const Value: Double);
begin
FVendedor_comissao := Value;
end;

procedure TPessoaModel.SetExt_codigo_cliente(const Value: Integer);
begin
FExt_codigo_cliente := Value;
end;

procedure TPessoaModel.SetExt_codigo_fornecedor(const Value: Integer);
begin
FExt_codigo_fornecedor := Value;
end;

procedure TPessoaModel.SetExt_codigo_vendedor(const Value: Integer);
begin
FExt_codigo_vendedor := Value;
end;

procedure TPessoaModel.SetLiberar_venda_prazo(const Value: String);
begin
FLiberar_venda_prazo := Value;
end;

procedure TPessoaModel.SetAcesso_grupo_id(const Value: Integer);
begin
FAcesso_grupo_id := Value;
end;

procedure TPessoaModel.SetAdministrador(const Value: String);
begin
FAdministrador := Value;
end;

procedure TPessoaModel.SetPessoa_avatar(const Value: String);
begin
FPessoa_avatar := Value;
end;

procedure TPessoaModel.SetAcesso_datahora(const Value: TDateTime);
begin
FAcesso_datahora := Value;
end;

procedure TPessoaModel.SetAcesso_ip(const Value: String);
begin
FAcesso_ip := Value;
end;

procedure TPessoaModel.SetCobranca_endereco(const Value: String);
begin
FCobranca_endereco := Value;
end;

procedure TPessoaModel.SetCobranca_numero(const Value: String);
begin
FCobranca_numero := Value;
end;

procedure TPessoaModel.SetCobranca_complemento(const Value: String);
begin
FCobranca_complemento := Value;
end;

procedure TPessoaModel.SetCobranca_bairro(const Value: String);
begin
FCobranca_bairro := Value;
end;

procedure TPessoaModel.SetCobranca_telefone1(const Value: String);
begin
FCobranca_telefone1 := Value;
end;

procedure TPessoaModel.SetCobranca_telefone2(const Value: String);
begin
FCobranca_telefone2 := Value;
end;

procedure TPessoaModel.SetCobranca_telefone3(const Value: String);
begin
FCobranca_telefone3 := Value;
end;

procedure TPessoaModel.SetCobranca_contato(const Value: String);
begin
FCobranca_contato := Value;
end;

procedure TPessoaModel.SetCobranca_email(const Value: String);
begin
FCobranca_email := Value;
end;

procedure TPessoaModel.SetCobranca_cep(const Value: String);
begin
FCobranca_cep := Value;
end;

procedure TPessoaModel.SetCobranca_uf(const Value: String);
begin
FCobranca_uf := Value;
end;

procedure TPessoaModel.SetCobranca_cidade_id(const Value: Integer);
begin
FCobranca_cidade_id := Value;
end;

procedure TPessoaModel.SetCod_cnae_principal(const Value: String);
begin
FCod_cnae_principal := Value;
end;

procedure TPessoaModel.SetSf_capitalsocial(const Value: Integer);
begin
FSf_capitalsocial := Value;
end;

procedure TPessoaModel.SetSf_capitalintegralizado(const Value: Integer);
begin
FSf_capitalintegralizado := Value;
end;

procedure TPessoaModel.SetSf_capitalgiro(const Value: Integer);
begin
FSf_capitalgiro := Value;
end;

procedure TPessoaModel.SetSf_imobilizado(const Value: Integer);
begin
FSf_imobilizado := Value;
end;

procedure TPessoaModel.SetCobranca_ref_entrega(const Value: String);
begin
FCobranca_ref_entrega := Value;
end;

procedure TPessoaModel.SetUrl(const Value: String);
begin
FUrl := Value;
end;

procedure TPessoaModel.SetConfig_email_smtp(const Value: String);
begin
FConfig_email_smtp := Value;
end;

procedure TPessoaModel.SetConfig_email_smtp_porta(const Value: Integer);
begin
FConfig_email_smtp_porta := Value;
end;

procedure TPessoaModel.SetConfig_email_usuario(const Value: String);
begin
FConfig_email_usuario := Value;
end;

procedure TPessoaModel.SetConfig_email_senha(const Value: String);
begin
FConfig_email_senha := Value;
end;

procedure TPessoaModel.SetConfig_email_pop(const Value: String);
begin
FConfig_email_pop := Value;
end;

procedure TPessoaModel.SetConfig_email_pop_porta(const Value: Smallint);
begin
FConfig_email_pop_porta := Value;
end;

procedure TPessoaModel.SetConfig_email_smtp_ssl(const Value: String);
begin
FConfig_email_smtp_ssl := Value;
end;

procedure TPessoaModel.SetConfig_email_pop_ssl(const Value: String);
begin
FConfig_email_pop_ssl := Value;
end;

procedure TPessoaModel.SetConfig_email_pop_usuario(const Value: String);
begin
FConfig_email_pop_usuario := Value;
end;

procedure TPessoaModel.SetConfig_email_pop_senha(const Value: String);
begin
FConfig_email_pop_senha := Value;
end;

procedure TPessoaModel.SetIncentivador_cultural(const Value: String);
begin
FIncentivador_cultural := Value;
end;

procedure TPessoaModel.SetInscricao_municipal(const Value: String);
begin
FInscricao_municipal := Value;
end;

procedure TPessoaModel.SetOptante_simplesnacional(const Value: String);
begin
FOptante_simplesnacional := Value;
end;

procedure TPessoaModel.SetReter_iss(const Value: String);
begin
FReter_iss := Value;
end;

procedure TPessoaModel.SetRegiao_id(const Value: Integer);
begin
FRegiao_id := Value;
end;

procedure TPessoaModel.SetPessoa_classificacao_id(const Value: Integer);
begin
FPessoa_classificacao_id := Value;
end;

procedure TPessoaModel.SetQualificacao_financeira(const Value: String);
begin
FQualificacao_financeira := Value;
end;

procedure TPessoaModel.SetLatitude(const Value: Double);
begin
FLatitude := Value;
end;

procedure TPessoaModel.SetLongitude(const Value: Double);
begin
FLongitude := Value;
end;

procedure TPessoaModel.SetLatitude_cobranca(const Value: Double);
begin
FLatitude_cobranca := Value;
end;

procedure TPessoaModel.SetLongitude_cobranca(const Value: Double);
begin
FLongitude_cobranca := Value;
end;

procedure TPessoaModel.SetCk_geo_principal_ok(const Value: String);
begin
FCk_geo_principal_ok := Value;
end;

procedure TPessoaModel.SetCk_geo_cobranca_ok(const Value: String);
begin
FCk_geo_cobranca_ok := Value;
end;

procedure TPessoaModel.SetDt_status(const Value: TDate);
begin
FDt_status := Value;
end;

procedure TPessoaModel.SetDt_revisao_cadastro(const Value: TDate);
begin
FDt_revisao_cadastro := Value;
end;

procedure TPessoaModel.SetCnae_descricao(const Value: String);
begin
FCnae_descricao := Value;
end;

procedure TPessoaModel.SetSituacao_receita(const Value: String);
begin
FSituacao_receita := Value;
end;

procedure TPessoaModel.SetNatureza_juridica(const Value: String);
begin
FNatureza_juridica := Value;
end;

procedure TPessoaModel.SetTipo(const Value: String);
begin
FTipo := Value;
end;

procedure TPessoaModel.SetCnae_fiscal(const Value: String);
begin
FCnae_fiscal := Value;
end;

procedure TPessoaModel.SetRoadmap_mostrado(const Value: String);
begin
FRoadmap_mostrado := Value;
end;

procedure TPessoaModel.SetLiberar_bi(const Value: String);
begin
FLiberar_bi := Value;
end;

procedure TPessoaModel.SetBloquear_automatico(const Value: String);
begin
FBloquear_automatico := Value;
end;

procedure TPessoaModel.SetBloqueado_automatico(const Value: String);
begin
FBloqueado_automatico := Value;
end;

procedure TPessoaModel.SetAgenda_workstart(const Value: TTime);
begin
FAgenda_workstart := Value;
end;

procedure TPessoaModel.SetAgenda_workfinish(const Value: TTime);
begin
FAgenda_workfinish := Value;
end;

procedure TPessoaModel.SetAgenda_workdays_dsunday(const Value: String);
begin
FAgenda_workdays_dsunday := Value;
end;

procedure TPessoaModel.SetAgenda_workdays_dmonday(const Value: String);
begin
FAgenda_workdays_dmonday := Value;
end;

procedure TPessoaModel.SetAgenda_workdays_dtuesday(const Value: String);
begin
FAgenda_workdays_dtuesday := Value;
end;

procedure TPessoaModel.SetAgenda_workdays_dtwednesday(const Value: String);
begin
FAgenda_workdays_dtwednesday := Value;
end;

procedure TPessoaModel.SetAgenda_workdays_dthursday(const Value: String);
begin
FAgenda_workdays_dthursday := Value;
end;

procedure TPessoaModel.SetAgenda_workdays_dfriday(const Value: String);
begin
FAgenda_workdays_dfriday := Value;
end;

procedure TPessoaModel.SetAgenda_workdays_dsaturday(const Value: String);
begin
FAgenda_workdays_dsaturday := Value;
end;

procedure TPessoaModel.SetCodigo_importacao(const Value: Integer);
begin
FCodigo_importacao := Value;
end;

procedure TPessoaModel.SetCodigo_restaurante(const Value: Integer);
begin
FCodigo_restaurante := Value;
end;

procedure TPessoaModel.SetRestaurante_nivel_acesso(const Value: String);
begin
FRestaurante_nivel_acesso := Value;
end;

procedure TPessoaModel.SetUltima_notificacao_email(const Value: TDate);
begin
FUltima_notificacao_email := Value;
end;

procedure TPessoaModel.SetEmpresa_padrao_id(const Value: Integer);
begin
FEmpresa_padrao_id := Value;
end;

procedure TPessoaModel.SetDia_vencimento_carteira(const Value: Smallint);
begin
FDia_vencimento_carteira := Value;
end;

procedure TPessoaModel.SetWs_map_id(const Value: Integer);
begin
FWs_map_id := Value;
end;

procedure TPessoaModel.SetContrato_nivel_acesso(const Value: Integer);
begin
FContrato_nivel_acesso := Value;
end;

procedure TPessoaModel.SetBoleto_protestar(const Value: String);
begin
FBoleto_protestar := Value;
end;

procedure TPessoaModel.SetPessoa_tabela_desconto_id(const Value: Integer);
begin
FPessoa_tabela_desconto_id := Value;
end;

end.

OnAsyncError

this works
procedure OnAsyncSuccess(r: IRESTResponse);
var
  ed: TovEmoData;
  e: TovEmo;
begin
  try
    ed := Mapper.JSONObjectToObject<TovEmoData>(r.BodyAsJsonObject);

    e := TovEmo.Create(ed);
    try
      Form1.memo_log.Lines.Text := IntToStr(e.Visi_Id) + '.' + e.Emo_Note;
    finally
      e.Free
    end;

    ed.Free;
  except
    ShowMessage('error')
  end;
end;

procedure OnAsyncError(e: Exception);
begin
  ShowMessage('error');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  RESTClient.Asynch(OnAsyncSuccess, OnAsyncError, nil, true).doGET('/emo', ['285063'])
end;

this does not work
procedure OnAsyncSuccess(r: IRESTResponse);
var
  ed: TovEmoData;
  e: TovEmo;
begin
  try
    ed := Mapper.JSONObjectToObject<TovEmoData>(r.BodyAsJsonObject);

    e := TovEmo.Create(ed);
    try
      Form1.memo_log.Lines.Text := IntToStr(e.Visi_Id) + '.' + e.Emo_Note;
    finally
      e.Free
    end;

    ed.Free;
  except
    ShowMessage('error')
  end;
end;

procedure OnAsyncError(e: Exception);
begin
  ShowMessage(e.message);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  RESTClient.Asynch(OnAsyncSuccess, OnAsyncError, nil, true).doGET('/emo', ['285063'])
end;

only the procedure OnAsyncError is different

Original issue reported on code.google.com by [email protected] on 28 Aug 2014 at 8:19

Disable 404 for Unhanded Action

Allowing the MVC Framework to not 404 if a page or action is not found will allow the WebModule to still handle additional requests. This can allow SOAP to remain working.

Not sure if others would have interest in this; fairly simple change, and I have made it a config item.

function TMVCEngine.ExecuteAction(Sender: TObject; Request: TWebRequest;
Response: TWebResponse): boolean;

if Config[TMVCConfigKey.AllowUnhandledAction] = 'false' then //tristan
begin
Http404(Context);
handled := True; //tristan
Log(TLogLevel.levNormal, Request.Method + ':' +
Request.RawPathInfo + ' -> NO ACTION ' + ' - ' +
Response.StatusCode.ToString + ' ' + Response.ReasonString);
end;

finally
Context.Response.FlushOnDestroy := Handled; // tristan
Context.Free;
end;

Changes to TMCVWebResponse to allow a FlushOnDestroy to be stopped.

private
FStreamOutputDone: boolean;
FFlushOnDestroy: boolean; // tristan

public
property FlushOnDestroy: boolean read FFlushOnDestroy write FFlushOnDestroy; // tristan

destructor TMVCWebResponse.Destroy;
begin
if FFlushOnDestroy then // tristan
Flush;
inherited;
end;

Boolean and Mapper.DataSetToObject(ADataSet: TDataSet; AObject: TObject);

I would find a boolean field would not actually read the value from a dataset. Enumerators are ignored.

Apply after case _field.PropertyType.TypeKind of

 case _field.PropertyType.TypeKind of
      tkEnumeration : // tristan
        begin
          if _field.PropertyType.Handle = TypeInfo(Boolean) then
          begin
            case ADataSet.FieldByName(field_name).DataType of
              ftInteger, ftSmallint, ftLargeint  :
                begin
                  Value := (ADataSet.FieldByName(field_name).AsInteger = 1);
                end;
              ftBoolean :
                begin
                   Value := ADataSet.FieldByName(field_name).AsBoolean;
                end;
              else
                Continue;
            end;
          end;
        end;

Feature request: make a sample for authentication with html form

I'm new on delphimvcframework, but i have a bit of trouble to implement a basic html page for authentication.

I'm starting from AuthenticateAuthorize.dproj sample and i have add a login route

[MVCPath('/login')]
[MVCHTTPMethod([httpGET])]
procedure Login(ctx: TWebContext);
// .............................................................................
procedure TApp1MainController.Login(ctx: TWebContext);
begin
  ContentType := TMVCMediaType.TEXT_HTML;

  ResponseStream.AppendLine('<form action="/role1" method="post">');
  ResponseStream.AppendLine('<input type="text" name="username" placeholder="username" value="" /><br />');
  ResponseStream.AppendLine('<input type="password" name="password" placeholder="password" value="" /><br />');
  ResponseStream.AppendLine('<input type="submit" name="submit" value="Login" />');
  ResponseStream.AppendLine('</form>');

  RenderResponseStream;
end;

and abjust the middleware control from TMVCBasicAuthenticationMiddleware to TMVCCustomAuthenticationMiddleware:

MVC.AddMiddleware(TMVCCustomAuthenticationMiddleware.Create(TAuthenticationSample.Create, '/login'));

now, i don't undestand how handle the TMVCCustomAuthenticationMiddleware response for redirect the user on the TAdminController route if logged or on the login page if not logged.

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.