Using lookup fields in calculations

Dynamically disable drop-down fields

Some workflow scenarios require that a drop-down field be disabled based on the value of another field. For example, you may want to disable the status field when the is_active field is set to No.

There are 2 types of drop-down fields in AppGini:

How to pre-populate a new record with data passed through the url?

In some cases, you might have frequent data entries with some common values. This can be made faster and more efficient using specially formatted shortcut links.

How to completely hide the membership system, making every user an admin?

This scenario is useful mainly if you are the only user of the generated AppGini app, and don't want to have to sign in every now and then, and want to remove the 'visual clutter' of the admin link, sign out link, .. etc.

Warning The following code basically makes every user a super admin. So, NEVER use this in a public-facing or multi-user app!

Protect your app login page from brute force attacks using reCAPTCHA

The code in this tutorial was tested on AppGini 22.13 and 22.14

A common problem facing all websites is malicious 'bots', automated scripts designed to "efficiently" perform harmful actions to websites. These include posting spam in forums, signing up with fake accounts (usually to post spam), trying to hack legit accounts by making thousands of password guesses in login forms (also known as brute force attacks), .. etc.

How to automatically detect the country of a user?

Using the free API service provided by ipinfo.io, you can add code into hooks for detecting the country of the current user, given his IP address. Here is how this code looks like:

  $country = 'Unknown'; // default in case country can't be detected
  $ip = $_SERVER['REMOTE_ADDR'];
  $udata_json = @file_get_contents("https://ipinfo.io/{$ip}");
  if($udata_json){
    $udata = json_decode($udata_json, true);
    $country = $udata['country'];
  }
  // you can now use $country in your code ...

Here is a demonstration that shows your country!

Your country is US

Country info retrieved from this service is ISO Alpha-2 abbreviation.

Using lookup fields in calculations

When customizing the before_insert, after_insert, before_update or after_update hooks to make a calculation, you might encounter a case where one or more fields in the formula you're calculating is a lookup field (foreign key) . In this case, the value of $data['fieldname'] (where fieldname is the name of the concerned lookup field) is probably NOT the value you'd like to use for your calculation.

To explain that, let's have a brief look at how lookup fields work. A lookup field is a way of referencing a value from one table in another table. For example, we might be storing product unit price in the products table and want to use that same unit price in the order_items table without having to manually re-type the price ... this is important not just to save a few keystrokes during data entry, but to also ensure referential integrity ... If you throw the same product price into every table in your database, it will be a nightmare to update the price later and make sure all tables see the updated price.

To avoid that mess, we use lookup fields. A unit price lookup field in the order_items table doesn't store the actual price value but rather a reference value that points to the location of the unit price in the products table. The best possible reference to use is the primary key of the product. Let's have an example with numbers to see this in action.

Products table

ID Product Unit price
15 Lindt HELLO Crunchy Nougat 2.05
16 Lindt CREATION Crème Brûlée 2.35
18 Lindt EXCELLENCE Mint 3.25
19 Lindt CREATION Pistachio 3.25

That was yummy! Each entry in the above table has a primary key ID value, which doesn't tell much about the item itself but is used as a reference to it. So, if we talk about product #18, we know we are referring to Lindt EXCELLENCE Mint priced at $3.25. Primary key fields are usually (but not necessarily) named ID.

Let's now have a look at some data from the order_items table.

Order Items table

ID Order ID Product Unit price Quantity Subtotal
2024 305 15 15 1
2025 305 18 18 3
2026 306 18 18 1
2027 307 19 19 2

Similar to the products table, the ID column above is the primary key field of the order_items table, a way of uniquely identifying each row. OrderID is a lookup field to the orders table (not shown here as it's irrelevant to our discussion). Product and 'Unit Price' are both lookup fields to the products table. To understand this with an example, order item #2024 is an order for product #15, which is Lindt HELLO Crunchy Nougat and its price is of course that of product #15 which is $2.05. And the quantity of Lindt HELLO Crunchy Nougat ordered in this record is 1.

When your AppGini application displays the order_items table, it doesn't display reference values like the above. It automatically joins both tables and displays more human-readable results like the ones below

Order Items table joined with Products table

ID Order ID Product Unit price Quantity Subtotal
2024 305 Lindt HELLO Crunchy Nougat 2.05 1
2025 305 Lindt EXCELLENCE Mint 3.25 3
2026 306 Lindt EXCELLENCE Mint 3.25 1
2027 307 Lindt CREATION Pistachio 3.25 2

If we later make any modifications to any product in the products table, like changing its name or unit price, the changes are automatically reflected in the order_items table without having to perform any manual data entry.

What remains now is to write code for calculating the subtotal column of the order_items table. We want this calculation to be applied whenever we add a new order item and also whenever we make changes to any existing order item. Therefore, we should perform the calculation in both the before_insert and before_update hook functions.

The initial code I see many AppGini users write usually looks something like this:

$data['Subtotal'] = $data['UnitPrice'] * $data['Quantity'];

The problem with the above code is that $data['UnitPrice'] stores the primary key of the parent product (the value of the ID field from the parent record in products). For example, if we're calculating the subtotal of order item #2025, the above code would display a subtotal of 18 x 3 = $54. This is of course not correct, as the unit price for Lindt EXCELLENCE Mint is $3.25 and we have a quantity of 3 units. Therefore, the correct subtotal should be $3.25 x 3 = $9.75.

What's wrong with the above code is that we didn't take into consideration the fact that UnitPrice field in order_items is actually a lookup field. The stored value is not the unit price but rather the primary key value of the parent product. Accordingly, we should retrieve the actual unit price from the products table using this code:

$UnitPrice = sqlValue(
   "SELECT UnitPrice FROM products where ID='{$data['UnitPrice']}'"
); 

The above code retrieves the unit price from the products table given the primary key value stored in the child order_items table, $data['UnitPrice'] , and stores the actual unit price in $UnitPrice . We can now perform the calculation as follows:

$data['Subtotal'] = $UnitPrice * $data['Quantity'];

Putting it all together, whenever we are performing calculations that involve lookup fields, we should first retrieve the actual values from the parent table and use those retrieved values in the calculation formula. It's very easy to write once we understand how it works. To sum up, here is our subtotal code:

$UnitPrice = sqlValue(
  "SELECT UnitPrice FROM products where ID='{$data['UnitPrice']}'"
);
$data['Subtotal'] = $UnitPrice * $data['Quantity'];

One final note ... some tables contain non-numeric primary key values. For example, if the above products table stores primary keys as LHCN01, LEM01 ... etc rather than 18, 19 and so on, then we should escape those primary keys first to avoid query errors and protect against SQL injection attacks:

/* Escape non-numeric lookup values before using them in SQL queries */
$SafeUnitPriceLookup = makeSafe($data['UnitPrice']);

/*
  Now it's safe to use $SafeUnitPriceLookup to
  retrieve our unit price
*/
$UnitPrice = sqlValue(
  "SELECT UnitPrice FROM products where ID='{$SafeUnitPriceLookup}'"
);

/* And here is our calculation */
$data['Subtotal'] = $UnitPrice * $data['Quantity'];

To summarize, whenever you are working with lookup fields in your calculations, you should first retrieve the actual values from the parent table and then use those values in your calculations. This is a simple concept that can save you a lot of time and headaches in the future.

Step by step: hosting your AppGini application on Bluehost


Bluehost is a widely-used website hosting service that offers a friendly interface and good technical support at a reasonable price. Due to its popularity, we've wrote this detailed page describing step-by-step how to publish your AppGini-generated web application there.

Download free open source web applications


All the applications listed here are MIT-licensed free open source web applications generated by AppGini. You can easily customize them by editing the source code, or by editing the accompanying project files in AppGini (both the trial and full version of AppGini can be used).

Install AppGini on Ubuntu Linux

Mac users heads up! You can follow very similar steps to install AppGini on MacOS using PlayOnMac :)

Although AppGini officially runs on Windows PCs, you can still install it on your Linux or Mac by following the steps listed here.

How to obtain a Google Maps API key?

TLDR; To enable Google Maps support in your AppGini apps, you need to enable Maps Embed API and Maps Static API in your Google Cloud console, create an API key and copy it to AppGini.

Obtaining a Google API key can be quite challenging due to the complex, ever-changing interface of Google Cloud console. So, we are listing the specific steps in detail to get you started quickly.

Following are the steps to obtain a Google Maps API key (last updated October 22, 2019).

Syndicate content