No announcement yet.

Coding Tutorial: Using data from an external form to create a custom entity in Espo

  • Filter
  • Time
  • Show
Clear All
new posts

  • Coding Tutorial: Using data from an external form to create a custom entity in Espo

    This tutorial describes how we use an external form to capture Rental Application data and use an API call to create a custom Rental Prospect record in Espo.

    Business Case:

    We wanted to allow prospective tenants to submit a Rental Application online without having to grant them portal access, similar to the Lead to Case implementation in Espo, but we also wanted to be able to gather many pieces of information from the prospect in the Rental Application form and not having to create a table column for each form field.

    To accomplish that, we created a custom RentalProspect entity that stores some key pieces of information from the Rental Application as individual fields and also stores the HTML code of the rendered Rental Application as a text field, so an analyst can evaluate the crucial points first and then can consult the Rental Application image for secondary information.

    When a prospect submits the external Rental Application Espo will receive the information via API, instantiate a new RentalProspect entity, send an email to a designated email address notifying the arrival of the application and append it to a dashlet list in the Property manager's dashboard, so the Manager can easily see and access the new record.

    The RentalProspect entity detail display will include the "key information" as individual fields and has an option at the top left corner drop-down menu that when clicked will display the rental application image in full view.


    1) Create an API user
    Administration > API Users > Create API User
    Choose a user name (eg: "rental-lead") and press save, the system will generate an API key, copy and enter it later at the external Rental Application code

    2) Copy the PHP API wrapper class to the same directory where your external PHP form is located
    Copy this code and save as EspoApiClient.php

    3) Include the following code in the external Rental Application form php script:
    PHP Code:
    // prepare the API call process
    $my_url 'https://www.your-website-address';
    $api_key 'key-copied-from-espo-api-user-screen';
    $client = new EspoApiClient($my_url);

    /* The form PHP code goes here, including saving the HTML code as a text variable
    *  These are our "key" fields, your form might include other information
    *  The form HTML code is stored as $applicationText
    // prepare the payload to send to Espo API
    $new_rental_prospect_data = [
    'name' => $prospectName,
    'propertyAddress' => $_POST['propertyAddress'],
    'cellPhone' => $_POST['cellNumber'],
    'email' => $_POST['eMail'],
    'timeAtCurrentAddress' => $_POST['ad1Length'],
    'reasonToMoveAtCurrentAddress' => $_POST['ad1Reason2Move'],
    'rentAtCurrentAddress' => $_POST['ad1Rent'],
    'timeAtPriorAddress' => $_POST['ad2Length'],
    'reasonToMoveAtPriorAddress' => $_POST['ad2Reason2Move'],
    'rentAtPriorAddress' => $_POST['ad2Rent'],
    'monthlyIncome' => $monthlyIncome,
    'postion' => $_POST['currPosition'],
    'jobTime' => $_POST['currJobTime'],
    'rentalApplication' => $applicationText

    // make the API call to create a RentalProspect record with the submitted data
    try {
    $response $client->request('POST''RentalProspect'$new_rental_prospect_data);
    } catch (
    \Exception $e) {
    $errorCode $e->getCode();

    4) Create a hook that will send the email notification of the new record to a designated email address
    PHP Code:
    namespace Espo\Custom\Hooks\RentalProspect;


    RentalProspectHooks extends \Espo\Core\Hooks\Base
        public function 
    afterSave(Entity $entity, array $options=array())
    // when a new application is received send email notifying of the new rental application
    if($entity->isNew()) {
    // initialize the entity manager class
    $entityManager $this->getEntityManager();
    // get the email address where notification of a new rental application is to be sent
    $notificationEmail "ENTER AN EMAIL ADRESS HERE";
    // get the email address specified as outbound in the application settings
    $fromAddress $this->getConfig()->get('outboundEmailFromAddress');
    // initialize the email service
    $mailSender $this->getContainer()->get('mailSender');
    // instantiate and load an email object
    $email $this->getEntityManager()->getEntity('Email');
    'subject' => "New application received for ".trim($entity->get('description'))." from ".$entity->get('name'),
    'body' => $entity->get('rentalApplication'),
    'isHtml' => true,
    'from' => $fromAddress,
    'to' => $notificationEmail,
    'isSystem' => true

    5) Create the javascript view class that will render the RentalProspect "rentalApplication" field (text) as a full page HTML rendering at the RentalProspect detail display.
    Espo.define('custom:views/rental-prospect/record/detail', 'views/record/detail', function (Dep) {
        return Dep.extend({
            // add button to render the rental application in full view
                name: 'viewHtmlFullPage',
                label: 'View Rental Application'
            // display html data as full page
            actionViewHtmlFullPage: function () {
                // create the 'close' and 'print' action buttons to display on top of the rental application
                var actionButtons = '';
                actionButtons += '<button title="Close" class="btn btn-default btn-icon-x-wide" id="documentBackButton" type="button" onClick="closeFullPageDocument();"><span class="fa fa-times"></span></button>';
                actionButtons += '<button title="Print" class="btn btn-default btn-icon-x-wide" id="documentPrintButton" type="button" onClick="printFullPageDocument();"><span class="fa fa-print"></span></button>';
                // get the rental application html content
                var htmlData = this.model.attributes.rentalApplication;
                // remove the copyright notice temporarily to display or print the application
                // display the html data inside the #main element
                // scroll view to top

    6) Let Espo know that the custom record detail view needs to be used when rendering a RentalProspect record in detail display
        "recordViews": {
            "detail": "custom:views/rental-prospect/record/detail"

    7) Create a dashlet that will list the active Rental Prospect list
        "aclScope": "RentalProspect",
        "entityType": "RentalProspect",
        "options": {
            "fields": {
                "title": {
                    "type": "varchar",
                    "required": true
                "autorefreshInterval": {
                    "type": "enumFloat",
                    "options": [0, 0.5, 1, 2, 5, 10]
                "displayRecords": {
                    "type": "enumInt",
                    "options": [3,4,5,10,15,20,30]
                "expandedLayout": {
                    "type": "base",
                    "view": "views/dashlets/fields/records/expanded-layout"
            "defaults": {
                "orderBy": "createdAt",
                "order": "desc",
                "displayRecords": 10,
                "expandedLayout": {
                    "rows": [
                            { "name": "propertyAddress" },
                            { "name": "name", "link": true },
                            { "name": "timeAtCurrentAddress" },
                            { "name": "monthlyIncome" }
                "searchData": {
                    "bool": {
                        "onlyMy": false
                    "primary": "active"
            "layout": [
                    "rows": [
                            {"name": "title"}
                            {"name": "displayRecords"},
                            {"name": "autorefreshInterval"}
                            {"name": "expandedLayout", "fullWidth": true}
    8) Create the view class that will render the dashlet
    Espo.define('custom:views/rental-prospect/dashlets/rental-prospects', 'views/dashlets/abstract/record-list', function (Dep) {
        return Dep.extend({
            name: "RentalProspects", // dashlet file name
            scope: "RentalProspect",
            // eliminate the "Create" action option inherited from 'views/dashlets/abstract/record-list'
            setupActionList: function () {
    Last edited by telecastg; 10-14-2020, 02:48 PM.

  • #2
    Small thing, you didn't add one slash to comment line in first block of code. There is `/ prepare the payload to send to Espo API` and should be `//` at the beginning


    • telecastg
      telecastg commented
      Editing a comment
      Thanks for noticing !, I will edit now.

  • #3
    Hello telecastg ,

    Great tutorial. Appreciate your effort build the community. Love to try this out.


    • telecastg
      telecastg commented
      Editing a comment
      Thanks ! glad you liked it.