demo application Archives | phpGrid - PHP Datagrid Create PHP grids in minutes, not hours. Fri, 06 Dec 2024 04:15:10 +0000 en-US hourly 1 CodeProjecthttps://wordpress.org/?v=7.0.3 129966043 phpGrid CodeIgniter 4 Integration https://phpgrid.com/example/phpgrid-codeigniter-4-integration/ Tue, 18 Apr 2023 04:18:52 +0000 https://phpgrid.com/?p=10098

Introduction Previously, we have covered phpGrid integration with CodeIgniter 3. CodeIgniter has since gone through some major iterations and many improvements. We will integrate phpGrid with CodeIgniter 4 and take advantages of its many new features and improvements. Why Upgrade to CodeIgniter 4 from 3? Created by EllisLab in 2006, now maintained by the British […]

The post phpGrid CodeIgniter 4 Integration appeared first on phpGrid - PHP Datagrid.

]]>

Introduction

Previously, we have covered phpGrid integration with CodeIgniter 3. CodeIgniter has since gone through some major iterations and many improvements. We will integrate phpGrid with CodeIgniter 4 and take advantages of its many new features and improvements.

Why Upgrade to CodeIgniter 4 from 3?

Created by EllisLab in 2006, now maintained by the British Columbia Institute of Technology, CodeIgniter is an open-source, lightweight PHP web application framework that follows the Model-View-Controller (MVC) architectural pattern. CI is known for its small footprint, high performance, and flexible features.

CodeIgniter 3 and CodeIgniter 4 have some key differences:

  • PHP version compatibility:
    • CodeIgniter 3 is compatible with PHP 5.2.4 or newer, while CodeIgniter 4 requires PHP 7.2 or newer.
  • Namespace support:
    • CodeIgniter 4 introduces support for namespaces, which makes it easier to organize and reuse code. CodeIgniter 3 does not have namespace support.
  • Modern MVC:
    • Both versions follow the MVC architectural pattern, but CodeIgniter 4 has a more modern implementation of the pattern with features like namespace support and PSR-4 autoloading.
  • Directory structure:
    • The directory structure of CodeIgniter 4 is different from CodeIgniter 3, with some new directories like app/Config and app/Views. The new directory structure provides a more organized and modular approach to application development.

Overall, while CodeIgniter 3 is still a solid framework for PHP web application development, CodeIgniter 4 offers several new features and improvements that make it a more modern and robust option for developers.

Install phpGrid

First, you need to download and install phpGrid on your server. You can download the latest version of phpGrid Lite. Extract the files into public folder.

codeigniter phpgrid folder structure

 

It is important to extract phpGrid into public folder, which is now recommended location for phpGrid.
X

phpGrid Configuration

Before using phpGrid, you need to specify database information in conf.php. conf.php is phpGrid configuration file in which we specify database connection parameters and path to the phpGrid. Please follow installation guide for configuration details.

Example 1: Insert phpGrid in CodeIgniter

For this tutorial, we add phpGrid in public\welcome_message.php, which is the default view in CodeIgniter 4. You can insert phpGrid in any other pages in public folder.

For free phpGrid Lite, namespace isn’t required

1
2
3
4
5
6
7
8
9
10
11
12
13
<section>

    <h1>phpGrid Demo</h1>

    <?php  
    require_once("../../phpGridx/conf.php");

    $dg = new C_DataGrid("SELECT * FROM orders", "orderNumber", "orders");
    $dg->enable_autowidth(true);
    $dg -> display();  
    ?>

</section>

For commercial version, be sure to add namespace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<section>

    <h1>phpGrid Demo</h1>

    <?php  
    use phpCtrl\C_DataGrid;
    require_once("../../phpGridx/conf.php");

    $dg = new C_DataGrid("SELECT * FROM orders", "orderNumber", "orders");
    $dg->enable_autowidth(true);
    $dg -> display();  
    ?>

</section>

Example 2: Add phpGrid to Another Page

To add phpGrid to other pages, following CodeIgniter Route Rules in app/Config/Routes.php. For example:

Route

1
2
3
// file: app/Config/Routes.php
$routes->get('/', 'Home::index');
$routes->get('/grid', 'Home::grid');

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// file: app/Controller/home.php
namespace App\Controllers;

class Home extends BaseController
{
    public function index()
    {
        return view('welcome_message');
    }

    public function grid()
    {
        return view('grid');
    }
}

View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Anther Grid</title>
</head>
<body>


<h1>Another grid</h1>

<?php  
use phpCtrl\C_DataGrid;
require_once("../../phpGridx/conf.php");

$dg = new C_DataGrid("SELECT * FROM orders", "orderNumber", "orders");
$dg->enable_autowidth(true);
$dg->enable_edit();
$dg -> display();  
?>

</body>
</html>

The post phpGrid CodeIgniter 4 Integration appeared first on phpGrid - PHP Datagrid.

]]>
10098
Laravel 10 & Bootstrap 5 Inventory Management with Dashboard, User Management https://phpgrid.com/example/inventory-management-dashboard-user-management-laravel-10-bootstrap-5/ Fri, 14 Apr 2023 18:27:12 +0000 https://phpgrid.com/?p=10078

Introduction This is an expansion of the popular inventory management system tutorial, integrated with Laravel 10, Bootstrap 5, as an out-of-box, and also customizable solution, can be used right away with little configuration. The inventory management system includes features like inventory tracking, stock alerts, barcode scanning, purchase order management, sales order management, and report generation. With […]

The post Laravel 10 & Bootstrap 5 Inventory Management with Dashboard, User Management appeared first on phpGrid - PHP Datagrid.

]]>

Introduction

This is an expansion of the popular inventory management system tutorial, integrated with Laravel 10, Bootstrap 5, as an out-of-box, and also customizable solution, can be used right away with little configuration.

The inventory management system includes features like inventory tracking, stock alerts, barcode scanning, purchase order management, sales order management, and report generation. With this system, you can easily manage your inventory, keep track of your stock levels, and ensure that you have the right amount of inventory on hand at all times.

In terms of the technology used, Laravel 10 provides a robust and secure back-end framework for handling the database and business logic, while Bootstrap allows for the creation of user-friendly front-end interfaces that are optimized for mobile devices.

The system is designed with a user-friendly interface, which makes it easy for users to navigate through the different sections of the application. This is important because it helps users to quickly access the information they need without having to spend too much time searching for it.

System Requirements

Our Inventory System requires the standard commercial phpGrid and phpChart license as it needs a few advanced features from both components.

  • PHP 8.1
  • MySQL or MariaDB
  • phpGrid 7+
  • phpChart (used for dashboard)

Inventory Management Components

    Database Diagram (updated 2023)

    The new inventory system has added a category in addition to products, purchases, orders, and suppliers. Current inventory, or products on hand, is updated by tracking incoming shipments and outgoing orders. Order alerts can be set to trigger when inventory levels fall below custom-defined minimum levels.

     

    Set up Database:

    The inventory management now has two separate databases, a inventory management database, and a Laravel framework database for user and session management.

    Import Inventory Management Database

    First of all, you’ll need to create a database for your inventory management system using InventoryManager.sql SQL script in the end of this tutorial. Execute the script using a MySQL tool such as MySQL Workbench. This will create a new database named InventoryManager.

    Set up Laravel System Database

    You will use Laravel’s built-in database migrations to create the necessary system tables and columns.

    1. Copy 
      1
      .env.example

       to 

      1
      .env

       and updated the configurations (mainly the database configuration)

    2. In your terminal run 
      1
      php artisan key:generate
    3. Run 
      1
      php artisan migrate --seed

       to create the database tables and seed the roles and users tables

    Set up phpGrid

    We will use a datagrid component by phpGrid to handle all internal database CRUD (Create, Remove, Update, and Delete) operations.

    Be sure to download a copy of phpGrid before you proceed.

    To install phpGrid, follow these steps:

    1. Unzip the phpGrid download file.
    2. Upload the phpGrid folder to the phpGrid folder.
    3. Complete the installation by configuring the conf.php file.
    To set up conf.php, follow those manual installation steps.

    User Administration

    User administration is included as part of the improved inventory management system. The system includes features for creating and deleting user accounts, assigning and revoking user permissions, and managing user roles and groups.

    User Login

    If you are not logged in you can only access this page or the Sign Up page. The default url takes you to the login page where you use the default credentials admin@admin.com with the password secret. Logging in is possible only with already existing credentials. For this to work you should have run the migrations.

    Register

    You can register as a user by filling in the name, email, role and password for your account. For your role you can choose between the Admin, Creator and Member. It is important to know that an admin user has access to all the pages and actions, can delete, add and edit another users, other roles, items, tags or categories; a creator user has accces to category, tag and item management, but can not add, edit or delete other users; a member user has access to the item management but can not take any action.

    You can do this by accessing the sign up page from the “Sign Up” button in the top navbar or by clicking the “Sign Up” button from the bottom of the log in form. Another simple way is adding /register in the url.

    Forgot Password

    If a user forgets the account’s password it is possible to reset the password. For this the user should click on the “here” under the login form or add /login/forgot-password in the url.

    User Profile

    The profile can be accessed by a logged in user by clicking “User Profile” from the sidebar or adding /user-profile in the url. The user can add information like birthday, gender, phone number, location, language or skills.

    User Management

    This module allows administrators to manage user accounts and access permissions for a particular application or system. In addition to managing user accounts, user management can also be used to manage customer accounts, partners, and other types of users who need access to a particular application or system.

    Dashboard

    What is an inventory system good for without some of type of report? In this section, you will learn how to use phpChart – which seamlessly integrates with phpGrid – to create visually pleasing and useful reports for your Inventory Manager application.

    Here’s what our dashboard:

    Quick Stats

    Admin

    Instead of manually update supplier and category information in database directly in the past, the improved admin page added both Supplier Management and Category Management. More management admin can be added and customized in this section.

    Supplier Management

    Category Management

    Inventory Administration

    Products

    Purchases

    Current Orders

    Barcodes

    This module is part of phpGrid Ultimate and also available for a separate purchase.
    X

    In conclusion, an inventory management system with Laravel and Bootstrap is a powerful tool for businesses that want to streamline their inventory management processes, improve accuracy, and reduce costs associated with inventory management. It can be a customizable solution that can be tailored to meet the specific needs of your business.

    Launch Demo

    The post Laravel 10 & Bootstrap 5 Inventory Management with Dashboard, User Management appeared first on phpGrid - PHP Datagrid.

    ]]> 10078 Create the Perfect Employee Timesheet System in PHP and MySQL https://phpgrid.com/example/create-the-perfect-employee-timesheet-system-in-php-and-mysql/ Mon, 11 Apr 2022 22:59:14 +0000 https://phpgrid.com/?p=9941

    With the Employee Timesheet application, employees can log in to add their hours for the day and view past time-sheets. A supervisor can manage his employees, projects, activities, and cost centers. An employee can have either an employee or a supervisory role. This project is another great example of combining roles with an online database […]

    The post Create the Perfect Employee Timesheet System in PHP and MySQL appeared first on phpGrid - PHP Datagrid.

    ]]>

    With the Employee Timesheet application, employees can log in to add their hours for the day and view past time-sheets. A supervisor can manage his employees, projects, activities, and cost centers. An employee can have either an employee or a supervisory role.

    This project is another great example of combining roles with an online database to make a really functional app. It could be extended to track any additional information you would want to record.

    System Requirements

    The Employee Timesheet application requires the standard commercial phpGrid license as it needs several key features such as the latest time-only picker and group summary.

    • PHP 5.6+
    • MySQL / MariaDB
    • phpGrid

    The Components of the Employee Timesheet System

    An employee timesheet system has several components. The primary component is obviously the Timesheet, but the system requires other entities to work together with it for companies, firms and agencies to effectively collect, manage, track and share records about Projects, Employees, Timesheets, Activities and Cost Centers.

    • Timesheet
    • Employees
    • Projects
    • Activities
    • Cost Center

    Database Diagram

    Typically, a timesheet system has four basic elements — cost center, project, activity, and lastly, the timesheet for time entry. Most employees will only have permission to access their own time entries, but managers/supervisors have access to all aspects of the timesheet database including the cost center and projects.

    Setting up the Database

    Download the employee-timesheet.sql SQL script from this tutorial’s GitHub repo, and then execute the script using a MySQL tool such as MySQL Workbench. The .sql files are in the db folder. This will create a new database named employee-timesheet as well as the tables needed for this tutorial.

    Set up phpGrid

    We will use a datagrid component by phpGrid to handle all internal database CRUD (Create, Remove, Update, and Delete) operations.

    Be sure to obtain a copy of phpGrid before you proceed (the free version can work but the timepicker and grouping features required for this application are only available in the paid version).

    To install phpGrid, follow these steps:

    1. Unzip the phpGrid download file.
    2. Upload the phpGrid folder to the phpGrid folder.
    3. Complete the installation by configuring the conf.php file.

    Before we begin coding, we must include the following information in conf.php, the phpGrid configuration file.

    1
    2
    3
    4
    5
    6
    define('PHPGRID_DB_HOSTNAME', 'localhost'); // host name
    define('PHPGRID_DB_USERNAME', 'root'); // database user name
    define('PHPGRID_DB_PASSWORD', ''); // database password
    define('PHPGRID_DB_NAME', 'employee-timesheet'); // our donation manager database name
    define('PHPGRID_DB_TYPE', 'mysql'); // database type
    define('PHPGRID_DB_CHARSET','utf8'); // always 'utf8' in MySQL

     

    Creating UI

    The Timesheet application has only two pages:

    The supervisor page will also have access to other database tables via tabs. We will discuss those later in the tutorial.

    Dashboards

    Timesheet Dashboard (Employee)

    Let’s start with the timesheet dashboard page for the employee.

    The page is composed of one datagrid populated with data sourced from the  timesheet table.

    If you have read the tutorial Building a Donation Manager from Scratch, or the Inventory Management Application tutorial, you will have no problem following the code below.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $dg = new C_DataGrid("SELECT * FROM timesheet", "id", "timesheet");
    $dg -> set_query_filter("employee_id = '1'");

    $dg -> set_col_hidden('id, employee_id', false);

    $dg -> set_col_edittype("activity_id", "select", "Select id, code from activity")->set_col_title('activity_id', 'Activity');

    $dg -> set_col_time("time_from")->set_col_property("time_from",
    array("formatter"=>"date", "formatoptions"=>array("srcformat"=>"h:i A","newformat"=>"h:i A")));
    $dg -> set_col_time("time_to")->set_col_property("time_to",
    array("formatter"=>"date", "formatoptions"=>array("srcformat"=>"h:i A","newformat"=>"h:i A")));

    $dg -> enable_edit('FORM')->enable_autowidth(true);

    $dg -> display();

     

    Let’s break our code down for a quick review.

    The first line has a simple SQL Select statement that uses the database table timesheet as the datasource that will populate the datagrid in the dashboard.

    Here we used set_query_filter() and hard coded the employee id for demo purposes only. In a real-world application, you would replace it with a user id which was authenticated through a login.

    We hid certain fields from our grid id, and employee_id with set_col_hidden().

    We made the activity field a dropdown by setting the type to select in set_col_edittype() so it could be used as a look up for Activity table.

    Finally, note the use of the set_col_time() function used to enable our time-picker, followed by the formatter function so that the time is set to the right value during edit. The fields must be the TIME type in MySQL.

    That’s it for the employee timesheet dashboard. Here’s what it looks like:

    Timesheet Dashboard (Supervisor )

    The supervisor dashboard is just slightly more complex than the employee dashboard. For this page, we will use a technique called tabbed grids from phpGrid to display a datagrid populated with data sourced from other database tables — all without refreshing the page.

    The complete code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    $dg = new C_DataGrid("SELECT id, employee_id, date,
    time_from, time_to, ROUND(TIMESTAMPDIFF(MINUTE, time_from, time_to)/60, 2) as hours,
    comments, activity_id, date_submitted
    FROM timesheet"
    , "id", "timesheet");

    $dg -> set_col_hidden('id', false);

    // hide aggregate field hours from the edit form
    $dg->set_col_property('hours', array('editable'=>false,'hidedlg'=>true));

    $dg -> set_col_edittype("employee_id", "select", "Select id, last_name from account")->set_col_title('employee_id', 'Employee');
    $dg -> set_col_edittype("activity_id", "select", "Select id, code from activity")->set_col_title('activity_id', 'Activity');

    $dg -> set_col_time("time_from")->set_col_property("time_from",
    array("formatter"=>"date", "formatoptions"=>array("srcformat"=>"h:i A","newformat"=>"h:i A")));
    $dg -> set_col_time("time_to")->set_col_property("time_to",
    array("formatter"=>"date", "formatoptions"=>array("srcformat"=>"h:i A","newformat"=>"h:i A")));

    $dg -> enable_edit('FORM')->enable_autowidth(true);

    $dg -> set_group_properties('employee_id', false, true, true, false)->set_group_summary('hours', 'sum');

    $dg -> display(false);
    $grid = $dg -> get_display(false);

    $dg -> display_script_includeonce();

    Now, let’s dissect the code.

    The first line uses an SQL statement with a generated column named hours which is used to compute the time difference between time_from and time_to. We will need this value later to sum the total hours once they have been grouped by employee.

    1
    ROUND(TIMESTAMPDIFF(MINUTE, time_from, time_to)/60, 2) as hours

    Because hours is a generated column, we must hide it from the edit form.

    1
    $dg->set_col_property('hours', array('editable'=>false,'hidedlg'=>true));

    We group the timesheet by the employee and summarize the total number of hours he/she worked.

    1
    $dg->set_group_properties('employee_id', false, true, true, false)->set_group_summary('hours', 'sum');

    Lastly, we don’t render the datagrid right away. Instead, we set the display to false and render the datagrid with the tabbed grid loader using the aforementioned tabs. The beauty of using a tab is that we don’t need to write datagrid code for each of the five tables used in our application — all we need to do is to simply replace the table name.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <div id="tabs">
    <div id="tabs-1" style="padding:0">
    <?php
    echo $grid;
    ?>
    </div>
    <ul>
    <li><a href="#tabs-1">Timesheets</a></li>
    <li><a href="tabbed_grid_loader.php?gn=account">Employees</a></li>
    <li><a href="tabbed_grid_loader.php?gn=activity">Activities</a></li>
    <li><a href="tabbed_grid_loader.php?gn=cost_center">Cost Center</a></li>
    <li><a href="tabbed_grid_loader.php?gn=project">Projects</a></li>
    <li style="background:transparent;border:0;"><a onclick="location.href='https://getzenbase.com'" href="https://getzenbase.com" target="_new" style="padding:0;padding-left: 10px;" rel="noopener"><img src="assets/images/zenbase-logo.png" width="85"></a></li>
    </ul>
    </div>

    Here’s a screenshot of our Supervisor Dashboard. Notice the hours group summary by the employee and the bottom tabs to other tables.

    Summary

    This tutorial builds a simple and extendable timesheet system using a minimal amount of code thanks to the phpGrid component which handles the bulk of the CRUD plumbing.

    Now, there you have it. Your just built your employee timesheet application from scratch using only PHP and MySQL!

    Timesheet Demo

    The post Create the Perfect Employee Timesheet System in PHP and MySQL appeared first on phpGrid - PHP Datagrid.

    ]]>
    9941
    Clone CoinMarketCap.com Cryptocurrency Price Table with WebSockets https://phpgrid.com/example/clone-coinmarketcap-com-cryptocurrency-price-table-with-websockets/ Wed, 26 Jan 2022 18:50:27 +0000 https://phpgrid.com/?p=9876

    Coinmarketcap.com is without a doubt the most popular cryptocurrency price tracking website. I’ve often wondered if its elegant bitcoin prices table could be reproduced with phpGrid. That is exactly what we are about to do today! The table includes crypto pricing statistics as well as sparkline chart based on real-time data from the backend server. […]

    The post Clone CoinMarketCap.com Cryptocurrency Price Table with WebSockets appeared first on phpGrid - PHP Datagrid.

    ]]>

    Coinmarketcap.com is without a doubt the most popular cryptocurrency price tracking website. I’ve often wondered if its elegant bitcoin prices table could be reproduced with phpGrid. That is exactly what we are about to do today!

    The table includes crypto pricing statistics as well as sparkline chart based on real-time data from the backend server. It’s a proof of concept to show how far phpGrid can be pushed before I have to resort to other tools and frameworks.

    Setup

    Acquire the full version of phpGrid. The free Lite version is not compatible with this tutorial.

    Follow these steps to install:

    1. Extract download file,
    2. Upload the phpGrid folder to web server,
    3. Complete the installation by configuring conf.php file.

    For demo purpose, conf.php, set all database values to blank since our project doesn’t require a database.

    1
    2
    3
    4
    5
    6
    7
    // set all to blank
    define(‘PHPGRID_DB_HOSTNAME’, ‘’);
    define(‘PHPGRID_DB_USERNAME’, ‘’);
    define(‘PHPGRID_DB_PASSWORD’, ‘’);
    define(‘PHPGRID_DB_NAME’, ‘’);
    define(‘PHPGRID_DB_TYPE’, ‘’);
    define(‘PHPGRID_DB_CHARSET’,’’);

    Sample JSON

    The first step is to obtain a crypto data feed. Though it may be automatically retrieved from places like Binance or FTX.US, I decided to start with a local JSON data source for simplicity’s sake.

    JSON sample

    We’ll use this top 10 crypto sample to populate our CoinMarketCap clone.

    Index.php

    Let’s create index.php with the following:

    1
    2
    3
    4
    5
    6
    7
    require_once("phpGrid/conf.php");

    $url = "data/coinmarket_top10.json";
    $data = file_get_contents($url);
    $json_output = json_decode($data, true);
    $dg = new C_DataGrid($json_output, "id", "CoinMarket");
    $dg -> display();

    $json_output is the sample JSON data source save in data folder. It is passed to C_DataGrid as the first parameter. It should display a very rudimentary grid similar to the following.

     

    JSON as data source is covered in this tutorial.

    I’ll confess, this is still a long way from what I’d like to accomplish. Let’s make some changes to the user interface.

    Update User Interface

    First by adding descriptive column title,

    1
    2
    3
    4
    5
    6
    $dg->set_col_title(<strong>Percentage24H</strong>, ‘24h %);
    $dg->set_col_title(<strong>Percentage7D</strong>, ‘7d %);
    $dg->set_col_title(<strong>MarketCap</strong>, ‘Market Cap’);
    $dg->set_col_title(<strong>Volume24H</strong>, ‘Volume(24h));
    $dg->set_col_title(<strong>CirculatingSupply</strong>, ‘Circulating Supply’);
    $dg->set_col_title(<strong>Last7Days</strong>, ‘Last 7 Days’);

    Hide non-display columns,

    1
    2
    $dg->set_col_hidden("Coin”);
    $dg->set_col_hidden("
    MaxSupply”);

    Fix text alignment,

    1
    2
    3
    4
    5
    6
    $dg->set_col_align(‘Price’, ‘right’);
    $dg->set_col_align(‘Percentage24H’, ‘right’);
    $dg->set_col_align(‘Percentage7D’, ‘right’);
    $dg->set_col_align(‘MarketCap’, ‘right’);
    $dg->set_col_align(‘Volume24H’, ‘right’);
    $dg->set_col_align(‘CirculatingSupply’, ‘right’);

    Update money format

    1
    2
    3
    4
    $dg->set_col_currency('Price', '$');
    $dg->set_col_currency('MarketCap', '$');
    $dg->set_col_currency('Volume24H', '$');
    $dg->set_col_currency('CirculatingSupply', '');

    Add row color and hover effect

    1
    $dg -> set_row_color(‘white’, ‘white’, ‘white’);

    Fix column sort

    1
    2
    3
    4
    $dg->set_col_property("Price”, array("sorttype”=>"currency"));
    $dg->set_col_property("MarketCap”, array("sorttype”=>"currency"));
    $dg->set_col_property("Volume24H”, array("sorttype”=>"currency"));
    $dg->set_col_property("CirculatingSupply”, array("sorttype”=>"integer"));

    Add responsive width to screen size

    1
    $dg-> enable_autowidth(true);

    Finally some misc. style tweaks

    1
    2
    3
    $dg->set_caption(false);
    $dg->set_col_property(‘Coin’, array(‘classes’=>‘coin’));
    $dg->set_col_property(‘Name’, array(‘classes’=>‘name’));

    Already look better! But it’s still not quite what I was looking for.

    Adding Cascading Style Sheets (app.css)

    I use a Chrome extension “What Font” to find out the font it used on CoinMarketCap. It is a free font from Google Fonts called “Inter”. Here are the embed links:

    1
    2
    3
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600&amp;display=swap" rel="stylesheet">

    Then I made a few adjustments with some additional custom styles so I could “perfectly” match the look (almost)

    It looked better but still with a few issues:

    1. Missing the coin icons and tick symbols
    2. The prices are static and do not updates automatically like CMC does.

    Let’s fix those.

    Icons and Tickers

    CoinMarketCap has the format: Icon Name Ticker as illustrated below.

     

    I found a free library of all the major crypto icons on http://cryptoicons.co/ and downloaded them to “images/icons” folder.

    Next, we need to use phpGrid custom formatter.

    phpGrid Custom formatter

    This is section is the most crucial. It’s what really makes our cloned table “shine”. Custom formatter in phpGrid is a super powerful and versatile function for manipulating, modifying, or even adding additional information in a single column in grid. You can learn more about it on custom formatter online documentation.

    I’m adding custom formatter to the followings:

    • Name (with icon & ticker)
    • Price
    • 24h change (%)
    • 7day change (%)
    • Volume with dollar amount
    • Circulating supply with % bar

    PHP

    1
    2
    3
    4
    5
    $dg->set_col_property('Name', array('formatter'=>'###nameFormatter###')); // must have ###
    $dg->set_col_property('Volume24H', array('formatter'=>'###volumeFormatter###')); // must have ###
    $dg->set_col_property('CirculatingSupply', array('formatter'=>'###circulatingSupplyFormatter###')); // must have ###
    $dg->set_col_property('Percentage24H', array('formatter'=>'###percentageChangeFormatter###')); // must have ###
    $dg->set_col_property('Percentage7D', array('formatter'=>'###percentageChangeFormatter###')); // must have ###

    Javascript (app.js)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function percentageChangeFormatter (cellValue, options, rowData) {
     if (cellValue==0) return 'N/A';

      return (cellValue.indexOf('-') >= 0) ? `<span style="color:red">${cellValue}</span&>`: `<span style="color:green">${cellValue}</span>`;
    }

    function volumeFormatter (cellValue, options, rowData){
      if (cellValue==0) return 'N/A';

      let volume24hTotalCoin = parseInt(rowData['Volume24H']/rowData['Price']);

      return `${rowData['Volume24H'].toLocaleString(undefined,{})} <span class="volume24hTotalCoin">${volume24hTotalCoin.toLocaleString(undefined,{})} ${rowData['Coin']}</span>`;
      }

    function circulatingSupplyFormatter (cellValue, options, rowData){
      if (cellValue==0) return 'N/A';

      let volume24hTotalCoin = parseInt(rowData['Volume24H']/rowData['Price']);

      if (!!rowData['MaxSupply']) {
        const percentageOfMaxSupply = parseInt((cellValue/rowData['MaxSupply']) * 100);
        return `<span class="circulating-supply"${cellValue.toLocaleString(undefined ${rowData['Coin']}</span>` + `<div width="160" class="maxsupply-bar" title="Percentage: ${percentageOfMaxSupply}% of Max Supply of ${rowData['MaxSupply']}"><div style="width:${percentageOfMaxSupply}px" class="percentage-of-maxsupply"></div></div>`;
      }
      return `${cellValue.toLocaleString(undefined,{})}`;
    }

    It looks pretty good!

    Real-Time Data via Binance WebSocket

    Last but not least, the data must be updated in real-time, similar to CoinMarketCap or CoinGecko, without requiring the entire page to be refreshed. For this experiment, I want the price to tick in the same way as CMC does.

    WebSocket is supported by all major web browsers, with the exception of Opera Mini, according to caniuse.com. I was concerned that it would be a huge undertaking. As a result, I pushed this to the bottom of my to-do list. Fortunately, this was not the case. Binance’s websocket trade stream API made it simple.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // real time data via Websocket
    $(document).ready(function(){
      let coins = ['BTC', 'ETH', 'BNB', 'USDT', 'SOL', 'ADA', 'XRP', 'DOT', 'USDC', 'DOGE'];
      coins.forEach(function(coin){
        var wss = new WebSocket(`wss://stream.binance.com:9443/ws/${coin.toLowerCase()}usdt@trade`);
        wss.onmessage = function (event) {
          var messageObject = JSON.parse(event.data)
          $("#CoinMarket").jqGrid("setCell", coin, "Price" ,(messageObject.p));
        }
       })
    })

    From its API, there are tons of great data can be consumed. For our purpose, we will only need messageObject.p, which returns ‘Order Price’.

    Bonus: Adding Sparkline Chart of “last 7 days”

    On the coin market cap, todays’ cryptocurrency price table also features a lovely “mini” line chart for column “last 7 days”. The name for the type of chart is “sparkline”, and it is typically drawn without axes or coordinates. I wonder if it’s possible to include that.

    It turns out jQuery already has a Sparkline plugin. It takes a simple array of numbers. For example:

    1
    "Last7Days”: "[64125.80, 64398.60, 64134.50, 64806.70, 64932.60, 66904.40, 67527.90]”

    call to the sparkline() function to display the sparkline

    1
    $('.sparklines').sparkline('html', { enableTagOptions: true, fillColor:false, lineWidth:2, width:'100%', height:'50px' });

    remember include Sparkline plugin before </body>

    1
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-sparklines/2.1.2/jquery.sparkline.min.js" type="text/javascript"></script>

    The Final Outcome of CoinMarketCap.com Clone

     

     

    Not too shabby!

    Summary

    Our little CMC cryptocurrency price chart looks darn good. Considering how little code it took. It uses custom formatter for most of the ‘fancy’ stuffs such as tickers and icons. WebSocket is definitely something very exciting to show live data stream.

    Potential Enhancements

    This is a fun experiment to really push the envelop with phpGrid beyond common use cases such as inventory management, CRM, timesheet applications.

    Some potential useful enhancements:

    • Interactive cryptocurrency market cap chart
    • Pick and choose cryptocurrencies for display
    • Filters
    • Search
    • Database to store price history

    The post Clone CoinMarketCap.com Cryptocurrency Price Table with WebSockets appeared first on phpGrid - PHP Datagrid.

    ]]>
    9876
    Creating a Custom Inventory Management Application in PHP and MySQL https://phpgrid.com/example/creating-custom-inventory-management-application-php-mysql/ Sun, 17 Sep 2017 04:24:28 +0000 http://phpgrid.com/?p=9368 Introduction You do not need bloated enterprise software to effectively track your inventory. This tutorial will help you develop your own custom inventory tracking system so you can make smart inventory decisions based on timely and accurate inventory data. System Requirements Our Inventory System requires the standard commercial phpGrid and phpChart license as it needs […]

    The post Creating a Custom Inventory Management Application in PHP and MySQL appeared first on phpGrid - PHP Datagrid.

    ]]>
    Introduction

    You do not need bloated enterprise software to effectively track your inventory. This tutorial will help you develop your own custom inventory tracking system so you can make smart inventory decisions based on timely and accurate inventory data.

    System Requirements

    Our Inventory System requires the standard commercial phpGrid and phpChart license as it needs a few advanced features from both components.

    • PHP 7+
    • MySQL or MariaDB
    • phpGrid
    • phpChart (for reports)

    What is in an Inventory Management System

    An inventory management system has several critical components. At its core, inventory control works by tracking the two main functions of a warehouse — receiving (incoming) and shipping (outgoing). Other activities such as movement, or relocating, of inventory also take place. Raw materials are decremented and finished goods are incremented.

    • Incoming shipments
    • Outgoing orders
    • Inventory
    • Suppliers

    Inventory System Database Diagram

    Typically, an inventory system has four basic elements – products, purchases, orders, and suppliers – which must be tracked based on their location, SKU, and quantity. Current inventory, or products on hand, is updated by tracking incoming shipments and outgoing orders. Order alerts can be set to trigger when inventory levels fall below custom-defined minimum levels.

    Inventory Manager DB Schema

    Setting up the Inventory Manager Database

    Get the InventoryManager.sql SQL script in the end of this tutorial, and then execute the script using a MySQL tool such as MySQL Workbench. This will create a new database named InventoryManager as well as the tables needed for this tutorial.

    Set up phpGrid

    We will use phpGrid as our datagrid component to handle all internal database CRUD (Create, Remove, Update, and Delete) operations.

    Be sure to download a copy of phpGrid before you proceed.

    To install phpGrid, follow these steps:

    1. Unzip the phpGrid download file.
    2. Upload the phpGrid folder to the phpGrid folder.
    3. Complete the installation by configuring the conf.php file.

    Before we begin coding, we must include the following information in conf.php, the phpGrid configuration file.

    1
    2
    3
    4
    5
    6
    define('PHPGRID_DB_HOSTNAME', 'localhost'); //  host name
    define('PHPGRID_DB_USERNAME', 'root'); // database user name
    define('PHPGRID_DB_PASSWORD', ''); // database password
    define('PHPGRID_DB_NAME', 'InventoryManager'); // our donation manager database name
    define('PHPGRID_DB_TYPE', 'mysql'); // database type
    define('PHPGRID_DB_CHARSET','utf8'); // always 'utf8' in MySQL

    Creating the User Interface (UI)

    The application has four pages:

    • Current Inventory
    • Incoming Purchases
    • Orders to Ship
    • Reports

    Inventory UI

    The include file for the menu is stored in an inc folder named menu.php. The code for the menu is straightforward. For the sake of focus, we will not go into great detail. Feel free to look at the code inside the inc folder.

    We have also added a menu item named Reports.

    Menu

    Pages

    We will use the same page template we used for the CRM and Project Management tutorials.

    Current Inventory

    Let’s start with the Current Inventory page.

    Incoming purchases increase the inventory while outgoing orders decrease it. From a master-detail perspective, the Current Inventory has not one, but two detail datagrids – the Purchases (incoming purchases) and the Orders (outgoing orders).

    Therefore, the Current Inventory page is composed of one master grid – the Current Inventory in stock – and two detail grids – Incoming Purchases and Outgoing Orders. We can easily present these relationships using the phpGrid one master and multiple detail datagrids feature.

    If you have read the last tutorial Building a Donation Manager from Scratch, you will have no problem following the code below.

    Note the use of the set_col_format() function used to format the integers.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    $dgProd = new C_DataGrid('SELECT * FROM products', 'id', 'products');
    $dgProd->set_col_hidden('id', false);
    $dgProd->enable_autowidth(true)->set_dimension('auto', '200px')->set_pagesize(100);

    $dgProd->set_col_title('ProductName', 'Name');
    $dgProd->set_col_title('PartNumber', 'Part Number');
    $dgProd->set_col_title('ProductLabel', 'Label');
    $dgProd->set_col_title('StartingInventory', 'Starting Inventory');
    $dgProd->set_col_title('InventoryReceived', 'Inventory Received');
    $dgProd->set_col_title('InventoryShipped', 'Inventory Shipped');
    $dgProd->set_col_title('InventoryOnHand', 'Inventory On Hand');
    $dgProd->set_col_title('MinimumRequired', 'Minimum Required');

    $dgProd->set_col_format('StartingInventory', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->set_col_format('InventoryReceived', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->set_col_format('InventoryShipped', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->set_col_format('InventoryOnHand', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->set_col_format('MinimumRequired', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->enable_edit('FORM');

    That’s it for the Current Inventory datagrid. Here’s what it looks like so far:

    products

    Now, let’s make a few changes to enhance our Product datagrid.

    First of all, we will add some conditional formatting so that whenever the InventoryOnHand is set to zero or a negative value, it is displayed using a different background color. We will use the set_conditional_format() function for this purpose.

    1
    2
    3
    4
    5
     $dgProd->set_conditional_format(
        'InventoryOnHand', 'CELL',
            array("condition"=>"lt",
              "value"=>"1",
              "css"=> array("color"=>"red","background-color"=>"#DCDCDC")));

    The above code adds a display condition so that whenever the InventoryOnHand field has a value that is less than (lt) one, the text color changes to red and the background color to dark gray (#DCDCDC).

    Secondly, whenever the InventoryOnHand is less than the value shown in MinimumRequired, we would like to alert the user by displaying it in a prominent background color such as gold. To compare values between two fields, we must switch to Javascript because the set_conditional_format() function only works with a single field.

    The code below uses a for loop to iterate through each row in the Products datagrid. It compares the inventoryOnHand with theminimumRequired and, when condition is met, it will use thesetCell function to change the background color.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     $onGridLoadComplete = <<<ONGRIDLOADCOMPLETE
    function(status, rowid)
    {
        var ids = jQuery("#products").jqGrid('getDataIDs');
        for (var i = 0; i < ids.length; i++)
        {
            var rowId = ids[i];
            var rowData = jQuery('#products').jqGrid ('getRowData', rowId);

            var inventoryOnHand = $("#products").jqGrid("getCell", rowId, "InventoryOnHand");
            var minimumRequired = $("#products").jqGrid("getCell", rowId, "MinimumRequired");

            // compare two dates and set custom display in another field "status"
            console.log(inventoryOnHand + " | " + minimumRequired);
            if(parseInt(inventoryOnHand) < parseInt(minimumRequired)){

                $("#products").jqGrid("setCell", rowId, "PartNumber", '', {'background-color':'gold'});

            }
        }

    }
    ONGRIDLOADCOMPLETE
    ;
    $dgProd->add_event("jqGridLoadComplete", $onGridLoadComplete);

    You can learn more about comparing multiple cell values on the phpGrid support website,

    Next, on the same page, we need to see the purchases coming in (Incoming) and orders going out (Outgoing) for a specific product.

    Purchases Detail Grid (Incoming)

    1
    2
    3
    4
    5
    6
     // Purchases detail grid
    $dgPur = new C_DataGrid('SELECT id, PurchaseDate, ProductId, NumberReceived, SupplierId FROM purchases', 'id', 'purchases');
    $dgPur->set_col_hidden('id', false)->set_caption('Incoming Purchases');
    $dgPur->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
    $dgPur->set_col_edittype('SupplierId', 'select', "select id, supplier from suppliers");
    $dgPur->set_dimension('800px');

    Orders Detail Grid (Outgoing)

    1
    2
    3
    4
    5
    6
     // Orders detail grid
    $dgOrd = new C_DataGrid('SELECT id, OrderDate, ProductId, NumberShipped, First, Last FROM orders', 'id', 'orders');
    $dgOrd->set_sortname('OrderDate', 'DESC')->set_caption('Outgoing Orders');
    $dgOrd->set_col_hidden('id', false);
    $dgOrd->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
    $dgOrd->set_dimension('800px');

    Both detail grids use the same foreign key ProductId to link to the master datagrid – Products.

    1
    2
     $dgProd->set_masterdetail($dgPur, 'ProductId', 'id');
    $dgProd->set_masterdetail($dgOrd, 'ProductId', 'id');

    Finally, our complete code to manage the Current Inventory page is:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
     $dgProd = new C_DataGrid('SELECT * FROM products', 'id', 'products');
    $dgProd->set_col_hidden('id', false);
    $dgProd->enable_autowidth(true)->set_dimension('auto', '200px')->set_pagesize(100);

    $dgProd->set_col_title('ProductName', 'Name');
    $dgProd->set_col_title('PartNumber', 'Part Number');
    $dgProd->set_col_title('ProductLabel', 'Label');
    $dgProd->set_col_title('StartingInventory', 'Starting Inventory');
    $dgProd->set_col_title('InventoryReceived', 'Inventory Received');
    $dgProd->set_col_title('InventoryShipped', 'Inventory Shipped');
    $dgProd->set_col_title('InventoryOnHand', 'Inventory On Hand');
    $dgProd->set_col_title('MinimumRequired', 'Minimum Required');

    $dgProd->set_col_format('StartingInventory', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->set_col_format('InventoryReceived', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->set_col_format('InventoryShipped', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->set_col_format('InventoryOnHand', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
    $dgProd->set_col_format('MinimumRequired', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));

    $dgProd->set_conditional_format('InventoryOnHand', 'CELL', array("condition"=>"lt",
                                                      "value"=>"1",
                                                      "css"=> array("color"=>"red","background-color"=>"#DCDCDC")));

    $onGridLoadComplete = <<<ONGRIDLOADCOMPLETE
    function(status, rowid)
    {
        var ids = jQuery("#products").jqGrid('getDataIDs');
        for (var i = 0; i < ids.length; i++)
        {
            var rowId = ids[i];
            var rowData = jQuery('#products').jqGrid ('getRowData', rowId);

            var inventoryOnHand = $("#products").jqGrid("getCell", rowId, "InventoryOnHand");
            var minimumRequired = $("#products").jqGrid("getCell", rowId, "MinimumRequired");

            // compare two dates and set custom display in another field "status"
            console.log(inventoryOnHand + " | " + minimumRequired);
            if(parseInt(inventoryOnHand) < parseInt(minimumRequired)){

                $("#products").jqGrid("setCell", rowId, "PartNumber", '', {'background-color':'gold'});

            }
        }

    }
    ONGRIDLOADCOMPLETE
    ;

    $dgProd->add_event("jqGridLoadComplete", $onGridLoadComplete);
    $dgProd->enable_edit('FORM');

    // Purchases detail grid
    $dgPur = new C_DataGrid('SELECT id, PurchaseDate, ProductId, NumberReceived, SupplierId FROM purchases', 'id', 'purchases');
    $dgPur->set_col_hidden('id', false)->set_caption('Incoming Purchases');
    $dgPur->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
    $dgPur->set_col_edittype('SupplierId', 'select', "select id, supplier from suppliers");
    $dgPur->set_dimension('800px');

    // Orders detail grid
    $dgOrd = new C_DataGrid('SELECT id, OrderDate, ProductId, NumberShipped, First, Last FROM orders', 'id', 'orders');
    $dgOrd->set_sortname('OrderDate', 'DESC')->set_caption('Outgoing Orders');
    $dgOrd->set_col_hidden('id', false);
    $dgOrd->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
    $dgOrd->set_dimension('800px');

    $dgProd->set_masterdetail($dgPur, 'ProductId', 'id');
    $dgProd->set_masterdetail($dgOrd, 'ProductId', 'id');
    $dgProd->display();

    Here’s the a snapshot of the inventory page:

    Current inventory

    Incoming Purchases

    The next page is the Incoming Purchase page. It is similar to the Purchase Detail Grid we saw when setting up the Current Inventory page. We group the purchases by ProductId and display the sum inNumberReceived. Any incoming purchases will increase the inventory.

    1
    2
     $dgPur -> set_group_properties('ProductId', false, true, true, false);
    $dgPur -> set_group_summary('NumberReceived','sum');

    The complete code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     $dgPur = new C_DataGrid('SELECT id, PurchaseDate, ProductId, NumberReceived, SupplierId FROM purchases', 'id', 'purchases');
    $dgPur->set_col_hidden('id', false);

    $dgPur->set_col_title('PurchaseDate', 'Date of Purchase');
    $dgPur->set_col_title('ProductId', 'Product');
    $dgPur->set_col_title('NumberReceived', 'Number Received');
    $dgPur->set_col_title('SupplierId', 'Supplier');

    $dgPur->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
    $dgPur->set_col_edittype('SupplierId', 'select', "select id, supplier from suppliers");

    // $dgPur->enable_edit('FORM');
    $dgPur->set_pagesize(100);

    $dgPur->set_col_width('PurchaseDate', '50px');
    $dgPur->set_col_width('NumberReceived', '35px');

    $dgPur -> set_group_properties('ProductId', false, true, true, false);
    $dgPur -> set_group_summary('NumberReceived','sum');

    $dgPur->enable_autowidth(true);
    $dgPur->display();

    Here’s a screenshot of our Incoming Purchases page with grouping enabled:

    Incoming purchases

    Outgoing Orders

    The next page is the Outgoing Orders page. It is similar to the Orders Detail Grid from the Current Inventory page. Here, we will introduce an advanced function called set_grid_method().

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     $dgOrd = new C_DataGrid('SELECT id, OrderDate, ProductId, NumberShipped, First, Last FROM orders', 'id', 'orders');
    $dgOrd->set_sortname('OrderDate', 'DESC');
    $dgOrd->set_col_hidden('id', false);

    $dgOrd->set_col_title('OrderDate', 'Order Date');
    $dgOrd->set_col_title('ProductId', 'Product');
    $dgOrd->set_col_title('NumberShipped', 'Number Shipped');

    $dgOrd->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");

    // $dgOrd->enable_edit('FORM');
    $dgOrd->set_pagesize(100);

    $dgOrd->set_col_width('OrderDate', '30px');
    $dgOrd->set_col_width('NumberShipped', '35px');
    $dgOrd->set_col_width('First', '20px');
    $dgOrd->set_col_width('Last', '20px');

    $dgOrd->set_grid_method('setGroupHeaders', array(
                                    array('useColSpanStyle'=>true),
                                    'groupHeaders'=>array(
                                            array('startColumnName'=>'First',
                                                  'numberOfColumns'=>2,
                                                  'titleText'=>'Customer Name') )));

    $dgOrd->enable_autowidth(true);
    $dgOrd->display();

    Summary

    This tutorial builds a simple and extendable inventory system in less than 50 lines of code. The progressive style of these tutorials also helps the reader to ultimately become more familar and comfortable with phpGrid by introducing a limited number of new phpGrid features in each one.

    What’s Coming Up

    This marks the end of the code needed to create the datagrids required for this tutorial. However, we are not done yet. There is still one more page we need to create — Reports. We will cover that after the jump.


    Reports

    What is an inventory system good for without some of type of report? In this section, you will learn how to use phpChart – which seamlessly integrates with phpGrid – to create visually pleasing and useful reports for your Inventory Manager application.

    Here’s what our page will look like when it’s done:

    inventory reports

    Before we start, we need to install phpChart. It is recommended that you obtain the full version of phpChart since the free version – phpChart Lite – supports only the line chart.

    Setup phpChart

    It’s important that we keep phpGrid and phpChart in separate folders. Below is the recommended folder hierarchy.

    1
    2
    3
    4
    5
    6
    7
    www
    +-- Donation_Manager
    |   |-- phpGrid
    |   |   +-- conf.php
    |   |-- phpChart
    |   |   +-- conf.php
    |   +-- ...

    Report Design

    We will place a pie chart next to an inventory summary grid. The datagrid provides the series data to plot the pie chart.

    Reports UI

    phpGrid and phpChart Integration

    First of all, include calls to both conf.php files at the beginning of the code.

    1
    2
    require_once("phpGrid/conf.php");
    require_once("phpChart/conf.php");

    Pie Chart

    Below is the complete code to create our pie chart:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     $pc = new C_PhpChartX(array(array(null)), 'PieChart');
    $pc->set_title(array('text'=>'Current Inventory Summary'));
    $pc->set_series_default(array( 'shadow'=> false,
        'renderer'=> 'plugin::PieRenderer',
        'rendererOptions'=> array(
          'showDataLabels' => true,
          'highlightMouseOver' => true,
          'startAngle'=> 180,
          'sliceMargin'=> 4,
          'showDataLabels'=> true )
      ));
    $pc->set_legend(array('show'=>true,'location'=> 'w'));
    // remove background
    $pc->set_grid(array(
        'background'=>'white',
        'borderWidth'=>0,
        'borderColor'=>'#000000',
        'shadow'=>false));
    $pc->add_custom_js("
            $('#PieChart').bind('jqplotDataHighlight',
                function (ev, seriesIndex, pointIndex, data) {
                   $('#label_info').text(data);      
                }
            );
        "
    );
    $pc->draw(660,400);

    Let’s walk through the code.

    The first line is the constructor. We pass array(null) as the series data because we don’t wish to have any data displayed in the pie chart initially as the inventory data used to plot the chart is not yet available when it is first initialized. The data is fed from the datagrid later in JSON.

    We also give our chart a unique name, PieChart.

    1
     $pc = new C_PhpChartX(array(array(null)), 'PieChart');

    Next, we give it a title. Nothing fancy here.

    1
     $pc->set_title(array('text'=>'Current Inventory Summary'));

    Once we have the title, we call the series default function to set the renderer to PieRenderer. Unlike a bar chart, a pie chart does not have a Y axis.

    We can also set the rendererOptions property. We will not go into each option in detail here, but you can find more information in the online documentation.

    1
    2
    3
    4
    5
    6
    7
    8
     $pc->set_series_default(array( 'shadow'=> false,
        'renderer'=> 'plugin::PieRenderer',
        'rendererOptions'=> array(
          'highlightMouseOver' => true,
          'startAngle'=> 180,
          'sliceMargin'=> 4,
          'showDataLabels'=> true )
      ));

    We also want to show a legend. The set_legend command below shows the legend to the west (noted byw) or to the left of the pie chart.

    1
     $pc->set_legend(array('show'=>true,'location'=> 'w'));

    We will also remove the border and the background.

    1
    2
    3
    4
    5
     $pc->set_grid(array(
        'background'=>'white',
        'borderWidth'=>0,
        'borderColor'=>'#000000',
        'shadow'=>false));

    Finally, we draw our chart by giving it a height and width in pixels.

    1
     $pc->draw(660,400);

    However, if you execute the code now, you will not see the chart because the data used to render it isn’t available yet.

    Inventory Summary Datagrid

    Here, we will use the same the inventory datagrid as we did in the Products page. We just need to add one more thing – an event handler.

    In phpGrid, we can add an event handler with the [add_event()] (https://phpgrid.com/documentation/add_event/) function. add_event() binds an event handler, which is essentially a JavaScript function, to a specific phpGrid event. A list of possible events can be found here.

    Since we must wait for the datagrid to finish loading before it can send the data to plot the chart, we use the event jqGridLoadComplete.

    phpGrid 101 – jqGridLoadComplete Event

    jqGridLoadComplete is last event that occurs once the whole datagrid body has finished loading. Note that the grid body will be reloaded if the user changes the sort order of a column or sets a filter.

    Send Data Using Javascript

    The following is the Javascript event handler for jqGridLoadComplete.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     <span class="hljs-function">function(status, rowid)
    {</span>
        var dataX = [];
        var dataY = [];

        d1 = $('#products').jqGrid('getCol', 'ProductLabel', false);
        d2 = $('#products').jqGrid('getCol', 'InventoryReceived', false);

        npoints = d1.length;
        for(var i=0; i < npoints; i++){
            dataX[i] = [i+1, d1[i]];
            dataY[i] = [i+1, parseInt(d2[i])];
        }

        var pieData = [];
        for(var j=0; j < dataX.length; j++)
        {
            pieData.push([dataX[j][1], dataY[j][1]]);
        }
        console.log(pieData);
        _PieChart.series[0].data = pieData;
        _PieChart.replot({resetAxes:true});
    }

    The complete code:


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     $dgProd = new C_DataGrid('SELECT id, ProductLabel, InventoryReceived FROM products', 'id', 'products');
    $dgProd->set_col_hidden('id', false);
    $dgProd->set_dimension('auto', 'auto')->set_pagesize(100);
    $onGridLoadComplete = <<<ONGRIDLOADCOMPLETE
    function(status, rowid)
    {
        var dataX = [];
        var dataY = [];

        d1 = $('#products').jqGrid('getCol', 'ProductLabel', false);
        d2 = $('#products').jqGrid('getCol', 'InventoryReceived', false);
        d3 = $('#products').jqGrid('getCol', 'InventoryShipped', false);
        d4 = $('#products').jqGrid('getCol', 'InventoryOnHand', false);


        npoints = d1.length;
        for(var i=0; i < npoints; i++){
            dataX[i] = [i+1, d1[i]];
            dataY[i] = [i+1, parseInt(d2[i])];
        }

        var pieData = [];
        for(var j=0; j < dataX.length; j++)
        {
            pieData.push([dataX[j][1], dataY[j][1]]);
        }
        console.log(pieData);
        _PieChart.series[0].data = pieData;
        _PieChart.replot({resetAxes:true});
    }
    ONGRIDLOADCOMPLETE
    ;
    $dgProd->add_event("jqGridLoadComplete", $onGridLoadComplete);
    $dgProd->display();

    Now there you have it. Your just built your very first inventory management system from scratch using only PHP and MySQL!

    Live Demo!

    Get this App *

    * Included in Ultimate edition.

    The post Creating a Custom Inventory Management Application in PHP and MySQL appeared first on phpGrid - PHP Datagrid.

    ]]>
    9368
    A Step-by-Step Guide to Building a Donation Manager from Scratch in PHP – Part II https://phpgrid.com/example/step-step-guide-building-donation-manager-scratch-php-part-ii/ Mon, 31 Jul 2017 08:12:44 +0000 http://phpgrid.com/?p=9347

    In this part of the tutorial, we will continue from where we left off in Build a Donation Manager Part I. You will learn how to use phpChart, an easy-to-use charting and graphing component, that will seamlessly integrates with phpGrid to create professional-looking, interactive reports for your Donation Manager application. Before we start, we need […]

    The post A Step-by-Step Guide to Building a Donation Manager from Scratch in PHP – Part II appeared first on phpGrid - PHP Datagrid.

    ]]>

    In this part of the tutorial, we will continue from where we left off in Build a Donation Manager Part I. You will learn how to use phpChart, an easy-to-use charting and graphing component, that will seamlessly integrates with phpGrid to create professional-looking, interactive reports for your Donation Manager application.

    Before we start, we need to install phpChart. To fully benefit from this tutorial, I recommend you obtain the full version of phpChart since the free version – phpChart Lite – supports only the line chart.

    Setup phpChart

    It is very important that phpGrid and phpChart be kept in its separate folders. Below is the recommended folder hierarchy.

    1
    2
    3
    4
    5
    6
    7
    www
    +-- Donation_Manager
    |   |-- phpGrid
    |   |   +-- conf.php
    |   |-- phpChart
    |   |   +-- conf.php
    |   +-- ...

    That’s it.

    Report Design

    Our report consists of a bar chart and a pie chart followed by a campaign summary datagrid. The datagrid provides the data used to plot the two charts.

    reports mockup

    phpGrid phpChart Integration

    First of all, include both conf.php files (phpGrid and phpChart) at the beginning of the code.

    1
    2
    require_once("phpGrid/conf.php");
    require_once("phpChart/conf.php");

    Bar Chart

    The first chart we will create is the bar chart. Below is the complete code to create an EMPTY bar chart. We first must create an empty chart is because the campaign data used to plot the chart is not available at the time when the chart is initialized.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    $pc = new C_PhpChartX(array(array(null)),'BarChart');
    $pc->add_plugins(array('canvasTextRenderer','canvasAxisTickRenderer', 'pointLabels'),true);
    $pc->set_animate(true);
    $pc->set_series_default(array(
            'renderer'=>'plugin::BarRenderer',
            'rendererOptions' => array('barWidth'=>60),
            'pointLabels'=> array('show'=>true)
            ));
    $pc->set_axes(array(
         'xaxis'=>array(
            'label'=>'Campaign',
            'renderer'=>'plugin::CategoryAxisRenderer',
            'rendererOptions'=>array('tickRenderer'=>'plugin::CanvasAxisTickRenderer'),
            'ticks'=>array(null),
            'tickOptions'=>array(
                    'angle'=>-35,
                    'fontStretch'=>1)),
        'yaxis'=>array('label'=>'Total Donations')
    ));
    $pc->draw(600,400);

    Let’s break this baby apart. For the sake of simplicity, we will only cover high level implementation and skip over details where the code is actually self-explanatory.

    The first line is the constructor. We pass an empty array, array(null), as the series data because we don’t wish to have any data displayed in the bar chart when it is first rendered. We also give our graph an unique name, BarGraph.

    1
    $pc = new C_PhpChartX(array(array(null)),'BarGraph');

    Next, we use the add_plugins() function to include some additional new elements to our bar chart. For this tutorial, we will include the canvasTextRenderer, canvasAxisTickRenderer, and pointLabels plugins. A list of supported plugins can be found here.

    1
    $pc->add_plugins(array('canvasTextRenderer','canvasAxisTickRenderer', 'pointLabels'),true);

    In the series default function, be sure to set the renderer type to BarRenderer. We can also set the rendererOptions and pointLabels properties here.

    1
    2
    3
    4
    5
    $pc->set_series_default(array(
                'renderer'=>'plugin::BarRenderer',
                'rendererOptions' => array('barWidth'=>60),
                'pointLabels'=> array('show'=>true)
                ));

    A bar chart has two sets of data – one set for the x axis and another for the y. In this example, the x axis shows the total amount donated to a given campaign and the y axis displays the name of the campaign. We can set the properties for both x and y in one statement by using the set_axes() function. Notice how label, renderer, and ticks properties are used.

    Complete documentation for phpChart methods and properties documentation can be found online.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $pc->set_axes(array(
         'xaxis'=>array(
            'label'=>'Campaign',
            'renderer'=>'plugin::CategoryAxisRenderer',
            'rendererOptions'=>array('tickRenderer'=>'plugin::CanvasAxisTickRenderer'),
            'ticks'=>array(null),
            'tickOptions'=>array(
                    'angle'=>-35,
                    'fontStretch'=>1)),
        'yaxis'=>array('label'=>'Total Donations')
    ));

    Finally, the last line reserves space for a chart that is 600px high and 400px wide.

    1
    $pc->draw(600,400);

    Pie Chart

    Now let’s move on to the second chart in our report. Below is the entire code to create an EMPTY pie chart.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $pc2 = new C_PhpChartX(array(array(null)),'PieChart');
    $pc2->set_series_default(array( 'shadow'=> false,
        'renderer'=> 'plugin::PieRenderer',
        'rendererOptions'=> array(
          'sliceMargin'=> 3,
          'showDataLabels'=> true )
      ));
    $pc2->set_legend(array('show'=>true,'location'=> 'w'));
    $pc2->draw(600,400);

    Let’s do a quick review of the above script.

    The first line is the phpChart constructor. Again, the first parameter is an empty array, array(null), as the series data will be loaded later from the Campaign Summary datagrid.

    1
    $pc2 = new C_PhpChartX(array(array(null)),'PieChart');

    We then set the renderer to PieRenderer and set the its properties using the series default function.

    1
    2
    3
    4
    5
    6
    $pc2->set_series_default(array( 'shadow'=> false,
        'renderer'=> 'plugin::PieRenderer',
        'rendererOptions'=> array(
          'sliceMargin'=> 3,
          'showDataLabels'=> true )
      ));

    We also want to display the legend to the west, or left, of the chart.

    1
    $pc2->set_legend(array('show'=>true,'location'=> 'w'));

    Lastly, we draws the pie chart.

    1
    $pc2->draw(600,400);

    You should now have two blank charts on the page.

    blank charts

    Campaign Summary Datagrid

    The Campaign datagrid used in this report is the same as what was used to create the Campaign page in Part 1. We just need to add one more thing – an event handler.

    In phpGrid, we can add an event handler with the add_event() function. add_event() binds an event handler, which is essentially a JavaScript function, for a specific phpGrid event. A list of possible events can be found here.

    Since we must wait for the datagrid to finish loading before sending its data needed to plot the charts, we use the event jqGridLoadComplete.

    phpGrid 101 – jqGridLoadComplete Event

    jqGridLoadComplete is the last event that occurs once the whole datagrid body has finished loading. Note that the grid body will be reloaded if the user changes the sorting of a column or sets a filter.

    Send Data Using Javascript

    The following is the Javascript event handler for jqGridLoadComplete.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function(status, rowid)
    {
        var barData1 = [];
        var barData2 = [];

        d1 = $('#campaigns').jqGrid('getCol', 'TotalDonation', false);
        d2 = $('#campaigns').jqGrid('getCol', 'CampaignName', false);

        npoints = d1.length;
        for(var i=0; i &lt; npoints; i++){
            barData1[i] = [i+1, parseInt(d1[i])];
            barData2[i] = [i+1, d2[i]];
        }
        _BarChart.series[0].data = barData1;
        _BarChart.axes.xaxis.ticks = barData2;
        _BarChart.replot({resetAxes:true});

        var pieData = [];
        for(var j=0; j &lt; barData1.length; j++)
        {
            pieData.push([barData2[j][1],barData1[j][1]]);
        }
        // console.log(pieData);
        _PieChart.series[0].data = pieData;
        _PieChart.replot({resetAxes:true});
       }

    The Javascript function is the bread and butter that makes our report come alive. It requires a certain level of knowledge of basic Javascript.

    Right off the bat, we declare two empty arrays to store x and y axis data points. Since we are now using JavaScript, the syntax will be different from that used in PHP.

    1
    2
    var barData1 = [];
    var barData2 = [];

    The following two lines return data from the datagrid column TotalDonation and CampaignName:

    1
    2
    d1 = $('#campaigns').jqGrid('getCol', 'TotalDonation', false);
    d2 = $('#campaigns').jqGrid('getCol', 'CampaignName', false);

    The for loop iterates each column and then stores the results in the x and y axis arrays.

    1
    2
    3
    4
    5
    npoints = d1.length;
    for(var i=0; i &lt; npoints; i++){
        barData1[i] = [i+1, parseInt(d1[i])];
        barData2[i] = [i+1, d2[i]];
    }

    Next, we assign the barData from the datagrid to the bar chart object. Lastly always call jqPlot replot function to load the chart.

    1
    2
    3
    _BarChart.series[0].data = barData1;
    _BarChart.axes.xaxis.ticks = barData2;
    _BarChart.replot({resetAxes:true});
    phpChart 101 – JavaScript Chart Object Name

    The JavaScript chart object name is the same as the name used in the phpChart constructor, e.g. BarChart, prefixed with the underscore character “_”.

    We have just completed our bar chart.

    Next, we move on to the pie chart. The JavaScript code for this is similar to what we used for the bar chart except that a pie chart does not have x and y axes. Instead, it uses a two-dimensional array.

    1
    pieData.push([barData2[j][1],barData1[j][1]]);

    bar chart & pie chart in donation manager

    That’s all there is to it!

    Conclusion

    Hopefully, after finishing this tutorial, you have become a true campaign master yourself – one who is capable of developing a fully functional donation manager system from start to finish.

    Run Demo Get this App *

    * Included in Ultimate edition.

    The post A Step-by-Step Guide to Building a Donation Manager from Scratch in PHP – Part II appeared first on phpGrid - PHP Datagrid.

    ]]>
    9347
    A Step-by-Step Guide to Building a Donation Manager from Scratch in PHP – Part I https://phpgrid.com/example/step-step-guide-building-donation-manager-scratch-php-part/ Mon, 03 Jul 2017 09:15:31 +0000 http://phpgrid.com/?p=9340

    Introduction This Donations Manager application can be used by charitable organizations to manage the processing of donations as well as ensure accurate data entry and seamless communications with donors. In addition, we will include a donation summary report with charts in our application. System Requirements PHP 5.3+ MySQL or MariaDB phpGrid phpChart Database Overview Our […]

    The post A Step-by-Step Guide to Building a Donation Manager from Scratch in PHP – Part I appeared first on phpGrid - PHP Datagrid.

    ]]>

    Introduction

    This Donations Manager application can be used by charitable organizations to manage the processing of donations as well as ensure accurate data entry and seamless communications with donors. In addition, we will include a donation summary report with charts in our application.

    System Requirements

    • PHP 5.3+
    • MySQL or MariaDB
    • phpGrid
    • phpChart

    Database Overview

    Our Donation Manager system has four objects.

    • Donor – Personal information about the donor.
    • Donation – The amount donated for a particular campaign
    • Campaign – Donation campaign information
    • Organization – The organization that manages the donations

    Our database is simple and straightforward. Each table is an entity that represents one of the above objects.

    Programming Terminology – Object or Entity

    An entity is a database term that’s typically represented by a table in a database schema.
    An object is an object-oriental programming term often mapped to a database table.

    In our data model, donations is used to store the information about donations; campaigns is used to compile campaign data and information about the campaign; the organization managing the campaign is stored in org.

    enter image description here

    Set up the Donation Manager Database

    Obtain the donation_manager_db.sql SQL script from this tutorial’s GitHub repo, and then execute the SQL script using a MySQL tool such as MySQL Workbench or Sequel Pro. This will create a new database named donation_manager and the tables we will need in this tutorial.

    Setup phpGrid

    Our simple project management application contains many datagrids. A datagrid is a spreadsheet-like data table that displays rows and columns which representing records and fields stored in the database table. These grids provide the end-user with the ability to read and write to the database tables from a web page.

    The phpGrid datagrid component handles all internal database CRUD (Create, Remove, Update, and Delete) operations for us, offering faster and better results with minimal coding.

    Be sure to download a free copy of phpGrid before you proceed.

    To install phpGrid, follow these steps:

    1. Unzip the phpGrid download file.
    2. Upload the phpGrid folder to the phpGrid folder.
    3. Complete the installation by configuring the conf.php file.

    Before we begin coding, we must include the following information in conf.php, the phpGrid configuration file.

    1
    2
    3
    4
    5
    6
    define('PHPGRID_DB_HOSTNAME', 'localhost'); //  host name
    define('PHPGRID_DB_USERNAME', 'root'); // database user name
    define('PHPGRID_DB_PASSWORD', ''); // database password
    define('PHPGRID_DB_NAME', 'donation_manager'); // our donation manager database name
    define('PHPGRID_DB_TYPE', 'mysql'); // database type
    define('PHPGRID_DB_CHARSET','utf8'); // always 'utf8' in MySQL

    UI Design

    The basic design is simple. It is composed of a single-level top menu bar and a datagrid. In the Reports section, we will add charts using the phpChart.

    mockup

    The Donations Manager has four menu items. Each item represents a corresponding table in the Donation Manager database.

    The include file for the menu is stored in the inc folder named menu.php. The code for the menu is straightforward. For the sake of focus, we will not go into great detail. Feel free to look at the content stored inside the inc folder.

    donation manager menu

    We have also added a menu item named Reports which we will address in Part II of this tutorial.

    Pages

    We will use the same page template we used for the CRM and Project Management tutorials.

    Donations

    Our first Donation Manager page is the Donations page on which we display donation information retrieved from the Donations table in a datagrid.

    Remember that each table in the Donation Manager database has the id as the primary key. So, we can easily create our first datagrid with the following two lines of code.

    1
    2
    $dgDonations = new C_DataGrid("SELECT * FROM donations", "id", "donations");
    $dgDonations -> display();
    phpGrid 101 – A Basic Datagrid

    A basic PHP datagrid requires only as little as TWO lines of code.

    1. On the first line, you create the phpGrid object to be displayed.
    2. Then you call display() to render the resulting datagrid on the webpage.

    You can learn more about how the basic datagrid works here.

    Here’s what our Donations datagrid looks like:

    Basic Donations datagrid

    Now, we will make a few enhancements to the Donations datagrid.

    First of all, we don’t need to show the Donations primary key id as it is only used internally and is meaningless to our users. We can hide it using set_col_hidden().

    1
    $dgDonations->set_col_hidden('id');

    Next, the Amount column is a currency value. We can format this column to be displayed as currency using set_col_currency().

    1
    $dgDonations->set_col_currency("Amount", "$");

    We also want our datagrid to display a human-readable Campaign description and Donor name instead of displaying meaningless integers in columns CampaignId and DonorId. We can easily obtain the campaign description and donor name from Campaigns and Donors table respectively using the set_col_edittype() function.

    1
    2
    $dgDonations->set_col_edittype('CampaignId', 'select', 'select id, CampaignName from campaigns');
    $dgDonations->set_col_edittype('DonorId', 'select', "select id, LastName from Donors")

    We also want to make the Donations grid editable. We can do this by adding the line:

    1
    $dgDonations->enable_edit();

    The complete code for the Donations datagrid:

    1
    2
    3
    4
    5
    6
    7
    $dgDonations = new C_DataGrid("SELECT * FROM donations", "id", "donations");
    $dgDonations->set_col_hidden('id');
    $dgDonations->set_col_edittype('CampaignId', 'select', 'select id, CampaignName from campaigns');
    $dgDonations->set_col_edittype('DonorId', 'select', "select id, LastName from Donors");
    $dgDonations->set_col_currency("Amount", "$");
    $dgDonations->enable_edit();
    $dgDonations -> display();

    Here’s how the Donations datagrid looks after our enhancements:

    Donations datagrid after enhancements

    Looks good, doesn’t it? Let’s move on!

    Donors

    The second page is the Donors page. It contains a list of donors and donation summary information.

    A one-to-many relationship exists between the table Donors and Donations because one donor can make one or more donations. The Donations table has a foreign-key field donorid which references the Donors table.

    We can join both tables, Donors and Donations by using an INNER JOIN to populate our Donations datagrid.

    SQL 101 – INNER JOIN

    Use an INNER JOIN to create a one-to-many relationship between two database tables. The table on the “one” side of the “one-to-many” relationship should have a primary key column. The other table has a foreign key that points to the primary key in the first table.

    Here’s our SQL statement.

    1
    2
    3
    4
    5
    6
    SELECT
     d.id,
     d.FirstName, d.LastName,
     d.Address, d.Email,
    FROM donors d
    INNER JOIN donations dn ON d.id = dn.donorid

    To make our data look more interesting, we create a full name by concatenating the first name FirstName and last name LastName fields with CONCAT, a SQL function that concatenates two or more strings. In MySQL, it has the following syntax:

    1
    2
    3
    4
    5
    6
    7
    8
    CONCAT(expression1, expression2, expression3,...)
    [cc]

    <p>TO CREATE the donor’s FULL name, we also ADD a blank CHARACTER after FirstName, which adds a SPACE BETWEEN the FIRST AND LAST names. </p>


    [cc lang="sql"]
    CONCAT(d.FirstName, ' ', d.LastName) AS Name

    We also want to display the total amount of donated by a given donor. This is where SQL aggregation functions come in handy. In MySQL, you can use the SUM() function to return the total sum of a numeric column. We name our total TotalDonation.

    1
    SUM(dn.Amount) AS 'TotalDonation'

    Because we want to display the summary information, we need to add a GROUP BY statement that groups identical data in the result-set. In this case, we assume that if the Address and Email fields are them same it means they refer to the same donor. The GROUP BY clause groups records into summary rows for each group. It is typically used with aggregate functions such as COUNT, MAX, MIN, SUM, and AVG.

    1
    GROUP BY d.Address, d.Email

    Putting it all together, here’s the final SQL statement that we will use to create our datagrid.

    1
    2
    3
    4
    5
    6
    7
    8
    SELECT
     d.id,
     concat(d.FirstName, ' ', d.LastName) AS Name,
     d.Address, d.Email,
     SUM(dn.Amount) AS 'TotalDonation'
    FROM donors d
    INNER JOIN donations dn ON d.id = dn.donorid
    GROUP BY d.Address, d.Email

    Just in case you were wondering about what the d and dn are for in the SQL statement, they are the SQL table aliases.

    SQL 101 – Table Alias

    SQL aliases are temporary names used for table or column. Aliases are often used to make column or table names more readable. It only exists for the duration of the query.

    Donors Datagrid

    Below is the code for our Donors datagrid. It is composed of a phpGrid constructor that uses the above SQL statement and the display() function.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $dgDonors = new C_DataGrid(
        "SELECT
            d.id,
            concat(d.FirstName, ' ', d.LastName) As Name,
            d.Address, d.Email,
            sum(dn.Amount) As 'TotalDonation'
            FROM donors d
            INNER JOIN donations dn on d.id = dn.donorid
            GROUP BY d.Address, d.Email "
    ,
        "id", "donors");
    $dgDonors -> display();

    Our Donations datagrid looks like this:

    basic donors datagrid

    Let’s add a few things to improve its usability.

    First of all, the first column displays the table’s primary key id. We don’t need to show this to our users. Let’s hide it using the set_col_hidden() function.

    1
    $dgDonors->set_col_hidden('id');

    Each donor has an email. We can easily make this field an email hyperlink using set_col_format().

    1
    $dgDonors->set_col_format('Email', 'email');

    The TotalDonation column is a currency field. We can change this column to currency format using set_col_currency().

    1
    $dgDonors->set_col_currency("TotalDonation", "$");

    And both the Name and TotalDonation fields should be read-only.

    1
    2
    $dgDonors->set_col_readonly("Name", true);  
    $dgDonors->set_col_readonly("TotalDonation", true);

    Finally, we make the Donors datagrid editable I(except for the fields we just made read-only) with the enable_edit() function.

    1
    $dgDonors->enable_edit();
    The complete Donors datagrid code:
    1
    2
    3
    4
    5
    6
    7
    $dgDonors->set_col_hidden('id');
    $dgDonors->set_col_format('Email', 'email');
    $dgDonors->set_col_currency("TotalDonation", "$");    
    $dgDonors->set_col_readonly("Name", true);  
    $dgDonors->set_col_readonly("TotalDonation", true);
    $dgDonors->enable_edit();
    $dgDonors->display();

    Here’s how the Donors datagrid looks like after the changes (with edit window open).

    donors datagrid edit

    Donation Detail Grid

    As one-to-many relationship exists between table Donors and Donations, we can easily present this relationship using the phpGrid master detail feature.

    Datagrid 101 – Master Detail

    A one-to-many relationship between two data models can be presented in a master-detail format using datagrids.

    The detail grid is a regular phpGrid datagrid object and can use the same methods as any other datagrid such as description title, sort, and update etc. The detail grid is dynamically rendered based on the row selected from the parent (master) grid.

    We will simply reuse the code from Donations datagrid we created earlier in this tutorial.

    1
    2
    3
    4
    5
    6
    $dgDonations = new C_DataGrid("SELECT * FROM donations", "id", "donations");
    $dgDonations->set_col_hidden('id');
    $dgDonations->enable_edit();
    $dgDonations->set_col_edittype('CampaignId', 'select', 'select id, CampaignName from campaigns');
    $dgDonations->set_col_edittype('DonorId', 'select', "select id, concat(FirstName, ' ', LastName) from Donors");
    $dgDonations->set_col_currency("Amount", "$");

    Note that we did NOT include the last line $dgDonations->display().

    Finally, we set the master-detail relationship in our code using set_masterdetails(). The second parameter is the foreign-key defined in the detail table Donations. The third parameter is the foreign-key defined in the master table Donors.

    1
    $dgDonors -> set_masterdetail($dgDonations, 'DonorId', 'id');

    A series of phpGrid master-detail demos and how to use them beyond the scope of this tutorial is also available.

    Campaigns

    The Campaigns page contains campaign information and donations details. Note that a given campaign can receive many donations from one or many donors. Again, we can use phpGrid’s master-detail feature as we what did on the Donors page.

    Let’s start with the Campaigns.

    Since the table Campaigns and Donations have a one-to-many relationship, we can join the two tables by creating an INNER JOIN.

    1
    2
    3
    SELECT c.id, dn.CampaignId, c.CampaignName, c.Description, c.StartDate, c.OrgId,
    FROM campaigns c
    INNER JOIN donations dn ON c.id = dn.CampaignId

    Note that c and dn are the SQL table aliases for the Campaigns and Donations table respectively.

    We also want to show the total amount that has been donated to a particular campaign. Again, we can use the SQL aggregation function SUM() to return the total of the Amount column from the Donations table.

    1
    SUM(dn.Amount) AS 'TotalDonation'

    One of the key ways to measure the success of a donation campaign, besides the its total amount of donations received, is the total number of the donations. Here, we introduce another useful SQL aggregation function called COUNT().

    1
    COUNT(*) AS 'DonationCount'

    The COUNT() function, well, as its name suggests, counts the number of rows returned in a SELECT statement. We give it the name DonationCount.

    Lastly, since we want to display the campaign summary information, we will add a GROUP BY statement which will group records and print their totals into summary rows for each group.

    1
    GROUP BY dn.CampaignId, c.CampaignName, c.Description, c.StartDate, c.OrgId
    SQL 101 – GROUP BY & Aggregates

    Use GROUP BY whenever you need to use the SQL aggregate functions such as COUNT, MAX, SUM, and AVG.

    The complete SQL SELECT statement for our Campaigns datagrid looks like this:

    1
    2
    3
    4
    5
    6
    SELECT c.id, dn.CampaignId, c.CampaignName, c.Description, c.StartDate,
        COUNT(*) AS 'DonationCount',
        SUM(dn.Amount) AS 'TotalDonation'
        FROM campaigns c
        INNER JOIN donations dn ON c.id = dn.CampaignId
        GROUP BY dn.CampaignId, c.CampaignName, c.Description, c.StartDate

    Next, we are going to include a few phpGrid functions to jazz up our Campaigns datagrid.

    First of all, as we did with the others, let’s hide the column id.

    1
    2
    $dgCamp->set_col_hidden('id');
    $dgCamp->set_col_hidden('CampaignId');

    Then, let’s display our TotalDonation field in a currency format.

    1
    $dgCamp->set_col_currency('TotalDonation', '$');

    Don’t forget to make the Campaigns grid editable.

    1
    $dgCamp->enable_edit();

    Lastly, we add a global search by adding the function enable_global_search() which enables a multi-fields global search on any searchable columns. That’s all it takes.

    1
    $dgCamp->enable_global_search(true);

    That’s it for the Campaigns grid. Let’s take a look:

    Campaigns datagrid

    The complete code for the Campaigns grid:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $dgCamp = new C_DataGrid(
        "SELECT c.id, dn.CampaignId, c.CampaignName,
        c.Description, c.StartDate,
        count(*) As 'DonationCount',
        sum(dn.Amount) As 'TotalDonation'
        FROM campaigns c
        INNER JOIN donations dn on c.id = dn.CampaignId
        GROUP BY dn.CampaignId, c.CampaignName, c.Description, c.StartDate"
    ,
        "id", "campaigns");
    $dgCamp->set_col_hidden('id');
    $dgCamp->set_col_hidden('CampaignId');
    $dgCamp->enable_edit();
    $dgCamp->enable_global_search(true);
    $dgCamp->set_col_currency('TotalDonation', '$');

    Donations Detail Grid

    Remember that we mentioned earlier that the Campaigns and Donations table have a one-to-many relationship? We can present their relationship using the phpGrid master detail feature similar to the way what we did for the Donors and Donations tables.

    We will simply reuse the same code we used for the Donations datagrid we made earlier in the tutorial.

    1
    2
    3
    4
    5
    6
    $dgDonations = new C_DataGrid("SELECT * FROM donations", "id", "donations");
    $dgDonations->set_col_hidden('id');
    $dgDonations->enable_edit();
    $dgDonations->set_col_edittype('CampaignId', 'select', 'select id, CampaignName from campaigns');
    $dgDonations->set_col_edittype('DonorId', 'select', "select id, concat(FirstName, ' ', LastName) from Donors");
    $dgDonations->set_col_currency("Amount", "$");

    Note that we did NOT include the last line $dgDonations->display().

    Finally, we set the master-detail relationship in our code using set_masterdetails(). Campaigns is the master grid, and Donations is the detail grid.

    1
    $dgCamp -> set_masterdetail($dgDonations, 'CampaignId', 'id');

    Thus, the complete code for the Campaigns page is:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    $dgCamp = new C_DataGrid(
        "SELECT c.id, dn.CampaignId, c.CampaignName, c.Description, c.StartDate,
        COUNT(*) As 'DonationCount',
        SUM(dn.Amount) As 'TotalDonation'
        FROM campaigns c
        INNER JOIN donations dn on c.id = dn.CampaignId
        GROUP BY dn.CampaignId, c.CampaignName, c.Description, c.StartDate"
    ,
        "id", "campaigns");
    $dgCamp->set_col_hidden('id');
    $dgCamp->set_col_hidden('CampaignId');
    $dgCamp->enable_edit();
    $dgCamp->enable_global_search(true);
    $dgCamp->set_col_currency('TotalDonation', '$');

    // Donations detail grid
    $dgDonations = new C_DataGrid("SELECT * FROM donations", "id", "donations");
    $dgDonations->set_col_hidden('id')->set_caption('Donations');
    $dgDonations->enable_edit();
    $dgDonations->set_dimension('1000px');
    $dgDonations->set_col_edittype('CampaignId', 'select', 'select id, CampaignName from campaigns');
    $dgDonations->set_col_edittype('DonorId', 'select', "select id, concat(FirstName, ' ', LastName) from Donors");
    $dgDonations->set_col_currency("Amount", "$");

    $dgCamp -> set_masterdetail($dgDonations, 'CampaignId', 'id');
    $dgCamp -> display();

    This marks the end of the code needed to create the datagrids required for this tutorial. However, we are not done yet. There is still one more page we need to create – Reports. We will cover this section in the Part 2.

    Stay tuned!

    Run Demo Get this App *

    * Included in Ultimate edition.

     
    Update (7/31)
    The PART II of this tutorial is now available here!

    The post A Step-by-Step Guide to Building a Donation Manager from Scratch in PHP – Part I appeared first on phpGrid - PHP Datagrid.

    ]]>
    9340
    Build a Project Management Application From Scratch https://phpgrid.com/example/build-project-management-application-scratch/ Tue, 06 Jun 2017 07:47:30 +0000 http://phpgrid.com/?p=9299

    What is a Project Management Application? A project management application is a software system used for project planning, resource allocation, tracking of project components, and change management. What is in a Project Management Application? We will be creating a simple and easily customizable PM system to tracks projects, including milestones, tasks, hours, costs, and more. […]

    The post Build a Project Management Application From Scratch appeared first on phpGrid - PHP Datagrid.

    ]]>

    What is a Project Management Application?

    A project management application is a software system used for project planning, resource allocation, tracking of project components, and change management.

    What is in a Project Management Application?

    We will be creating a simple and easily customizable PM system to tracks projects, including milestones, tasks, hours, costs, and more. Since every project is unique, this tutorial merely means to build an application foundation; you should be able to easily extend it based on your requirements.

    In our project management application, employees will be able to:

    • View their tasks

    • Log in hours worked

    Managers will be able to:

    • Manage projects

    • Manage milestones

    • Manage tasks

    • Manage costs and hours

    • Manage employee resources

    The Building Blocks of a Project Management System

    Here are the primary functions of a project management system:

    • Project planning: To define a project schedule, a project manager may use the software to map project tasks and visually describe task interactions.

    • Task management: Allows the project manager to create and assign tasks, establish deadlines, and produce status reports.

    • Resource management: Defines responsibilities – who is supposed to do what.

    • Budgeting and cost tracking: A good project management application facilitates budget reporting as well as viewing, notifying, and updating costs for stakeholders.

    • Time tracking: The software must have the ability to track time spent on all tasks and maintain records for third-party consultants.

    enter image description here

    System Requirements

    • PHP 5.3+

    • MySQL or MariaDB

    • phpGrid

    Creating a Project Management Database

    We will start by creating our project management database. The main tables we will use are:

    • Clients – customer company data

    • Contacts – client contact data. A client can have one or more contacts.

    • Projects – project information

    • Milestones – project milestone

    • Tasks – project tasks

    • Hours – time spent on each task

    • Costs – cost of a task

    • Users – user data; one can be either an employee or a manager

    db table list

    Other tables (lookup tables):

    • ms_status –

    • proj_status –

    • task_status –

    Complete Database Schema Diagram

    A database schema is the structure that represents the logical view of the entire database: tables, views, and primary and foreign keys. A database schema includes all entities and the relationships between them.

    Below is the database diagram of our simple project management application. The key symbol in each table represents the table’s primary key while the magnifying glass indicates a foreign key linking it to another table (lookup table) in the database.

    The diagram is made with DBSchema.

    schema diagram

    Setup phpGrid

    Our simple project management contains many DataGrids. The DataGrid is a spreadsheet-like data table which displays rows and columns representing records and fields from the database table. The DataGrid provides the end-user with the ability to read and write to the database tables on a web page.

    To create the DataGrid, we use a dataGrid tool from phpGrid . The reason why we use a tool instead of building our grids from scratch is that developing a DataGrid in php is usually extremely tedious and prone to errors. The phpGrid DataGrid library will handle all internal database CRUD (Create, Remove, Update, and Delete) operations for us offering faster and better results with minimal coding.

    To install phpGrid, follow these steps:

    1. Unzip the phpGrid download file.
    2. Upload the phpGrid folder to the phpGrid folder.
    3. Complete the installation by configuring the conf.php file.

    Before we begin coding, we must include the following information in “conf.php,” the phpGrid configuration file. Here is an example of the database connection settings:

    1
    2
    3
    4
    5
    6
    define('PHPGRID_DB_HOSTNAME', 'localhost');
    define('PHPGRID_DB_USERNAME', 'root');
    define('PHPGRID_DB_PASSWORD', '');
    define('PHPGRID_DB_NAME', 'custom_pm');
    define('PHPGRID_DB_TYPE', 'mysql');
    define('PHPGRID_DB_CHARSET','utf8');
    • PHPGRID_DB_HOSTNAME – web server IP or host name

    • PHPGRID_DB_USERNAME – database user name

    • PHPGRID_DB_PASSWORD – database password

    • PHPGRID_DB_NAME – database name

    • PHPGRID_DB_TYPE – type of database

    • PHPGRID_DB_CHARSET – always ‘utf8’ in MySQL

    Page Template

    Our page will be comprised of a header, menu, body, and footer. Instead of creating the same page elements repeatedly, we will start by creating a reusable page template.

    head.php

    This is a basic HTML5 template header; it includes a link to a custom stylesheet that will be created in a later step.

    1
    2
    3
    4
    5
    6
    7
    8
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
    <title>My Custom Project Management Application</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link type="text/css" rel="Stylesheet" href="../css/style.css" />
    </head>
    <body>
    1
    2
    3
    4
    5
    6
    <div id="menu">
    <ul>
    <li><a href="clients.php" <?php if($_GET['currentPage'] == 'clients') echo 'class="active"'; ?>>Clients</a></li>
    <li><a href="projects.php" <?php if($_GET['currentPage'] == 'projects') echo 'class="active"'; ?>>Projects</a></li>
    </ul>
    </div>

    menu bar

    Notice the usage of $_GET[‘currentPage’]. Each page will set a value that will highlight the name of the current page on the top menu bar.

    Include the following code in style.css for menu styling; it will transform the above unordered list into a menu.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #menu ul {
        list-style-type: none;
        margin: 0;
        padding: 0;
        overflow: hidden;
        background-color: #1590C2;
    }

    #menu ul li {
        float: left;
    }

    #menu ul li a {
        display: block;
        color: white;
        text-align: center;
        padding: 14px 16px;
        text-decoration: none;
    }

    #menu ul li a:hover,
    #menu .active {
        background-color: #ddd;
        color:black;
    }

    footer.php

    Simply includes the closing tags for the elements we opened in the header:

    1
    2
    </body>
    </html>

    Our Complete Reusable Page Template

    The main content will go after the section title.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?php
    include_once("../phpGrid/conf.php");
    include_once('../inc/head.php');
    ?>

    <h1>My Custom Project Management Application</h1>

    <?php include_once('../inc/menu.php'); ?>

    <h3>Section Title</h3>

    <?php
    // Your main content (datagrid eg.), such as a datagrid, goes here
    ?>

    <?php include_once('../inc/footer.php'); ?>

    Project Management Main Pages

    Our project management application for managers has four pages:

    • Clients

    • Client Details

    • Projects

    • Project Details

    The Clients page displays a list of clients with links to individual client details (Client Details page).

    The Projects page displays a list of projects being managed with links to project details (Project Details page).

    Design Mockup

    Here is our project management application design mockup for project managers who manage one or more projects and assign tasks to employees.

    design mockup

    Clients

    When a manager logs in to the project management system, the first page he sees is the Clients page which contains a complete list of companies.

    The following code will give us a list of clients.

    1
    2
    3
    4
    $dgClient = new C_DataGrid("SELECT * FROM clients", "id", "clients");
    $dgClient->set_col_dynalink("Name", "client-details.php", "id");
    $dgClient->enable_edit();
    $dgClient->display();
    • The first line creates a phpGrid object by passing the SELECT SQL statement with its primary key id followed by the name of the database table – clients.

    • The second line creates a dynamic URL from the primary key “id”; it uses a function called set_col_dynalink(). This function sets a specific column-to-display HTML hyperlink URL based on dynamic values. If the primary key “id” has the value 100, it will display a URL like this client-details.php?id=100 which drills down the client detail page.

    • The third line, enable_edit(), makes the DataGrid editable and all CRUD (Create, Read, Update, Delete) operations are now accessible.

    • The last line calls the display() function to render the DataGrid on the screen.

    You can check out more demos below:

    Client Details

    From the Clients page, the client name has a hyperlink that redirects to the Client Details page for that client when clicked.

    client details

    From the Client Details page, we need to obtain the Client ID that is passed as the URL parameter.

    1
    $clientId = (isset($_GET['id'])) ? intval($_GET['id']) : 0;

    In our application, the Client ID should always be an integer. Thus, we use the PHP intval() function to ensure the Client ID is returned as an integer.

    The following code displays projects associated with the current $clientId using the filter function set_query_filter(). In addition, we make the DataGrid editable with the enable_edit() function; phpGrid will take care of any CRUD operations for us.

    Client Details > Projects

    As you may notice, we again use the same function, set_col_dynalink(), to create hyperlinks to the Project Details table using the Project ID. We will get into the project-details.php page next.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <h4>Projects</h4>

    <?php
    $dgProj = new C_DataGrid("SELECT * FROM projects", "id", "projects");
    $dgProj->set_query_filter(" ClientID = $clientId ");
    $dgProj->set_col_dynalink("ProjectName", "project-details.php", "id");
    $dgProj->enable_edit();
    $dgProj->display();
    ?>
    Client Details > Contacts

    Under the Projects DataGrid, a list of contacts associated with the $clientid is displayed using the same functions set_query_filter() and enable_edit().

    Contacts

    1
    2
    3
    4
    5
    6
    <?php
    $dgCont = new C_DataGrid("SELECT * FROM contacts", "id", "contacts");
    $dgCont->set_query_filter(" ClientID = $clientId ");
    $dgCont->enable_edit();
    $dgCont->display();
    ?>

    Projects

    Now, let’s build the Projects page.

    The Projects page displays a list of managed projects. It is very similar to the Clients page except that the database table is “Projects,” and the hyperlinks have the URL project-details.php instead of client-details.php.

    1
    2
    3
    4
    5
    6
    <?php
    $dgProj = new C_DataGrid("SELECT * Budget FROM projects", "id", "projects");
    $dgProj->set_col_dynalink("ProjectName", "project-details.php", "id");
    $dgProj->enable_edit();
    $dgProj->display();
    ?>

    Project Details

    From the Projects page, each project name has a hyperlink which redirects to each individual Project Details page when clicked.

    And from the Project Details page, we retrieve the Project ID for the URL parameter.

    1
    $projectId = (isset($_GET["id"])) ? intval($_GET["id"]) : 0;

    Look familiar? It should because both Projects and Project Details pretty much follow the same coding pattern used in the Clients and Client Details pages; there are not really that many surprises.

    The Project Details page is made of the following grids, all filtered by the $projectId obtained from the URL parameter.

    • Milestones

    • Tasks

    • Hours

    • Costs

    Milestones

    A milestone marks a major event in a project timeline. Here, we can easily display all the milestones of a project by filtering the value $projectId. Project managers have the necessary access rights to modify the milestones.

    1
    2
    3
    4
    5
    6
    7
    8
    <h4>Milestones</h4>

    <?php
    $dgMS = new C_DataGrid("SELECT * FROM milestones", "id", "milestones");
    $dgMS->set_query_filter(" ProjectID = $projectId ");
    $dgMS->enable_edit();
    $dgMS->display();
    ?>

    Likewise, we can easily filter and display a list of tasks for the current project.

    1
    2
    3
    4
    5
    6
    7
    8
    <h4>Tasks</h4>

    <?php
    $dgTask = new C_DataGrid("SELECT * FROM tasks", "id", "tasks");
    $dgTask->set_query_filter(" ProjectID = $projectId ");
    $dgTask->enable_edit();
    $dgTask->display();
    ?>

    I think you are probably getting the hang of it now. Here’s the code for the two remaining DataGrids.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <h4>Hours</h4>

    <?php
    $dgHour = new C_DataGrid("SELECT * FROM hours", "id", "hours");
    $dgHour->set_query_filter(" ProjectID = $projectId ");
    $dgHour->enable_edit();
    $dgHour->display();
    ?>

    <h4>Costs</h4>

    <?php
    $dgCost = new C_DataGrid("SELECT * FROM costs", "id", "costs");
    $dgCost->set_query_filter(" ProjectID = $projectId ");
    $dgCost->enable_edit();
    $dgCost->display();
    ?>

    Employees Page

    We can now move on to the final part of the tutorial, the Employees page. Employees can login to view active project tasks assigned to them, track task hours, and costs. Their responsibility is simple: to monitor the tasks and log hours worked on any specific project task.

    Design Mockup

    employees screen

    The Employees page has only one menu item: Tasks.

    employees menu

    My Active Tasks

    The first part of the page shows a list of active tasks assigned to the current employee. Each task will have the hours reported by the current employee; this is a perfect situation in which to use a phpGrid subgrid.

    We also need to use set_query_filter() to display only active tasks that have Status value “2”, and only for the current employee.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?php
    $empId = intval(2); // hard code for the demo. In real world, the id should be retrieved in PHP SESSION

    // active (StatusID = 2) tasks datagrid for the current employee
    $dgTask = new C_DataGrid("SELECT * FROM tasks", "id", "tasks");
    $dgTask->set_query_filter(" EmployeeID = $empId AND StatusID = 2 "); // Active value is 2

    // hours reported for the current employee
    $dgHour = new C_DataGrid("SELECT * FROM hours", "id", "hours");
    $dgHour->set_query_filter(" EmployeeID = $empId ");
    $dgHour->enable_edit();

    // hours datagrid is a subgrid of the tasks datagrid
    $dgTask->set_subgrid($dgHour, "TaskID", "id");
    $dgTask->display();
    ?>

    For demo purposes, we hard-coded the Employee ID to 2. In a real-world application, the Employee ID value should be stored and retrieved using PHP SESSION.

    We then create the active Tasks DataGrid for the current employee. Notice the filter function.

    Once we’ve defined the grid for the active tasks, we create a DataGrid to log the hours reported by the current employee.

    Lastly, set_subgrid() causes the Hours DataGrid to become a subgrid of the Tasks DataGrid. The linking field in the Hours subgrid is ‘TaskID’, which is the second parameter, and in the main grid Tasks, it is “id,” the third parameter.

    1
    $dgTask->set_subgrid($dgHour, "TaskID", "id");

    active tasks

    My Hours History

    Lastly, we would like to display a read-only DataGrid using data from the Hours table for the current employee for reviewing purposes.

    1
    2
    3
    4
    5
    6
    <?php
    $dgHourHist = new C_DataGrid("SELECT * FROM hours", "id", "hours");
    $dgHourHist->set_jq_gridName("myHoursHistory"); // the grid name must be unique
    $dgHourHist->set_query_filter(" EmployeeID = $empId ");
    $dgHourHist->display();
    ?>

    Notice we used a function called set_jq_gridName(). You can find more documentation here. This function sets a unique object name for the DataGrid. By default, phpGrid uses the database table name as its internal object name. Since we already created a DataGrid from the Hours table in the last part, we must set a unique name for our second Hours DataGrid.

    Screenshots

    Managers

    managers screenshot 1

    managers screenshot 2

    Employee

    employees screen

    Run Demo Get this App *

    * Included in Premium and Ultimate editions.

    The post Build a Project Management Application From Scratch appeared first on phpGrid - PHP Datagrid.

    ]]>
    9299
    Build a Simple CRM from Start to Finish https://phpgrid.com/example/build-first-simple-crm-scratch/ Tue, 23 May 2017 02:45:16 +0000 http://phpgrid.com/?p=9293

    Customer Relationship Management (CRM) is a system that manages customer interactions and data throughout the customer lifecycle between the customer and the company across different channels. In this tutorial, we are going to build a custom CRM in PHP, which a sales team can use to track customers through the entire sales cycle. We’ll be […]

    The post Build a Simple CRM from Start to Finish appeared first on phpGrid - PHP Datagrid.

    ]]>

    Customer Relationship Management (CRM) is a system that manages customer interactions and data throughout the customer lifecycle between the customer and the company across different channels. In this tutorial, we are going to build a custom CRM in PHP, which a sales team can use to track customers through the entire sales cycle.

    We’ll be creating a simple CRM system for salespeople to:

    • Access their tasks
    • View their leads
    • Create new tasks for each lead
    • Create new opportunity
    • Lose a sale

    Sales managers will be able to:

    • Manage all customers
    • Manage sales team
    • View current sales activities

    Building Blocks of a CRM

    Here is a list of the essential components of the CRM:

    • Leads: initial contacts
    • Accounts: Information about the companies you do business with
    • Contact: Information about the people you know and work with. Usually, one account has many contacts
    • Opportunities: Qualified leads
    • Activities: Tasks, meetings, phone calls, emails and any other activities that allow you to interact with customers
    • Sales: Your sales team
    • Dashboard: CRM dashboards are much more than just eye candy. They should deliver key information at a glance and provide links to drill down for more details.
    • Login: Salespeople and managers have different roles in the system. Managers have access to reports and sales pipeline information.
    Sales Process Overview

    System Requirements

    Create CRM Database

    We will start by creating our custom CRM database. The main tables we will be using are:

    • contact – contains basic customer data
    • notes – holds information collection from Contact by sales people.
    • users – information about sales people
    Main Database Tables

    The contact table contains basic customer information including names, company addresses, project information, etc.

    The notes table is used to store all sales activity information such as meetings and phone calls.

    The users table holds login information about users of the system such as usernames and passwords. Users can also have roles, either Sales or Manager.

    All other tables are simple lookup tables to join to the aforementioned three main relational database tables.

    • contact_status – contains contact status such as Lead and Opportunity each indicating a different stage in a typical sales cycle
    • task_status – the task status can be either Pending or Completed
    • user_status – a sale person can be Active or Inactive
    • todo_type – a type of task either Task or Meeting
    • todo_desc – description of a task such as Follow Up Email, Phone Call, and Conference etc.
    • roles – a user can be either a Sales Rep or a Manager

    Complete Database Schema Diagram

    A database schema is the structure that represents the logical view (tables, views, primary and foreign keys) of the entire database. A database schema includes entities and the relationship among them.

    It is a good practice to have one primary key for each table in a relational database. A primary key is a unique identifier for each record. It can be the social security number (SSN), vehicle identification number (VIN), or simply auto-increment number (a unique number that is generated when a new record is inserted into a table).

    Below is the database diagram of our simple CRM. The key symbol in each table represents the table primary key. The magnifying glass indicates foreign key linking another table in the database. Sometimes we call it the “lookup” table.

    install.sql

    Once you have an understanding of the database table structure, find the `install.sql` script in the db folder and use a MySQL tool such as MySQL Workbench or Sequel Pro to run the SQL script. It should create a new relational database named custom_crm and its database tables.

    Setup phpGrid

    Our simple CRM contains many datagrids. The datagrid is a spreadsheet-like data table that displays rows and columns representing records and fields from the database table. The datagrid gives the end-user ability to read and write to database tables on a web page.

    We opt-in a datagrid tool from phpGrid to create the datagrid. The reason to use a tool instead of building them from scratch is that developing the datagrid is usually extremely tedious and error-prone. The datagrid library will handle all internal database CRUD (Create, Remove, Update, and Delete) operations for us with better and faster results with little code.

    To install phpGrid, follow these steps:

    1. Unzip the phpGrid download file
    2. Upload the phpGrid folder to the `phpGrid` folder
    3. Complete the installation by configuring the `conf.php` file

    Before we begin coding, we must specify the database information in `conf.php`, the phpGrid configuration file. Here is an example of database connection settings:

    1
    2
    3
    4
    5
    6
    define('PHPGRID_DB_HOSTNAME', 'localhost');
    define('PHPGRID_DB_USERNAME', 'root');    
    define('PHPGRID_DB_PASSWORD', '');
    define('PHPGRID_DB_NAME', 'custom_crm');
    define('PHPGRID_DB_TYPE', 'mysql');  
    define('PHPGRID_DB_CHARSET','utf8');
    • PHPGRID_DB_HOSTNAME – web server IP or host name
    • PHPGRID_DB_USERNAME – database user name
    • PHPGRID_DB_PASSWORD – database password
    • PHPGRID_DB_NAME – database name of our CRM
    • PHPGRID_DB_TYPE – type of database
    • PHPGRID_DB_CHARSET – always ‘utf8’ in MySQL

    Page Template

    The CRM Page Template

    Before we can start building our first page of the CRM, it is a good practice to make the page items reusable such as header and footer.

    The page will be comprised of a header, menu, body and footer. We will start by creating a reusable page template.

    head.php

    This is a basic HTML5 template header. It includes a link to a custom stylesheet that will be created in a later step.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <!DOCTYPE html>
    <html lang="en">

    <head>
      <title>My Custom CRM</title>
      <meta charset="utf-8">
      <link rel="stylesheet" href="../css/style.css">
    </head>

    <body></code>
    </html>

    <h4>menu.php</h4>

    <figure id="post-251806" class="align-none media-251806"><img src="https://raw.githubusercontent.com/phpcontrols/phpgrid-custom-crm/master/design/menus/custom-crm-salesrep-menu.png" alt="" /><figcaption>The Top Menu Bar</figcaption></figure>



    [cc lang="html"]
    <div id="menu">
        <ul>
            <li><a href="tasks.php" <?php if($_GET['currentPage'] == 'tasks') echo 'class="active"'; ?>>Tasks</a></li>
            <li><a href="leads.php" <?php if($_GET['currentPage'] == 'leads') echo 'class="active"'; ?>>Leads</a></li>
            <li><a href="opportunities.php" <?php if($_GET['currentPage'] == 'opportunities') echo 'class="active"'; ?>>Opportunities</a></li>
            <li><a href="customerwon.php" <?php if($_GET['currentPage'] == 'customerwon') echo 'class="active"'; ?>>Customers/Won</a></li>
        </ul>
    </div></code>

    Notice the usage of

    1
    $_GET['currentPage']

    Each page will set a value which will highlight the name of the current page on the top menu bar.

    Include the following code in `style.css` for menu styling. It will transform the above, unordered list into a menu.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #menu ul {
      list-style-type: none;
      margin: 0;
      padding: 0;
      overflow: hidden;
      background-color: #1590C2;
    }
    #menu ul li {
      float: left;
    }
    #menu ul li a {
      display: block;
      color: white;
      text-align: center;
      padding: 14px 16px;
      text-decoration: none;
    }
    #menu ul li a:hover,
    #menu .active {
      background-color: #ddd;
      color: black;
    }</code>

    footer.php

    Closing tags for the elements we opened in the header:

    1
    2
    </body>
    </html>

    Our Complete Reusable Page Template

    This is the complete page template. The main content will go after Section Title.

    1
    2
      include_once("../phpGrid/conf.php");      
      include_once('../inc/head.php');
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <h1>My Custom CRM</h1>

    <?php include_once('../inc/menu.php'); ?>

    <h3>Section Title</h3>

    <?php
      // Your main content, such as a datagrid, goes here
    ?>

    <?php include_once('../inc/footer.php'); ?>

    CRM Main Pages

    Are you still with me? Good! We can now finally develop the first page in our CRM.

    Our CRM for sales team members has four pages:

    • Tasks
    • Leads
    • Opportunities
    • Customers/Won

    Each page indicates a different stage in a typical sales cycle.

    Design Mockup

    Here’s our CRM design mockup for the sales people.

    Sales Team CRM Screen

    Tasks

    When a sales team member logged in, the first page he sees is a list of current tasks.

    As you may recall, our notes table holds all the sales activity information. We can create a datagrid and populate it from the Notes table using phpGrid.

    The Tasks page main content is a datagrid. The following two lines will give us a list of tasks of the current sales person.

    1
    2
    3
      $dg = new C_DataGrid("SELECT * FROM notes", "ID", "notes");
      $dg -> display();
    ?>
    • The first line creates a phpGrid object by passing the SELECT SQL statement, its primary key – ID, and then the name of the database table – notes.
    • The second and the final line calls display() function to render the datagrid on the screen. Check out the basic datagrid demo for more detail.

    Leads

    The leads page contains list of current leads that the sales person is responsible for. Each Lead can have one or many Notes. We will use the phpGrid subgrid feature for that.

    We also need to use set_query_filter() to display only the leads, Status = 1, and only for the current sales person.

    Contact status table

    Contact Status Table
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      $dg = new C_DataGrid("SELECT * FROM contact", "id", "contact");
      $dg->set_query_filter(" Status = 1 && sales_rep = 1 ");

      // the detail grid displays notes about a lead
      $sdg = new C_DataGrid("SELECT * FROM notes", "id", "notes");
      $sdg->set_query_filter(" Sales_Rep = 1 ");
      $sdg->enable_edit();

      $dg->set_subgrid($sdg, 'Contact', 'id');
      $dg -> display();

    Opportunities

    A Lead becomes an Opportunity once it is qualified. The Opportunities page is similar to the Leads page. The only difference is the filtered status code in set_query_filter is Status = 2.

    1
    2
    3
    4
    5
    6
    7
    8
    9
      $dg = new C_DataGrid("SELECT * FROM contact", "id", "contact");
      $dg->set_query_filter(" Status = 2 && sales_rep = 1 ");

      $sdg = new C_DataGrid("SELECT * FROM notes", "id", "notes");
      $sdg->set_query_filter(" Sales_Rep = 1 ");
      $sdg->enable_edit();

      $dg->set_subgrid($sdg, 'Contact', 'id');
      $dg -> display();

    Customers/Won

    Customers/Won has the Status = 3. Similar to Leads and Opportunities, Customers/Won can also have Notes.

    1
    2
    3
    4
    5
    6
    7
    8
    9
      $dg = new C_DataGrid("SELECT * FROM contact", "id", "contact");
      $dg->set_query_filter(" Status = 3 && sales_rep = 1 ");

      $sdg = new C_DataGrid("SELECT * FROM notes", "id", "notes");
      $sdg->set_query_filter(" Sales_Rep = 1 ");
      $sdg->enable_edit();

      $dg->set_subgrid($sdg, 'Contact', 'id');
      $dg -> display();

    That’s all there is to it for sales people in our simple CRM.

    Manager Dashboard

    The sales manager will have access to all records in the sales pipeline as well as the ability to manage sales team and customer data.

    Here’s the design mockups:

    My Sales Reps

    Menu

    Managers Dashboard has three menu items.

    1
    2
    3
    4
    5
    6
    7
    <div id="menu">
        <ul>
            <li><a href="?gn=users" <?php if($tableName == 'users') echo 'class="active"'; ?>>My Sales Reps</a></li>
            <li><a href="?gn=notes" <?php if($tableName  == 'notes') echo 'class="active"'; ?>>Tasks</a></li>
            <li><a href="?gn=contact" <?php if($tableName == 'contact') echo 'class="active"'; ?>>Contact</a></li>
        </ul>
    </div>

    Main content

    Each menu item represents a table in the CRM database. $_GET[‘gn’] will store the table name. It dynamically generates the datagrid based on table name passed.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
      $tableName = (isset($_GET['gn']) && isset($_GET['gn']) !== '') ? $_GET['gn'] : 'users';

      switch($tableName){
        case "users":
            $dg = new C_DataGrid("SELECT * FROM users", "id", "users");

            $sdg = new C_DataGrid("SELECT * FROM contact", "id", "contact");
            $dg->set_subgrid($sdg, 'sales_rep', 'id');
            break;

        case "notes":
            $dg = new C_DataGrid("SELECT * FROM notes", "id", "notes");
            break;

        case "contact":
            $dg = new C_DataGrid("SELECT * FROM contact", "id", "contact");

            $sdg = new C_DataGrid("SELECT * FROM notes", "id", "notes");
            $sdg->enable_edit();

            $dg->set_subgrid($sdg, 'Contact', 'id');
            break;
    }

      $dg->enable_edit();
      $dg->display();
    ?>

    My Sales Rep

    Since a sales manager needs to quickly find out whom a sale person is working with, we added a detail grid $sdg populated from contact table and link with the parent grid.

    1
    2
    $sdg = new C_DataGrid("SELECT * FROM contact", "id", "contact");
    $dg->set_subgrid($sdg, 'sales_rep', 'id');

    sales_rep is the connecting key in contact table to the id that is the foreign key in users table. Remember the users stores all of our sales people information.

    Screenshots

    CRM – Sales Screen
    CRM – Manager Screen

    Interactive Demo

    Login as Sales Rep Login as Manager Get this App *

    * Included in Ultimate edition.

    The post Build a Simple CRM from Start to Finish appeared first on phpGrid - PHP Datagrid.

    ]]>
    9293
    Create a Database Management System in 15 Lines of Code https://phpgrid.com/example/database-content-administration-application-15-lines-php-code/ Mon, 02 Jan 2017 04:15:11 +0000 http://phpgrid.com/?p=9186

      Introduction We will learn how to build a fully functional, single-page database content administration system using phpGrid and other PHP components with a minimum amount of code. The application will perform common data operations such as Create, Read, Update, Delete, otherwise known as CRUD on MySQL database tables. Note the demo application requires phpGrid […]

    The post Create a Database Management System in 15 Lines of Code appeared first on phpGrid - PHP Datagrid.

    ]]>
    Download this demo

     

    Introduction

    We will learn how to build a fully functional, single-page database content administration system using phpGrid and other PHP components with a minimum amount of code. The application will perform common data operations such as Create, Read, Update, Delete, otherwise known as CRUD on MySQL database tables.

    Note the demo application requires phpGrid version 7 and above. The demo uses MySQL, however, the same basic code should work with other databases with the use of a different SQL schema SELECT statement.

    Design

    Our application will have a list of database schemas and tables on the left side – the sidebar – and a database table on the main screen – the main. Both the sidebar and the main are datagrids. On the main datagrid, which contains the database table, we will also add a search bar so users can search within the displayed grid.

    Our design mockup:

    db-admin-mockup

    2-Column Layout

    Let’s start by creating the layout. What we need is a fixed-width sidebar on the left while the main – a grid – stays “fluid” so it fills the remaining document width. The main grid will be populated with data from the database table selected from the left sidebar.

    Luckily, CSSPortal has an excellent layout tool which easily generates a column-based layout with only point and click.

    http://www.cssportal.com/layout-generator/

    An alternative is to download this boilerplate (File -> Save As) which contains all the HTML and CSS code needed for this demo application.

    Setup

    Let’s start coding. Presumably, you have already installed phpGrid on your web server. If not, follow this guide to learn how – http://phpgrid.com/documentation/installation/

    First, add the following lines to the TOP of our page

    1
    2
    use phpGrid\C_DataGrid;
    require_once("phpGrid/conf.php");

    The first line adds the phpGrid namespace so PHP knows where to find phpGrid in the system. Otherwise, PHP will throw a nasty error – “Fatal error: Class ‘C_DataGrid’ not found”.

    The second line references phpGrid by including its conf.php. The Installation Guide – http://phpgrid.com/documentation/installation/ – explains this in greater length.

    Sidebar

    The left sidebar contains a list of the tables found in each respective database in a subgrid.

    Sidebar – Step 1

    The first step is to return a list of current schemata from the selected database. In MySQL, the following SQL statement retrieves a list of schema names.

    1
    SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA

    The PHP code to return a list of schemas is as follows:

    1
    2
    3
    4
    // schema list
    $dbs = new C_DataGrid("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA", "SCHEMA_NAME", "INFORMATION_SCHEMA.SCHEMATA");
    $dbs->set_dimension('300px');
    $dbs->set_pagesize(999)->set_scroll(true);

    How the above code works:

    set_dimension sets the width of the left sidebar to 300 pixels.
    set_pagesize sets the height of the page to a very large number, e.g. 999. Thus, all data will be displayed on a single page. set_scroll removes the pagination controls normally found in the bottom footer.

    Sidebar – Step 2

    The second step displays a list of available database tables in each schema in a subgrid.

    The PHP code to return a list of tables appears below.

    1
    2
    3
    4
    // table list    $tbl = new C_DataGrid("SELECT TABLE_NAME, TABLE_SCHEMA, TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES", "TABLE_NAME", "INFORMATION_SCHEMA.TABLES");
    $tbl->set_col_hidden('TABLE_SCHEMA');
    $tbl->set_pagesize(999)->set_scroll(true);
    $tbl -> set_col_dynalink("TABLE_NAME", "db_admin.php", array("TABLE_NAME", "TABLE_SCHEMA"), '', "_top");

    How the above code works:

    First, we hide the TABLE_SCHEMA column because it is redundant. The page size is set to a large number (999) and scroll is set to true. Finally, and  most importantly, set_col_dynalink forms a dynamic URL for each database table used to populate the main datagrid.  You can learn more about the set_col_dynalink function here: http://phpgrid.com/documentation/set_col_dynalink/

    Sidebar – Step 3

    Lastly, set the subgrid. The subgrid displays an inline detail grid for each row in the parent grid. If you are not familiar with phpGrid subgrids, check out the subgrid demo online – http://phpgrid.com/example/subgrid/.

    1
    2
    $dbs->set_subgrid($tbl, 'TABLE_SCHEMA', 'SCHEMA_NAME');
    $dbs->display();

    db-admin-sidebar

    Main Column

    The main column contains the datagrid for the database table. Recall that in the code to create the sidebar, Step 2, we used a function called “set_col_dynalink” which set a dynamic URL for every database table name in the URL query string. Now we need to retrieve the schema name and table name by using the following code:

    1
    2
    $schemaName = (isset($_GET['TABLE_SCHEMA']) && isset($_GET['TABLE_SCHEMA']) !== '') ? $_GET['TABLE_SCHEMA'] : 'sampledb';
    $tableName = (isset($_GET['TABLE_NAME']) && isset($_GET['TABLE_NAME']) !== '') ? $_GET['TABLE_NAME'] : 'orders';

    The first line of code gets the schema name and the second gets the table name. There’s nothing special about this except we set a default value for each variable to be used in cases where the parameters are missing – such as as when the page is first loaded.

    Below is the code for the main grid:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $dg = new C_DataGrid("SELECT * FROM $tableName",'orderNumber', "$tableName",
    array("hostname"=>"localhost",
    "username"=>"root",
    "password"=>"",
    "dbname"=>$schemaName,
    "dbtype"=>"mysql",
    "dbcharset"=>"utf8"));
    $dg->enable_global_search(true);
    $dg -> display();

    How the above code works:

    The first line uses phpGrid’s multiple database reference feature. This is essential because we need to reference different tables found in different databases. See http://phpgrid.com/example/multiple-databases-support/ for more information about how phpGrid can be configured to work with multiple databases.

    Note that it is important to use the correct corresponding primary key when referencing the default database table.  In this case, we are referencing the “orders” table with the primary key “orderNumber”.

    enable_global_search adds the global search bar to top of the grid. Finally, the last line displays our datagrid.

    db-admin-main

    That’s all there is to it! You now have a web-based database content management console using fewer than 15 lines of code.

    But Wait, There’s More!

    We can beef up the grid and take advantage of the fluid layout design by adding a few more lines of code.

    First, we add a caption to show the current schema and table name. Then, we set the auto width, enable edit and then add a global search to the top.

    1
    2
    3
    4
    5
    $dg->set_caption(strtoupper("$schemaName.$tableName"));
    $dg->enable_autowidth(true);
    $dg->enable_edit();
    $dg->set_scroll(true);
    $dg->enable_global_search(true);

    Finally, before we go, let’s add the following javascript event to make sure that the grid will only resize in its container and not in the browser window itself.

    1
    2
    3
    4
    // set grid width to parent DIV
    $dg->before_script_end .= 'setTimeout(function(){$(window).bind("resize", function() {
    phpGrid_'
    . $tableName .'.setGridWidth($(".right").width());
    }).trigger("resize");}, 0)'
    ;

    Summary

    Congrats! You have built a content management system for your database!

    Download this demo

    The post Create a Database Management System in 15 Lines of Code appeared first on phpGrid - PHP Datagrid.

    ]]>
    9186