You are on page 1of 132

eFrontPro

MANUAL
Contents
Intro ................................................................................................................................ 5
What’s new in eFrontPro ......................................................................................... 5
Administrator ................................................................................................................ 7
Dashboard ................................................................................................................ 7
Users ........................................................................................................................... 8
Courses .................................................................................................................... 10
Curriculums ............................................................................................................. 14
Categories .............................................................................................................. 15
Certificates.............................................................................................................. 16
Groups ..................................................................................................................... 17
Branches ................................................................................................................. 18
Jobs .......................................................................................................................... 19
Skills........................................................................................................................... 20
User types ................................................................................................................ 21
Audiences ............................................................................................................... 23
Locations ................................................................................................................. 25
Themes .................................................................................................................... 26
Notifications ............................................................................................................ 27
Extend Profile .......................................................................................................... 28
Languages .............................................................................................................. 30
Reports..................................................................................................................... 31
Maintenance.......................................................................................................... 33
Discussions ............................................................................................................... 34
Archive .................................................................................................................... 34
Plugins ...................................................................................................................... 34
eCommerce ........................................................................................................... 35
System Settings ....................................................................................................... 36
Instructor ..................................................................................................................... 37
Dashboard .............................................................................................................. 37
Course screen ........................................................................................................ 38
Lesson screen ......................................................................................................... 39
Group key ............................................................................................................... 42
Course catalog ...................................................................................................... 42
Discussions ............................................................................................................... 44
Courses .................................................................................................................... 44
Learner ........................................................................................................................ 45
My courses .............................................................................................................. 45
Course view ............................................................................................................ 45
Course catalog ...................................................................................................... 46
Discussions ............................................................................................................... 46
Personal info ........................................................................................................... 47
Search ..................................................................................................................... 49
Logout ..................................................................................................................... 49
Technical Topics ........................................................................................................ 50
Installation details and considerations ............................................................... 50
Upgrading ............................................................................................................... 52
System Architecture .............................................................................................. 53
How to secure your environment ........................................................................ 55
Performance Tips ................................................................................................... 56
How to create a Theme ........................................................................................ 57
How to customize Certifications .......................................................................... 61
Frequent Questions ................................................................................................... 66
How to assign a set of courses to new users directly ........................................ 66
How to offer Compliance Training ...................................................................... 67
How to customize your learning portal ............................................................... 69
How to customize the communication emails .................................................. 70
What is the difference between Branches and Groups .................................. 72
How to work with Mass Actions ............................................................................ 73
How eFrontPro supports Instructor Led Training ................................................. 74
How eFrontPro deals with WCAG, Section 508 & ADA Compliance ............. 75
How to integrate eFrontPro with your system .................................................... 77
How to work with content conversions ............................................................... 78
How to work with Videoconferencing ................................................................ 79
Appendix 1: eFrontPro Plugin Guide....................................................................... 80
Quick start ............................................................................................................... 80
More plugin examples......................................................................................... 114
Considerations...................................................................................................... 114
Plugin API Reference ........................................................................................... 120
Event Reference .................................................................................................. 124
Core API Notes ..................................................................................................... 126
Intro
Welcome! Whether you’re a long time eFront user upgrading to the latest
version, or you have just entered the world of e-learning, rest assured that you
have chosen well. eFront is a stable, proven, platform covering the e-learning
needs of thousands of organizations and millions of students all over the world.

This Quick Start Guide will teach you all you need to know to get started with
deploying eFrontPro, and creating, managing and taking courses. It’s organized
in 3 sections in accordance with the 3 working modes of eFrontPro: the
Administrator, the Instructor and the Learner mode, plus a fourth section
covering common UI elements.

What’s new in eFrontPro


eFrontPro (originally code-named eFront4) is the new, revamped, version for our
best-of-breed eFront LMS platform. This new version combines the depth of
eFront with a new fluid interface, reworked internals and support for blended
learning.

Improvements include:

New User interface


The User Interface has been redesigned from ground-up to bring consistency
and superior support for mobile devices through a responsive design and a
mobile first approach. eFrontPro also minimizes the clutter of the system in a
number of meaningful ways.

Content creation
With eFrontPro we took a leap in revamping the content creation process. We
made it really easy to re-use content you already have from PDFs, Videos,
Audios, Images and SCORM or re-use web material from Youtube, Vimeo, Prezi
and other sources.

Blended learning (ILT)


eFrontPro seeks to redefine the blended learning environment. It allows you to
manage both your online and offline training programs. To achieve that, we
introduce a new classroom course type that takes place in the physical world
but is organized and moderated online. A classroom course can have limited
seats, waitlists, meetings and multiple sessions among others.

Reporting
We totally redesigned the Reporting section of the system to provide clarity and
easy access to vital information. The new filtering system let you segment your
reports in any meaningful way. The new visualization of system activity offers a

5
stunning way to report on your learners’ progress. And the mass actions minimize
the time to perform complex tasks.

Extended Enterprise
Leverage the power of eFrontPro to extend eLearning across your enterprise.
Serve content from a centralized eLearning repository and deliver to any number
of privately branded portals. Each enterprise portal can be personalized using
distinct skins and features to provide a learning experience appropriate to any
target audience.

E-commerce extensions
There is a wealth of ecommerce extensions in eFrontPro, such as Paypal and
Stripe support and ways to handle complex e-commerce relationships through
Balances, Discounts and Price Tracks. If you want to use eFrontPro to resell or
license courses we have great news for you!

Offline Learning
eFrontPro utilizes the power of HTML5 to bring offline content support embedded
within the platform. This first-of-its-class offline implementation let you download
a lesson for offline viewing directly within your browser and without the need of
a dedicated mobile application.

Audiences and Curriculums


Audiences and Curriculums are new entities to help you organize your learners
and courses. The Audiences feature offers dynamic user grouping behavior,
while Curriculums offer a way to group courses in larger logical entities and apply
rules to them.

Internals
eFrontPro is built around jQuery (a step forward from our legacy Prototype based
codebase), uses (industry standard) get-text for translations, HTML5 and
Bootstrap-3 for the interface and a modern MVC architecture. The result is a
dramatically improved and lean code-base that we can build upon in the years
to come.

6
Administrator

Dashboard
The Admin dashboard includes everything you need to effectively manage your
eFrontPro installation. Within it you can add users, create courses, view reports
and manage your account.

The Dashboard includes 2 main sections.

The left one, titled “Options”, has an icon-based menu of all the available
administration sections.

The right includes a list of announcements (with the ability to create a new one),
and a calendar highlighting events for the current month.

Finally, the header contains a menu with options to quickly go to a specific


section, search and edit your account information.

7
Users
The Users section allows you to list, add and manage users.

A user can be either an Administrator, a Professor, a Student or a custom user


type.

The Users section allows you to see all users in a tabular listing with buttons to edit,
delete or login as a specific user, and contains a search box for quickly finding
the users you want to view or edit.

The user list can be downloaded as an Excel-compatible CSV file.

The user add/edit panel, shown when you create a new user or edit an existing
one, allows you to specify user information such as email address, preferred
language, time zone, whether or not the user is active, and a short CV.

Mini How-to: Adding a User


1. On the Users section, click the “+ Add User” button. This will take you to
the form for adding a new user.

2. Enter the values for the required fields: First and Last name, username,
password (and password confirmation), and e-mail address. The default
user type created is Student (as normally most of your users will be
students), so if you want to add an Administrator or Instructor be sure to
change it.

8
3. The optional values include: User avatar (usually a photo of the user),
language (which can be used to serve language specific content), time-
zone and the Branch the user belongs to (in case you use eFrontPro’s
Branches feature). You can also add a short description or CV for the user.

4. After you’ve completed the User add form, click Submit and your new
User will be created.

Note that you can also have custom fields when you add a User, which you
can enable in the Extend Profile section.

9
Courses
A course is the main learning entity in eFrontPro.

You can create a new course in the Courses section, by opening the “Add
Course” panel and giving it a name, a category, a type (e-learning or classroom
based), and an optional description and thumbnail image (Avatar).

There are a few more options that can be set for a course if you click to open
the “Advanced Settings”, such as its price (if you want it to be a paid course),
whether the course will offer a certification to those who have completed it (as
well as the certification’s duration), the intended audience and language, and
the branch (department) that offers it.

A course code can also be set, to help users quickly and uniquely identify the
course.

Courses are owned by the user that creates them, and, who has the ability to
edit the basic course information such as name, category, price, etc. A course
owner can assign more users as Instructors for the course, giving them the ability
to add and modify course content.

The Courses section allows you to see all courses in a tabular listing with buttons
to edit or delete a specific course, and contains a search box for quickly finding
the course you want to view or edit. The courses list can be downloaded as an
Excel-compatible CSV file.

After selecting a course, the user can view or edit its Properties, Lessons, Users
and Skills, through the respective tabs. The Properties tab displays the same basic
and advanced course information as discussed above for the “Add Course”
panel.

10
The Lessons tab displays a listing of the lessons contained in the course, and
allows the user to create new lessons assigned to the course, set the lesson order
and configure whether or not the students have to complete lessons in order
(“Serial rule enabled/disabled”). The lesson list can be downloaded as an Excel-
compatible CSV file.

The Users tab displays a listing of the users associated in the course, as either
Professors or Students and their registration date. For each student, the Users
listing also displays his course completion date, what his score was and whether
he was awarded a certificate. This information can be downloaded as an Excel-
compatible CSV file.

Finally, the Skills tab shows a listing of skills associated with the selected course.
A “skill” describes a specific knowledge or experience that is either Offered by
the course (meaning that students who complete the course are assigned that
skill) or “Required” by the course (meaning that students need to have that skill,
perhaps by completing another course offering it, in order to take the course).
The listing of skills can be downloaded as an Excel-compatible CSV file.

11
Mini How-to: Adding a new Course

To add a new course, click on the “+ Add Course” button in the Courses section.
This will open the page to add a new course.

The required fields are the Name and the Category of the course (e.g. History,
Math, Physics, etc.)

The default course type is set to e-learning, for a typical e-learning course
based on asynchronous (i.e. at the student’s discretion) access to the course
material. If you want to create an instructor-led classroom based course,
change this option to Classroom (ILT).

There’s also the option add a short description for the course.

If you’re OK with the settings, you can create the course by clicking the
“Submit” button. But there are several advanced options that you can see and
set by clicking on the “Advanced Settings” button.

The advanced settings include: a course code (a short alphanumeric code for
easy reference, e.g. “CS101”), language (to show language specific content to
different users), a base price (for selling the course), availability (how many
days an enrolled user has access to the course), CEUs (how many continuous
education units the course corresponds to), course’s audiences and branch,
and, finally, the certification awarded for completing the course.

12
When done, click “Submit”. The arrow on the right of the submit button works as
a shortcut that enabled you to create a Lesson with the same name as the
course.

13
Curriculums
Curriculums are a way of grouping your courses for better organization, to
perform mass actions on all of them, and to sell them online as a single entity.
What Groups are for Users, Curriculums are for courses.

The Curriculums section allows you to see all existing curricula in a tabular listing
that also shows the number of students enrolled to each one and buttons to edit
or delete a specific curriculum. The section also features a search box for quickly
finding the curriculum you want to view or edit. The curriculum list can be
downloaded as an Excel-compatible CSV file.

You can add a new curriculum through the “Add curriculum” button, by entering
a name for your new curriculum and selecting the category it belongs too, an
avatar and a short description.

There are also a number of advanced settings, such as a code enabling students
to register to the curriculum by themselves, whether the Curriculum is active and
ok to be shown on the catalog, a base price for enrolling in the curriculum, the
branch it belongs to and the certification you get by completing it.

After you have created your curriculum you can add Courses and Users to it.

Mini How-to: Adding a Curriculum

To add a new curriculum, click on the “+ Add Curriculum” button in the


Curriculum section. This will open the page to add a new curriculum.

On the form that appears you need to fill in the name of the curriculum and
select the category (e.g. History, Math, etc) that your curriculum belongs to. You
can also add an optional Short Description.

Finally, there are several advanced options that you can set when you click on
the “advanced settings” link. Those are a unique code for identifying the
curriculum, whether to activate and/or show the curriculum on the catalog, the
base price for selling the curriculum, the branch the curriculum belongs to, and
a certification that is awarded to the users completing this curriculum.

When you are finished completing the form, click “Submit” to create the new
curriculum.

14
Categories
Categories are a way of organizing your courses into different themes / topics,
etc. They can be a flat list (e.g Ancient Civilizations, Biology, Programming, etc)
or form nested hierarchies (e.g Ancient Civilizations/Greek, Ancient
Civilizations/Latin, etc).

The Categories section allows you to see all existing categories in a tabular listing
that also shows the number of courses assigned to each one and buttons to edit
or delete a specific category. The section also features a search box for quickly
finding the category you want to view or edit. The categories list can be
downloaded as an Excel-compatible CSV file.

You can add a new category through the “Add category” button, by entering
a name for your new category and selecting its parent category (if it’s supposed
to be nested).

15
Certificates
The Certificates section shows a listing of the certificates available to be
awarded upon the completion of a course. You can edit, delete or preview
existing certificates and add new ones.

To add a new certificate, you press the “Add certificate” button (duh!). A
certificate needs a name, and a definition of how it should be presented (as a
PDF). The definition is in the form of an XML template, with all the defaults
provided for you, and the option to customize the presentation and the
information shown in the certificate by placing simple pre-defined tags like
<grade>, <username> and <logo>.

You can also assign the certificate to a specific branch, in which case it will only
be available to its members.

To learn how you can create your own certificate or customize and existing
one, visit the How to customize Certifications chapter.

16
Groups
Groups organize users into logical entities, allowing them to treat all of them as a
single entity. You can communicate to the users of a group directly, assign them
courses, or see reports on them. Groups come with mass actions to synchronize
its users with its courses.

The Groups section shows a tabular listing of all existing groups, allowing you to
edit or delete them and add a new one. You can add a group with the “Add
Group” button by setting a name, selecting an optional branch, and entering a
short description. There are also some advanced options that can be set for a
group, such as a unique group key (which can be shared with the students to
allow them to register to the group’s classes) and an optional limit of maximum
key uses (for groups were a limited student membership is desired).

After selecting a group from the list of groups, you can update its basic and
advanced information, and see the Users and Courses assigned to the group.
You also have the option to mass-enroll all of the group users to the group’s
courses.

To learn how to mass-enroll all the users belonging to a Group to a course,


check the How to assign a set of courses to new users directly chapter.

17
Branches
Branches allow you to divide your e-learning offering into different logical units
(or “departments”), each with its own courses, users, professors and branding
(sub-domain, theme, logo, etc.). Branches can be a flat list or form a nested
hierarchy.

The Branches section displays a tabular listing of all existing branches, their parent
branch (if nested), and the number of users and courses belonging to the
branch, and allows you to edit a branch or add a new one. The branches list
can be downloaded as an Excel-compatible CSV file.

To create a new branch, you press the “Add Branch” button and enter the
desired name and sub-domain (e.g. mybranch.efrontlearning.com), and an
optional parent branch. You can also enter an optional branch short-code, to
help you uniquely identify the branch.

The panel for editing an existing branch is similar to the “add branch” panel, but
also contains tabs to see the branches Users, Courses and extra Settings.

The Users and Courses tabs are simple tabular listings of the Users and Courses
assigned to the branch respectively, and allow you to download this information
in Excel-compatible CSV format.

The branch Settings tab allows you to set the language used for the branch, as
well as a custom logo, favicon and theme to be used for the branch’s content.

To learn more about the differences between Branches and Groups, you can
visit the What is the difference between Branches and Groups chapter.

18
Jobs
Jobs enable you to divide your students according to their role in your
organization or company. This can be helpful in enterprise e-learning situations,
allowing you to assign courses to people with specific positions. Jobs are a handy
attribute for defining dynamic “Audiences” (see later chapter).

The Jobs section shows a tabular listing of all defined jobs, along with the branch
they belong to (if set), and the number of users holding that job. From the listing,
you have the option to edit or delete an existing job, or create a new one. The
Job listing can be downloaded as an Excel-compatible CSV file.

To create a new Job, click the “Add Job” button, and enter the desired name,
and an optional Branch that the job will be constrained in, number of maximum
users allowed having this job and a short description. You also have the option
to set a unique short-code to quickly and unambiguously identify this job.

19
Skills
A “skill” describes a specific knowledge or experience that is either offered by a
course (meaning that students who complete the course “get” that skill) or
“required” by a course (meaning that students need to have that skill, perhaps
by completing another course offering it, in order to take a course).

The Skills sections shows you a listing of all skills, along with the category each skill
belongs to and the number of users that possess it, and has buttons to add a
new skill, or edit or delete an existing one.

The listing of skills can be filtered, to quickly find the one you want to view/edit,
and it can also be downloaded as an Excel-compatible CSV file.

To add a new skill, click the “Add Skill” button and enter a name and category
the skill belongs to, as well as an optional description and branch to which it
would be constrained.

20
User types
A user’s type defines the set of permissions and capabilities that he has in working
with eFrontPro. You have the option to fine-tune the permissions of the built-in
user types (Administrator, Professor and Student) or add new user types based
on the existing ones.

The set of permissions and capabilities that you can fine-tune includes whether
the user type can view or edit other Users, Courses, Lessons, Groups, Branches,
Skills, Announcements, Themes, etc.

The User Types section shows a tabular listing of the available user types, and
provides buttons to edit an existing user or add a new one.

To add a new user type, click the “Add User Type” button, enter a new name for
the new type (e.g. “Admin Helper” or “Course Manager”), select an existing user
type it will be based on, and configure his permissions.

Mini How-To: Editing a User Type

Creating or editing a user type mostly concerns changing his permissions.

The three built-in user types (Administrator, Professor (Instructor) and Student) can
serve as the templates to base your custom user type permissions on, by selecting
the “Basic User Type” for your user type (note that this will change the permissions
of your user type to the ones that the basic user type has, so it’s best to only do it
when you begin editing a new user type, to avoid losing your changes).

21
Permissions are applied to eFrontPro’s entities, such as courses, lessons, users,

groups, jobs, branches, etc, and can be “Disabled” (not applicable to this user),
“View” (user can view this item), “Edit” (user can view and edit this item’s
properties) and “Add/Edit” (user can edit this items properties and create new
items of the same kind).

Thus, a user with the following permissions:

- Can Add, View and Edit (Add/Edit) Courses.

- Can View and Edit Users, User Types, Branches and Jobs, (“Edit”)

- Doesn’t have access to view or Edit Categories (“Disabled”)

Note that if you can “Edit” an item, it is implied that you can also “View” it (but
not the reverse).

22
Audiences
Audiences allow you to divide your users into logical groups based on certain
conditions (“Rules”), such as the Branch they belong to, their Job Position, their
User Type, or custom criteria (the values of custom “Extended Fields” you might
have defined for them).

The Audiences section shows a tabular listing of the audiences you have
defined, allowing you to edit, delete or activate an existing audience or add a
new one.

To add an audience you click on the “New Audience” button, and enter the
name and an optional branch and description for your new audience.

After you created an Audience, you have the option to edit its rules in the “Rules”
tab, and see a listing of the users matching this Audience in the “Users” tab.

Mini How-to: create a new Audience based on rules

To create a new Audience entry, click on the “+ New Audience” button on the

Audiences section. You’ll need to enter a name for the Audience, and specify
an optional Branch and Description. Finally, you can set it to active (default) or
not. When finished, click “Submit” to create your new Audience entry.

After you have created your Audience you get to specify the rules for it. You
can select one or more Branches, Job Positions and User Types to have the
Audience automatically match the users fitting those criteria.

23
You can also specify specific users to be included in the Audience, or use
Extended Criteria, which are custom fields you can specify for your users
(consult the Extend Profile chapter for how to create and manage them).

The Users tab of your Audience will show you a listing of all the Users that your
rules matched.

24
Locations
Locations are names of venues (real of virtual) that classes or meetings will take
place, allowing you to organize your class schedule and inform your students of
upcoming meetings. Locations are especially useful in a hybrid-learning
scenario.

The Locations section shows a tabular listing of all locations, with their short-code,
time zone info and whether or not they are virtual or physical places. Buttons
allow the user to edit or delete an existing Location as well as add a new one.

To add a new Location, click the “+ Add Location” button and enter the name
and the (optional) Branch that the Location applies to.

You can also configure a set of advanced settings, such as the Location’s virtual
or physical status, its address down to the room number (for physical venues), its
time zone and the assigned contact person(s).

25
Themes
Themes allow you to change the layout and look of your e-learning content. You
can have a default look and also define a different look for each of your
Branches.

The Themes section shows two tabs, one for the “Layout” and one to “Change
Theme”.

The “Layout” allow you to define the contents of the page, including what blocks
are shown and in what order. A block, in eFrontPro lingo, is any separate
rectangular page entity, such as the Calendar view or the Announcements list.

The “Change Theme” tab shows a listing of installed themes, and allows you to
edit existing themes or install new ones.

To install a new theme click the Install Theme button, and enter the name of your
theme, an optional branch it will be applied to, and the CSS code with the styling
directions (colors, backgrounds, fonts etc.) for your theme.

Each Branch can have its own Layout and Theme.

To learn more about creating your own themes, or customizing an existing one,
visit the How to create a Theme.

26
Notifications
“Notifications” in eFrontPro lingo are the communication emails that are sent
automatically from the system when specific events take place. eFrontPro
comes with a few notifications types built-in, but you also have the option to
define your own notifications. For example you can setup a mail to be sent to a
user after he or she registers for a course. The Notifications section shows a list of
all defined Notifications and the event that triggers them, and allows you to edit,
delete and activate a Notification, as well as create a new one.

To create a new Notification, click the “Add Notification” button and select the
event that triggers the notification (e.g. course completion), the recipients, the
delivery time, the subject and the body of the email that will be send to the user.
You can write anything you want for the body, and there are also several
keywords such as “date” and “recipient’s name” that you can use, which the
system automatically replaces with their proper values.

The Notifications section also contains the “Mail Queue” and “History” tabs,
which show pending and previously sent notification emails respectively.

To learn more about working with Notifications and customizing messages, visit
the How to customize the communication emails chapter.

27
Extend Profile
Profile extension in eFrontPro lingo refers to the act of adding custom information
fields to Users, Courses, and Branches.

For example you could “extend” the user profile to store the user’s age, gender,
country of origin, twitter link, etc.

The extra fields can be used to filter and view reports for users, and are especially
useful in defining dynamic Audiences.

The “Extend Profile” section displays a tabular listing of all defined extended
profile fields, and allows you to edit or delete an existing field or add a new one.

Mini How-To: Add a new User profile field

To add a new field, click the “+ Add Field” button.

On the form that shows you have to add a name for the field (how it will be stored
in the system) and an assorted Label (how it will be shown in the user interface).

Besides those two mandatory fields, there are several more options to set:

- A placeholder text (that will be shown inside the text-entry box to tell the
user what the field is about, e.g. “Insert a telephone number here” for a
telephone field).

- A default value, to be used when the user doesn’t specify a value.

- Whether the field is mandatory (has to be filled) or not.

28
- A field rule, which is a regular expression to validate that the entered
value is correct (a regular expression is a kind of computer code that
can match specific types of text, e.g. web addresses, email addresses,
numbers, alphanumeric sequences, etc.).

- Finally, you can specify the type of the field, with options being a simple
text box (the default, suitable for things like names, descriptions,
addresses and generally any free from text), a yes/no checkbox (e.g.
“Speaks english”), or a dropdown to choose among a list of items (e.g.
“male” or “female”).

29
Languages
The Languages section simply lists the available languages that can be used for
your e-learning content, and allows you to edit a language’s automatic
translations for words in the original to the target language and toggle the
language active or inactive.

30
Reports
Reports in eFrontPro are visualizations of interesting data regarding the system,
the courses and the users.

eFrontPro comes with a variety of pre-defined reports. Upon entering the Reports
section, in the “Systems” tab you’ll see an overview of "events" and activity for
the current day. You can adjust the reference period to yesterday, week, month
and year or set a custom date range.

Other tabs contain reports about Users, Courses, Tests, as well as a “Timeline”
listing of all user actions.

Depending on the report type, you can filter the data based on Branch, User
type, Audience, Group, Job, Skill, etc.

To learn more about how reports enable you perform changes to multiple
viewed items at once, visit the How to work with Mass Actions section.

Mini How-To: working with report Filters


To open the filtering panel, click on the “Filter” button on the top left of a report
view.

There will be different options depending on the current view (Users, Courses,
Tests, etc.), but the functionality is the same. You select and set a list of criteria,
and you filter (“narrow down”) the list of items shown based on whether those
criteria match your filters.

31
For example the default Users tab on the Reports section, displays the list of all
Users.

To see just Users from a specific Branch that also belong to a specific Group,
open the Filter panel, and select the Branch and Group (leave the other options
in their default values), then click “Submit”.

The list will be recalculated to display only the Users matching the criteria you
have set in your filter.

You’ll see grey tags next to the “Filter” button, showing what filters are currently
active. Click on the “X” of a filter tag to de-activate this filter, or the single “X” next
to the filter button to discard all active filters.

32
Maintenance
The Maintenance section has some infrequently used items, such as buttons to
import data from CSV (e.g. to transfer users, courses, branches etc from another
system or database), to enter your registration key for eFrontPro (so you can
activate the product and receive updates) and to see the web server’s and
PHP’s status.

The available actions are:

Import from CSV


Let’s you mass import Users, Courses, Sessions, Branches, Jobs, Skills, and other
system types from a comma separated value (CSV) file directly into the LMS.

You have the option to merge or ignore entries already existing on the system
(duplicates).

Registration
Here you can enter and view your license key, and related details about your
installation (version number, activation date, expiration date, etc).

Information
Displays information about your installation environment (OS, PHP settings,
database, file system permissions, etc.), the PHP-Info table (a PHP diagnostic
tool that displays all PHP related information), and information about the system
cache.

33
Discussions
The Discussions section shows a list of all available “discussions” (eFrontPro lingo
for a simplified discussion forum) and the number of discussion topics (or threads)
that each contains.

For each discussion you can view and delete its topics, and add new ones. To
add a new topic for a discussion click the “Start new discussion” button and enter
its title.

Archive
The “Archive” is eFrontPro’s “recycle bin”, allowing you to see deleted Users,
Lessons and Courses and permanently delete them or restore them.

Plugins
Plugins are packaged pieces of functionality that extend eFrontPro’s
capabilities. An example would be the “LandingPage” plugin, that adds the
ability to show a custom introductory front-page to the user after he signs in.

The Plugins section shows a tabular listing of the installed plugins, and allows the
user to view their description, configure them, delete them or export them. It also
provides the option to install a new plugin or update an existing one.

To install a new plugin you click the “Install plugin” button, and specify the plugin
installation file and whether it should overwrite (upgrade) any existing plugin with
the same name.

34
To learn more about installing, editing and even creating your own plugins, visit
the Appendix 1: eFrontPro Plugin Guide.

eCommerce
The eCommerce section is divided in several sub-sections allowing you to
configure and manage your paid-for courses.

The “Transactions” sub-section displays a historical view of transactions, listing the


user who made the transaction, the amount paid, and the transaction’s status.

The “Price Tracks” sub-section allows you to set special offers such as discounts
and premiums for specific date ranges and specific Courses, Sessions, Audiences
and Branches.

The “Booked Seats” sub-section allows you to set the number of pre-made
bookings for a session (for sessions with limited seat availability).

The “Balance” sub-section shows a tabular listing of the balance of your students
(i.e how much money they have left to purchase lessons and sessions).

The “Settings” sub-section allows you to configure all the aspects of your
commercial e-learning offering, such as the currency used, the payment
gateway etc.

35
System Settings
The System Settings section allows the administrator (or a user with suitable
permissions) to configure all aspects of the system’s operation.

The Settings section is divided into several sub-sections, which are as follows:

The “Identity” sub-section allows you to define the site’s identity (URL, motto, title
etc.).

The “Locale” sub-section lets you set the locale, default language and time zone
of your service.

The “Logo” sub-section allows you to upload a logo to brand your LMS platform.

The “Limits & Debug” sub-section allows you to set some esoteric PHP options.

The “Security” sub-section allows you to control access to the service (e.g. by IP),
define password length and format policy, etc.

The “Users” sub-section allows you to toggle the ability for Users to self sign-up, to
setup a license note to display on the site, toggle mapped accounts, and set
the username format.

The “Email” sub-section allows you to configure the SMTP server for sending
emails (such as notifications).

The “LDAP” and “SAML” sub-sections allows you to configure authentication


methods (against an external authentically provider) and setup single-sign-on
(SSO).

The “Payments” sub-section allows you configure course payments (set the
currency, base price, cancellation policy, etc) as well as setup the payment
gateway (currently only PayPal is supported).

36
Instructor

Dashboard
The instructor dashboard is divided in two columns. The main column on the left
displays a listing of all the courses you own as Instructor (*), and allows you to
view, edit or view reports for any of them. Note that when you add a course you
become its owner, and you can still manage a course you have created even if
you stop being an Instructor for it.

The right column shows you your profile picture, a calendar with upcoming items
highlighted, and a Tools palette.

The tools palette contains links to add your Group Key, see the full Course
Catalog, manage Discussions and view Courses. If you have plugins installed, this
is the place they install icons that let you configure them.

(*) If you also have courses assigned to you as a Learner, they won’t be shown
on this screen unless you switch to Learner mode. This allows you to experience
how your courses look and feel like when accessed from your students.

37
Course screen
The course screen (shown after you right click and select “Edit Course” on any
of the courses you own) includes a variety of tools to manage your courses.

From the “Properties” tab you can change the course’s settings, such as name,
avatar, category, type and description. There are more options that can be set
for a course if you click to open the “Advanced Settings”, such as its price (if you
want it to be a paid course), whether the course will offer a certification to those
who have completed it (as well as the certification’s duration), the intended
audience and language, and the branch (department) that offers it. A course
code can also be set to help users quickly and uniquely identify the course.

The Lessons tab displays a listing of the lessons contained in the course, and
allows the user to create new lessons assigned to the course, set the lesson order
and configure whether or not the students have to complete lessons in order
(“Serial rule enabled/disabled”). The lesson list can be downloaded as an Excel-
compatible CSV file.

The Users tab displays a listing of the users associated in the course, as either
Professors or Students and their registration date. For each student, the Users
listing also displays his course completion date, what his score was and whether
he was awarded a certificate. This information can be downloaded as an Excel-
compatible CSV file.

Finally, the Skills tab shows a listing of skills associated with the selected course.
A “skill” describes a specific knowledge or experience that is either Offered by
the course (meaning that students who complete the course are assigned that
skill) or “Required” by the course (meaning that students need to have that skill,
perhaps by completing another course offering it, in order to take the course).
The listing of skills can be downloaded as an Excel-compatible CSV file.

38
Lesson screen
The Lesson screen is shown when you click on a specific lesson shown under a
course you own, or click the arrow icon (“take to lesson”) in the Lessons’ listing.

In this screen you can see the lesson’s content as well as an “Options” panel,
with tools allowing you to add more Content, manage Tests and Completion
Conditions, upload Files, monitor Attendance and Progress, and configure
several other lesson settings.

eFrontPro supports a number of different content types such as Text, URLs and
Files. To add a new content unit, you click on the “Add Unit” button, and enter
a name, the content’s source (e.g written on your own in the editor or taken from
a URL), and content.

If you are uploading a file, the system will detect its type and present it in the best
possible way. For example, images will display embedded, videos in a video
player etc. SCORM 1.2 files will be directly imported and made ready for delivery.

You can also set a completion method, such as “button” (the lesson is
considered “read” by the student after he clicks a button), “time” (the lesson is
considered “read” by the student after some specific time has passed), or
“automatic”.

39
The “Tests” sub-section shows you a listing of existing tests, and allows you to edit
and delete them, or add new ones. To add a test you have to click on the “Add
test” button and specify a name and an optional short description.

You can set a number of advanced settings for a test, such as:

1) Test duration: A test is auto-submitted when its duration is exceeded. Leave


this option empty if you do not want a duration for your test.

2) Mastery score: An end user needs to get this minimum to pass the Test.

3) Repetitions: Allow the end use to repeat the test.

4) Shuffle: When set it shuffles (randomizes order) of questions and/or answers.

5) Test password: Require a password to take the test.

6) Submit action: In this option you can define what it happens when the test is
submitted and graded.

The “Questions” tab lists all existing questions you can re-use on your tests, and
allows you to define new ones. A test question can be one of the following types:

1) Empty Spaces (the student has to fill in the missing words in a phrase).

2) Free Text / File Upload (the student uploads a file, e.g an essay in .doc format,
which will be manually graded later). This type of question can also be
automatically graded based on the presence of specific keywords (that
denote correct answers) in the text.

3) Multiple choice (with either a single correct answer or multiple answers)

40
4) Match (the student must match related items)

5) True/False (the student must determine if the statement provided holds or


not)

6) Drag and Drop (a variation on the Match question type).

A newly added option for test questions is the “random” type enabling you to
create randomized tests.

A “random question” entry represents a pool of questions.

You can add as many as you want to the pool, and you get to specify how many
questions you want displayed when the “random question” entry is added to a
test.

For example, if you have added 20 questions to a “random question” entry and
you have specified 3 of them to be shown, a user taking a test containing that
random question entry will have to answer 3 questions randomly selected
among those 20.

eFrontPro intelligently and auto-magically displays the questions, randomizing


the choices as needed, and (with the exception of the Free Text / File Upload
type) grades the answers.

The “Completion Conditions” sub-section allows you to set a number of


conditions under which eFrontPro will consider the course as “completed” by a
student. Those can be:

1) Complete all units (making all content units mandatory)

2) Completed a specific unit (making one or more units mandatory)

3) Completed all tests

41
4) Completed a fraction of the units

You are allowed to mix and match conditions, e.g include several conditions
requiring different specific units, and even specify if all the conditions should be
met (AND) or just some of them (OR).

The “Files” sub-section allows you to upload files such as Word, PowerPoint, PDF,
audio and video items for the lesson’s content.

The “Attendance/Progress” sub-section shows attendance and progress


statistics for the students taking the course, and allows you to set a student’s
grade manually and see a report on his progress.

Finally, the “Administration” sub-section allows you to set various properties of the
lesson, such as calendar notifications, adjust its content tree and order, and the
toggle the ability to read it when offline.

Group key
The Group key sub-section allows you to enter the group key you have been
given to automatically subscribe to your group and be assigned any classes set
for that group.

Course catalog
The course catalog displays a listing of all the existing courses (as opposed to just
the ones you own or manage). A blue badge is shown to mark courses you own.

42
43
Discussions
The Discussions section shows a list of all available “discussions” (eFrontPro lingo
for a simplified discussion forum) and the number of discussion topics (or threads)
that each contains.

For each discussion you can view and delete its topics and add new ones. To
add a new topic for a discussion click the “Start new discussion” button and enter
its title and a short message to be shown to participants.

Courses
The Courses section (selectable from the Options box on the right) allows you to
see all courses you manage in a tabular listing with buttons to edit or delete a
specific course, and contains a search box for quickly finding the course you
want to view or edit.

After selecting a course, you can view or edit its Properties, Lessons, Users and
Skills, through the respective tabs, with the same behavior as described above
for the “Course screen”.

44
Learner

My courses
Your dashboard includes an overview of the courses you’re taking. Courses you
have completed are marked as such, and display a certification badge if you
have been awarded any certifications for their completion.

Click on the name of a course to start or resume it.

Course view

When you select a course you go directly to the course view mode and have
the option to start it (if it’s the first time you open it) or resume from the last seen
unit.

45
A progress bar in the “Content” block displays your overall progress within the
course.

You can complete a course/lesson’s “units” via various actions; including clicking
on a “complete course” button, answering a question or spending a minimum
elapsed time. Depending on the traversal rules set for course might necessitate
to complete units in a serial order. Each course has a course completion rule
(e.g., complete a specific test or complete all units). When you complete a
course a popup will appear with your options for the next step, which may
include proceeding to the next course or download a certification.

Course catalog
The course catalog displays a listing of all the existing courses (as opposed to just
the ones you are subscribed to). A blue badge is shown to mark courses you’re
talking.

Discussions
The Discussions section shows a list of all available “discussions” (eFrontPro lingo
for a simplified discussion forum) and the number of discussion topics (or threads)
that each contains.

For each discussion you can view and delete its topics and add new ones. To
add a new topic for a discussion click the “Start new discussion” button and enter
its title.

46
Generic
In this section we’re going to describe some common UI elements shown to all
user types.

Personal info
From the header you have direct access to your account and the status of your
learning.

From the drop-down list showing your account name you can edit your account
information, see your progress reports, your e-commerce transactions and
balance, and view/edit/add any mapped accounts you might had

Depending on the type of your account you may also have options to switch
between different user modes; these can include the Administrator, the Instructor
and the Learner.

Messages
You can send private messages to other users using the Messages function. The
recipients can be specific users or users involved to specific courses, groups or
branches.

The administrator can communicate with every group and branch of the system,
while a simple user can communicate only with users that share common groups,
branches, courses etc. This behavior is controllable from the user-types (available
only to admins).

The Messages section displays your Incoming messages along with their status,
as well as a second tab (“Sent”) with a list of messages you have send.

Mini How-to: sending a private Message

To send a new message go to the Messages section and click the “+ New

Message” button, or click the “Messages -> Compose” menu on the top header
bar.

47
You have to specify the recipient (which can be multiple users, and even whole
Courses or Groups, if you are allowed to message them), the subject that will be
shown, and enter your message.

You are also allowed to include an attachment in your message (e.g. to send
some supplementary course material to some student, or your homework to your
instructor).

When you’re done click “Send Message”.

48
Search
The search box allows you to quickly find relevant courses, lessons, messages and
more.

Search suggestions are autocompleted against the available LMS content, and
are grouped depending on their type.

Note that there is no result-listing page, matching results are shown as


autosuggestions in the search pop-down.

When you hit ENTER having selected a suggestion entry, you’re taken directly to

that entry’s page.

Logout
Ends your current session and logs you out of eFrontPro.

49
Technical Topics

Installation details and considerations

Hardware Requirements

There are no limits on the type of hardware used to host an eFrontPro installation.
However, as your needs grow, so will the need for additional resources. A simple
eFrontPro installation requires about 50M of free disk space and 64M of free
system memory. However, a minimum of 128M free memory available to PHP is
recommended. Disk space should be allocated according to usage

Software Requirements

eFrontPro requires an environment running the following:


 PHP version 5.5+
 Mysql Server 5+
 Web server (Apache 2+ recommended for Linux systems, IIS for Windows
servers)
 eFrontPro may be installed either on a Windows or on a Linux
environment. However, if you are going to use non-latin language
settings, linux is preferred over windows due to the latter's poor support
for UTF-8 filenames
 It is strongly recommended to employ a PHP caching backend, such as
APCu and Wincache (for windows)
 Apache's mod_rewrite should be available and enabled.
 .htaccess overrides should be enabled for the virtual host

Setting up Apache/Mysql/PHP (AMP)


Before you proceed with installing of eFrontPro, you have to make sure that you
have a running Apache/Mysql/PHP environment. There are bundles that can
ease this procedure, such as Wampserver and XAMPP

Preparing eFrontPro setup


1. Uncompress eFrontPro files to a system folder, for example C:\efrontpro
or /var/www/efrontpro
2. Create a virtual host in your web server, having a document root
pointing to the above directory's www/ folder, for example
c:\efrontpro\www or /var/www/efrontpro/www
3. Give write permissions to your web server for the `efrontpro` folder. At
minimum, the web server must have write access to www/content/,
www/plugins/, upload/, backups/, temp/ and to libraries/ for the

50
duration of the installation (in order for the configuration file to be
created)

Installing eFrontPro using the web interface wizard


1. Point your browser to your virtual host's homepage, for
example http://efrontpro.example.com
2. Click the «Install» button and fill in the required database and user
information. Click on submit.
3. That's it! You're now signed in as the administrator account, have fun!

51
Upgrading
Upgrading eFrontPro is easy and does not require any special action, nor incurs
any downtime

1. Download the latest available eFrontPro package.

2. Extract on top of your current installation, making sure that existing files
are replaced.

3. Make sure that required write permissions have not changed.

4. Visit your eFrontPro installation and sign in as administrator. Any required


database upgrade will happen automatically and you may continue
using the system. Users will not experience any disruption whatsoever.

It is important to note that during the upgrade process, an automatic backup


takes place. If your data volume is rather high, you may wish to disable this
behavior, see the option “Backup before upgrade” in System Settings.

52
System Architecture
eFrontPro is a client-server web application, designed to be delivered in a
browser using the HTTP protocol. The client side is implemented using HTML,
Javascript and CSS, and the server side is mainly written in PHP.

The server-side architecture follows the MVC pattern, which imposes a 3-way
division of the application logic: The Model represents real-world entities and
relationships; The View implements the user interface of the application; and the
Controller binds user interactions with models to perform operations.

All data are stored inside a RDBMS system. The platform communicates with it
using a Data Abstraction Library called Adodb.

In addition to the traditional client-server interface, eFrontPro offers a server-to-


server interface, implemented via a REST API. This allows any 3rd party
application to exchange data with the system, provided that it is equipped with
a proper API key.

53
54
How to secure your environment

eFrontPRO employs elaborate filters to mitigate various kind of attacks, such as


XSS, CSRF, SQL injection and others, based on The Open Web Application

Security Project guidelines. In addition, the codebase employs various measures


in its logic to prevent unauthorized access and privilege escalation.

However, no application can ever be 100% secure. The following tips will help
you keep your environment safe:

 Remove write access for the web server for any files and folders that the
system does not require write access to. See Maintenance for a list

 Make sure that the system where your web and database servers are
installed is always up-to-date. Use the latest release of a PHP version that
is supported.

 Anyone with administrator level access in your eFrontPro can install


programs using the “Plugins” option. Disable it for administrator users that
will not be installing plugins (using custom user types)

55
Performance Tips
eFrontPro is designed to deliver fast performance and scale graciously with
increasing load. However, there are a few tips that can moderately or greatly
increase performance:

1. Install a user-caching engine: eFrontPro requires PHP 5.5 which by default


comes with an embedded opcode caching engine. However, installing
an usercache engine, such as APCu or Wincache (for IIS) can have a
tremendous effect in performance, since eFrontPro makes heavy use of
them, when available. Suggested allocated memory size is
between 64MB to 128MB. You can check to see if any of these engines
are already installed under Maintenance.

2. Enabling Mysql Query Cache will reduce the load on the Mysql Server and
consequently the time it takes to serve a request. In order to see whether
mysql query cache is enabled, visit the Maintenance page.

56
How to create a Theme
eFrontPro's look and feel is based on Bootstrap 3, but can be customized by using custom
themes. All installations come with a collection of pre-installed themes, available to use or
customize to anyone's needs. Theme customization is solely based on the use of CSS and
optionally Javascript code. Below we will share some tips on how to quickly put together a
theme that is suitable for your use case.

Setting Basic colors


To change the overall background, style the body element:

body { background: #d9e5aa; }

Using a background image


You can set a background image as your site's background, using the image's URL (the
image must be accessible via the web).

body {
background-image:url('https://c626fd9a3ea7d7aaf25a-
13df01e1540c03f09828a4c08555f8b9.ssl.cf2.rackcdn.com/back13.jpg');
opacity:0.9;
background-size:cover;
}

Increase or decrease the opacity to determine how opaque your background will appear.

Customizing Fonts
Set a font-family style to your body element, to change the font used throughout the platform:

body { font-family: 'Open Sans', sans-serif; }

57
Changing Blocks
Blocks are the main container element used throughout the system and you can customize
any aspect you wish. Below you can find some basic examples:

/*Box Titles*/
div.block .title {
background:#FFF;
border: 4px solid #ccc;
border-bottom: 0px;
position: relative;
top: 8px;
}

/*Box Content*/
div.block .content {
border: 4px solid #ccc;
box-shadow: 0 1px 1px rgba(0,0,0,0); /*shadow*/
border-radius: 8px;
}

/*Handle in a different way blocks within a block*/


div.block div.block .content { border: 0px; }

/*Hide top left radious when then block has a Header*/


div.block .blockHeader ~ .content {
border-top-left-radius: 0px;
}

/*Consistency with toolbars*/


div.block .toolbar {
border: 4px solid #ccc;
border-bottom: 0px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}

/* Hide radious on box after a toolbar*/


div.block .toolbar ~ .content {
border-top-left-radius: 0px;
border-top-right-radius: 0px;
border-top:0px;
}

Changing Grids
Grids are the tables listing users, courses etc. You can customize their look and feel via css
using classes similar to the example below:

58
/*Grid table*/
table.sortedTable {
background-color:#d9e5aa;
top: 2px;
border-radius:4px;
}

/*Odd rows*/
tr.oddRowColor {
background: #e9f5ca;
border-bottom: 1px solid #D0D0D0;
border-top: 1px solid #D0D0D0;
}

/*Even rows*/
tr.evenRowColor {
background: #edf9da;
}

/*On hover above row color*/


tr.oddRowColor:hover, tr.evenRowColor:hover {
background: #C7D7F3;
}

/*Grid footer*/
td.sortedTableFooter {
background-color:#d9e5aa;
}

Customizing the navbar and breadcrumb


The navbar is the horizontal bar appearing on top of every page. The breadcrumb bar is the
path row right below the navbar. Customizing these is easy, as can be seen in the examples
below:

/*Navigation bar color*/


.navbar-inverse {
background: #d7e7d5; /*Background color*/
border:0px;
}

/*Breadcrubs external layer*/


.breadcrumb-x {
background: #81CF81; /*Background color*/
border-bottom: 2px solid #3B993B;
border-top: 2px solid #3B993B;

59
}

/*Breadcrumb internal layer*/


.breadcrumb {
background: #81CF81; /*Background color*/
color:#FFF;
}

/*Breadcrumb separator*/
.breadcrumb > li + li:before { color: #000; content: "\003e"; }

Changing buttons
Most of the buttons in the system bear the “primary” class, thus you can alter them as follows:

/*Main button color*/


.btn-primary {
background-color: #3B993B;
}

/*Main button hover color*/


.btn-primary:hover {
background-color: #0D5F0D;
}

60
How to customize Certifications
It is important to have a well designed appealing certificate. In this section, we will figure out
how to draw lines, display pictures, set background image and insert fields within the
certificate.

The example XML schema below specifies where elements of the certificate will appear.
Next we will look at each of the elements and explain their properties.

<?xml version="1.0" encoding="utf-8" ?>


<certificates>
<certificate>
<organization text="eFront" font="Freeserif" weight="bold" size="60"
color="#005b7f" x="120" y="13"></organization>
<student font="Freeserif" weight="" size="35" color="#000000" x="5"
y="95" align="center"></student>
<course font="Freeserif" weight="" size="28" color="#000000" x="5"
y="133" align="center"></course>
<grade font="Freeserif" weight="bold" size="28" color="#000000"
x="160" y="150" align="center"></grade>
<date font="Freeserif" weight="" size="15" color="#575757" x="225"
y="182"></date>
<serial font="Freeserif" weight="" size="14" color="#575757" x="107"
y="182"></serial>
<logo file="default" x="14" y="14"></logo>
<background file="medium.png"></background>
<orientation name="landscape"></orientation>
<creator name="eFront"></creator>
<author name="eFront"></author>
<subject name="Certificate for "></subject>
<keywords name="This is a list of keywords"></keywords>
<labels>
<label text="NOT JUST ANOTHER ELEARNING COMPANY" font="Freeserif"
size="20" color="#000000" x="80" y="41"></label>
<label text="We Make e-Learning Special" font="Freeserif" weight=""
size="18" color="#000000" x="110" y="51"></label>
<label text="Certificate of Achievement" font="Freeserif" weight=""
size="35" color="#000000" x="80" y="67"></label>
<label text="This Certificate is Awarded to:" font="Freeserif"
weight="" size="24" color="#000000" x="97" y="82"></label>
<label text="For the successful completion of:" font="Freeserif"
weight="" size="22" color="#000000" x="95" y="120"></label>
<label text="With grade:" font="Freeserif" weight="" size="22"
color="#000000" x="120" y="152"></label>
<label text="Instructor" font="Freeserif" weight="" size="10"
color="#000000" x="20" y="192"></label>

61
<label text="Serial Number" font="Freeserif" weight="" size="10"
color="#000000" x="110" y="192"></label>
<label text="Date" font="Freeserif" weight="" size="10"
color="#000000" x="200" y="192"></label>
</labels>
<lines>
<line x1="5" y1="5" x2="292" y2="5" color="#005b7f" thickness="2"
note="Top Thick"></line>
<line x1="292" y1="5" x2="292" y2="204" color="#005b7f"
thickness="2" note="Right Thick"></line>
<line x1="5" y1="204" x2="292" y2="204" color="#005b7f"
thickness="2" note="Bottom Thick"></line>
<line x1="5" y1="5" x2="5" y2="204" color="#005b7f" thickness="2"
note="Left Thick"></line>
<line x1="7" y1="7" x2="290" y2="7" color="#005b7f" thickness=".25"
note="Top Thin Border"></line>
<line x1="290" y1="7" x2="290" y2="202" color="#005b7f"
thickness=".25" note="Right Thin Border"></line>
<line x1="7" y1="202" x2="290" y2="202" color="#005b7f"
thickness=".25" note="Bottom Thin Border"></line>
<line x1="7" y1="7" x2="7" y2="202" color="#005b7f" thickness=".25"
note="Left Thin"></line>
<line x1="17" y1="190" x2="97" y2="190" color="#000000"
thickness=".25" note="Signature Line"></line>
<line x1="107" y1="190" x2="187" y2="190" color="#000000"
thickness=".25" note="Serial Line"></line>
<line x1="197" y1="190" x2="277" y2="190" color="#000000"
thickness=".25" note="Date Line"></line>
</lines>
<images>
<image file="certificate.gif" x="238" y="14"></image>
<image file="signature.gif" x="18" y="176"></image>
</images>
</certificate>
</certificates>

 creator: is used to populate the creator for the PDF document header (it does not
appear on the document).
 author: is used to populate the author for the PDF document header (it does not
appear on the document).
 subject: is used to populate the subject for the PDF document header (it does not
appear on the document).
 keywords: is used to populate the list of keywords for the PDF document header (they
do not appear on the document).
 organization: is used to display the organization name on the certificate.
 student: is used to display the name of the student on the certificate.

62
 course: is used to display the name of the course on the certificate.
 grade: is used to display the overall grade of the course on the certificate.
 date: is used to display the date the certificate was issued.
 serial: is used to display the serial number of the certificate.
 logo: is used to display the logo image on the certificate. You can either display the
default logo of your eFront installation or an external image, by supplying its URL.
 background: is used to display a background image on the certificate. The
medium.png file corresponds to the background image of the Medium Decoration
template. Also, the heavy.png file corresponds to the background image of the Heavy
Decoration template. Apart from these background images you can display an external
image, by supplying its URL. Image width should be equal to 840 pixels.
 orientation: is used to define the page orientation.
 label: a label is a line of text that will appear on the certificate. A label element must
appear within the labels section. You can add any number of labels as needed.
 line: a line is a graphical line that is drawn on the certificate. A line element must
appear within the lines section. You can add any number of lines as needed.
 image: an image is a graphic that will appear on the certificate. An image must appear
within the images section. You can add any number of images as needed.

Properties for student, course, grade, date, serial and organization elements

Property Description
font Name of the font to use.
weight The font weight. Possible values: bold, italic, bold|italic. For normal font, leave the value
empty.
size Size of the font to use.
color Hex value for text color (i.e: #000000 is black).
x X coordinate.
y Y coordinate.
align The text alignment. Possible values: center, left, right.
text Text to appear on the certificate. It applies only on the organization element.

Properties for creator, author, subject and keywords elements

Property Description
name The value that will appear in the PDF document header.

63
Properties for image, logo and background elements

Property Description
file Name of the image to use or the URL of an external image.
x X coordinate. It applies only on the image and logo elements.
y Y coordinate. It applies only on the image and logo elements.

Properties for orientation element

Property Description
name The page orientation. Possible values: landscape, portrait.

Properties for label elements

Property Description
text Text to appear on the certificate.
font Name of the font to use.
size Size of the font to use.
weight The font weight. Possible values: bold, italic, bold|italic. For normal font, leave the value
empty.
color Hex value for text color (i.e: #000000 is black).
x X coordinate.
y Y coordinate.
Properties for line elements

Property
color Hex value for line color (i.e: #000000 is black).
note A note for user reference. It does not appear on the document.
thickness The line thickness (i.e: Thin: .25, Thick: 2).
x1 Starting X coordinate.
x2 Ending X coordinate.
y1 Starting Y coordinate.
y2 Ending Y coordinate.
Templates with two or more pages In case you would like to have a certificate with more
than one page you should include each page within a <certificate> tag. You should include
all the properties for creator, author, subject and keywords within your first <certificate> tag

64
and you do not need to repeat them again in your second (or third…etc) <certificate> tag.
For example

<?xml version="1.0" encoding="utf-8" ?>


<certificates>
<certificate>content of page 1</certificate>
<certificate>content of page 2</certificate>
</certificates>

65
Frequent Questions

How to assign a set of courses to new users directly


As an LMS instructor or administrator you’ll often find yourself in the need of
making changes to multiple entities (students, lessons, etc) at once.

You could of course do all those changes manually, one by one, but eFrontPro
provides powerful tools to automate your workflow.

The most common use cases for this would be assigning a set of courses to new
users when starting a new e-learning program (e.g. at the start of a semester).

To automate this action, as with many student related actions, you can use
eFrontPro’s “groups” functionality.

As discussed in the relevant section, groups help you organize users into logical
sets, allowing you to treat all of them as a single entity. Actions performed to the
group can be applied by eFrontPro to each and every member of the group.

Specifically, a group comes with mass actions to synchronize its users with its
courses.

Let’s walk through the mass assignment of a set of courses to a number of users.

(1) In the eFrontPro UI, click to visit the Groups section. A tabular listing of all
existing groups will be shown, along with an “Add Group” button allowing you to
add a new group.

(2) Click to add a new group. Enter a name for the group (e.g. “class of 2015”)
and optionally select a branch the group will belong to or enter a short
description.

(3) Click to save your new group, and select the newly created group. There are
links to see the list of Users and Courses assigned to it. Begin by assigning the users
you want to the group. Then assign a number of courses to the group.

(4) The final step is to click to enroll all of the group’s users to the group’s courses

(eFrontPro doesn’t perform this automatically behind your back, to give you the
ultimate flexibility to handle it however you like).

Voila: the group’s users are now enrolled to the specified courses without you
having to manually assign each user.

66
How to offer Compliance Training
When a business operates within certain markets or competes for public sector
tenders, compliance with industry standards, laws and regulations is often
necessary. eFrontPro is a great tool for implementing compliance training for
your employees (or even the general public).

In their essence compliance training courses are similar to all other courses. The
main difference is that their content is detailed and outlined exhaustingly in the
relevant standards and laws, and thus they result in a very specific “skill” or

“knowledge set”. You can model this kind of learning in eFrontPro using
certifications.

Since certifications in eFrontPro are awarded upon the completion of a course


or a course curriculum, a user being awarded a certificate for his participation
in a compliance course or curriculum means he has completed his compliance
training successfully.

Since compliance certificate holders are often obliged by law or company


policy to periodically refresh their compliance training, eFrontPro supports time-
limited certificates.

The way this feature works is that the user sets an (optional) duration for the
certificate (e.g. 6 months), and eFrontPro automatically expires the certificate
after that interval passes.

You can even indicate that you want to reassign the course that the certificate
was assigned from, upon its expiration, or N days prior to expiration, and have
eFrontPro re-enroll the students automatically. When that happens, the course’s
progress for those users is reset, and they have to complete it again to get re-
certified.

The certificate expiration settings in the Course properties view

Certificates in eFrontPro are created with user-defined templates that are


customizable with your own titles, body text and other details.

From the Certificates section eFrontPro admins can view and edit any defined
certificate templates, and dig in to view the details for each and the courses

67
that award it. (To learn mode about creating and editing certificates, check
the How to customize Certifications chapter).

In the same section, the Users tab displays a listing of all certificates awarded to
your users, the courses they were awarded for and their expiration status.
eFrontPro admins can filter down the user listing and view, edit, and revoke any
particular certification they wish.

68
How to customize your learning portal
Branding is an important part of any modern business and eFrontPro was created
with theming and customizability built-in, making it easy to add your own logo,
favicon, custom theme and even custom javascript in your eFrontPro based
learning portal.

To begin customizing eFrontPro, login with an admin account and visit the
“Identity” section, where you can set your custom domain, as well a your site’s
motto.

Next comes the “Appearance” tab. From there you can start by picking a logo
and favicon from your computer.

It is advisable that the logo is 72 pixels high, while width can be up to 500px, and
that it’s selected to match your header color. As for the favicon (the small icon
that represent your page in the browser taskbar or bookmarks listings), it has to
be square, and will be displayed in a 16x16 resolution by most browsers.

Custom theme settings have their own section, aptly named “Themes”.

In the Themes page you can see the visual layout of eFrontPro, and drag and
drop page building blocks (such as the Catalog, the Sign in panel, etc.) to create
the layout you want. You can also add your own custom blocks to the layout,
e.g. a panel displaying a welcome message, ads, custom widgets, etc.

For ultimate flexibility, eFrontPro allows you to define a custom layout of each
branch of your e-learning service.

Themes sit on top of a layout, and define the various colors, fonts, backgrounds
etc. that the layout is displayed in (if you’re confused think of it like this: the layout
defines the structure of your site – where things are -, whereas themes define its

decoration – how things look -).

You can select between several pre-defined themes or install a new one (even
one that you have created) from the “Change Theme” tab. From the themes
listing you can set the active theme, preview themes, and even edit any theme
(a theme being a set of CSS and JS instructions).

69
How to customize the communication emails
In an e-learning environment that lacks the immediacy of physical interaction,
proper and fast communication becomes profoundly important.

In this area too, eFrontPro has you covered, with automated notifications for any
kind of event (user registration, grades posted, etc.), as well as custom on-
demand messages to any user or group.

Notifications are sent to their recipients as emails, which means that any web,
desktop or mobile mail client can be used to read them.

To create a notification, visit the Notifications section. In there you’ll see a list of

currently defined Notifications, as well as a button to “Add Notification”.

Clicking on “Add Notification” will display a form that you have to fill in to create
a new notification. You get to select the specific event that will trigger the
notification, the recipients (which can be individual users, administrators, course
professors, etc.), the exact time to send the notification when the event is
triggered, an optional branch, a subject (title), and finally the body of the
notification, which is the message that will be shown to the recipients.

Let’s go through a simple walkthrough for how to create a notification. This


assumes you are seeing the “Add Notification” screen. We will create a
notification to be send to course professors every time a student completes a
course.

1) Select an Event that will trigger the notification. We select “User Completed

Course”.

2) On the Recipients control, we select “Course professors”.

3) We enter “User completed course” as the subject (just something to describe


our notification).

4) We select the course that this notification will apply to. For example, “History
101”.

5) We optionally select a branch (a “department” of our e-learning institution)


that this notification applies to. Note that notifications will apply to the branch
and to all of its sub-branches.

6) We add the message we want the recipient to see. We have the option to
create different messages for each language group (English, French, etc

70
students) and to use keywords that will be automatically filled in by the LMS, such
as the date/time, the recipients name, etc.

Let’s write a simple message, such as “Student … completed the course, …., at
….”. To fill-in the blacks, click the buttons below the body field, and automatically

replaceable keywords will be inserted. E.g. clicking the “User’s full name” button
inserts the {user_name} keyword in the notification body. This will be replaced by
the actual student’s name in the message that will be send for each individual
user that completes this course.

This works the same as Work / Excel’s “mail merge” function, in case you’re familiar
with that.

71
What is the difference between Branches and Groups
eFrontPro was designed to offer many ways to customize its operation to cater
how different organizations and businesses operate. To keep all this
customization power simple, we based it on a few key organizational entities,
such as Branches and Groups.

While Branches and Groups might look similar, they serve different purposes and
roles within eFrontPro.

Groups organize users into logical entities, allowing them to treat all of them as a
single entity. You can communicate to the members of a group directly, assign
them courses, and see aggregate reports on all of them. Groups also come with
mass actions to synchronize their users with their courses.

You create groups based on any criteria you like, e.g. “Medical Students”, “Class

of 2015”, etc., and you can assign students and courses to them.

Branches on the other hand allow you to divide your e-learning offering into
different logical units (or “departments”), each with its own courses, users,
professors and branding (sub-domain, theme, logo, etc.). Branches can be a flat
list or form a nested hierarchy.

Branches are a much larger logical entity than groups (a group can belong to a
branch, but not vice versa), and might be overkill for smaller deployments, but
are a good way to separate and customize your e –learning offering for different
company departments, units, geographical sections, etc.

72
How to work with Mass Actions
Mass actions allow you to eliminate repetitive work by automating tasks to be
performed to multiple users (e.g. to all members of a group).

It’s in enabling mass actions that eFrontPro’s organizational units (from groups
and branches to courses and skills) are especially helpful.

Mass actions can be easily accessed from the Reports section, in the “Mass
Actions” dropdown that appears in the Users tab.

To apply a Mass Action, first select the users you want to have it applied. The
default listing in the Users tab shows all Users, but you can narrow it down using
the filter function to select users of a specific Type, Group, Job, Skill, Audience or
Branch.

When you have selected the users you want, you can apply any of the several
mass actions available:

- Enroll them to a specific course

- Un-enroll them from a course

- Add them to a group

- Remove them from a group

- Send them a message

- Deactivate

- Activate

And finally, archive them.

Depending on the action, you will be asked to select a course or group to add
the users to, or to confirm that you want it to go throu.

You can also use mass actions outside of the Reports page. Specifically, mass
action buttons at the Group and Curriculum pages allow you to:

- Add all members of a group to one or more courses (“Enroll members to


courses”)

- Add all members of a group to one or more curriculums (“Enroll members to

curriculums”)

73
How eFrontPro supports Instructor Led Training
We designed eFrontPro as a multi-paradigm LMS, that is, to be able t adapt to
the way you work. It can adapt to small and big teams, local units and
geographically dispersed branches, hybrid remote and classroom-based
learning and to lots of other use cases. One of its core characteristics though is
its support for Instructor Led Training.

Instructor-led training refers to the kind of learning process facilitated by an


instructor, who prepares tasks and learning, uses real-time communication and
collaboration tools, and in general can adapt the course and his delivery based
on his students’ needs. It’s a fuller, interactive e-learning experience, as opposed
to merely making some course content accessible online.

eFrontPro allows for Instructor Led Training and blended learning through its
introduction of the classroom (ILT) course type that takes place in the physical
world but is organized and moderated online. Such a classroom course can
have limited seats, waitlists, meetings and multiple sessions.

Other tools available in eFrontPro that facilitate Instructor Led Training include:

- The instructor user type and related dashboard, that allows instructors to control
their courses and add and edit lessons, tests and multimedia material on the fly.

- Notifications, which allow instructors to be informed in real-time for students’


actions and progress and respond to it accordingly.

- Discussions, the eFrontPro forum system, which allows instructors and students
to discuss, collaborate and provide feedback on their courses.

- The Messages feature that can be used for one-to-one communication


between instructors and students.

- Reports, which give instructors an overview of how their students are doing and
allow them to perform mass actions pertaining to student groups.

- Tele-conference and whiteboard integration, that allows for real-time class


meetings (or personal tutoring).

eFrontPro’s organizational tools, like Groups, Curriculums, Audiences, Skills, etc.,


also help instructors treat multiple students as a single entity depending on
various criteria, making his job easier when he has to manually perform some
action to many of them.

74
How eFrontPro deals with WCAG, Section 508 & ADA
Compliance

The US legislation regarding non-discrimination that is referred to as "Section


508" requires that electronic and information technology that is developed by
or purchased by the Federal Agencies be accessible by people with
disabilities. It is an amendment to the Workforce Rehabilitation Act of 1973.

According to the Section 508 technical standards a web site has to satisfy
sixteen specific items for web accessibility. These are specific things that can be
done during web site development to ensure that a person who is mobility
impaired or blind, for example, can use your site.

508 standards have drawn on the work of the Web Accessibility Initiative (WAI)
of the World Wide Web Consortium (W3C) that has crafted a set of Web
Content Accessibility Guidelines (WCAG). The WCAG guidelines are grouped
by priority and are very similar to those in the final Section 508 rule. The
Americans with Disabilities Act (ADA), which became law in 1990 is a civil rights
law that prohibits discrimination against people with disabilities. The ADA
generally requires employers, state and local governments and places of
public accommodation to offer reasonable services or tools to insure that
people are not discriminated against on the basis of disability.

On eFrontPro we have worked with WCAG-2 guidelines that are web-specific


and (mostly) cover Section 508 and ADA.

Note that there are no related certifications for web-sites and services since
there is no way to make a site 100% compatible with WCAG-2 without
restricting it too much. We can however, reach a level of conformance.

Here are the high-level items on WCAG-2:

1/ Text Alternatives: Provide text alternatives for any non-text content so that it
can be changed into other forms people need, such as large print, braille,
speech, symbols or simpler language.

2/ Time-based Media: Provide alternatives for time-based media.

3/ Adaptable: Create content that can be presented in different ways (for


example simpler layout) without losing information or structure.

4/ Distinguishable: Make it easier for users to see and hear content including
separating foreground from background.

5/ Keyboard Accessible: Make all functionality available from a keyboard.

6/ Enough Time: Provide users enough time to read and use content.

75
7/ Seizures: Do not design content in a way that is known to cause seizures.

8/ Navigable: Provide ways to help users navigate, find content, and determine
where they are.

9/ Readable: Make text content readable and understandable.

10/ Predictable: Make Web pages appear and operate in predictable ways.

11/ Input Assistance: Help users avoid and correct mistakes.

12/ Compatible: Maximize compatibility with current and future user agents,
including assistive technologies.

There are 3 elements that play a role on whether a web platform can meet
those requirements:

- The LMS software. eFrontPro has taken into its design the above requirements
and makes sure that it meets them as good as possible. For example, we offer
alternatives for all images (alt tags), we make no-use of iframes / Java or Flash
and we do not use strictly colors to convey information. We also offer a
consistent navigation to make the system predictable.

- The browser. A modern browser is essential to make a system WCAIG 2.0


compatible. For example, a browser offers tools to navigate a page with the
keyboard, ways to increase/decrease the font-size and help users enter data
to forms.

- The content. Many of the accessibility requirements reside on the content. As


an example, the content must be offered in alternative ways to cover different
disabilities and it also needs to be adaptable.

76
How to integrate eFrontPro with your system
eFrontPRO provides a comprehensive REST JSON API that allows interaction
with remote services. Authentication is based on an API key that is defined
under your installation’s system settings. The functionality provided focuses on
performing tasks meaningful for a remote service, such as user creation, course
assignment, listing courses etc. In addition, one can use the API to provide
basic SSO for users.

To ease implementation of services, we provide a SDK library for PHP that


automates the tasks of communicating with the API. The first part of this guide
provides a detailed description of the available API calls, as well as information
on authentication and error handling. The second part of the guide
demonstrates the use of the PHP SDK, providing information on setting it up and
performing some basic tasks.

You can download the eFrontPro SDK and read the related documentation on
GitHub.

77
How to work with content conversions
eFrontPro integrates with the EncodeMagic service to offer seamless,
automatic conversions of various file types to a web-friendly format, ensuring
that content delivery and compatibility is optimal across a multitude of devices.
Currently most video and audio types are supported, as well as Powerpoint
(.ppt) presentations.

In order to setup the service, you must first obtain an API key and secret from
your vendor. Once you have these, then visit the System settings page, click on
Integrations→EncodeMagic and input this information.

That's it! Next time you upload a video, audio, or document file, it will be sent to
Encode Magic, transcoded on the fly and delivered back to the system. The
whole process usually takes a few minutes, during which the unit will be in a
waiting state. Once it's done, you can visit your content and see the converted
file in action.

78
How to work with Videoconferencing
Discuss the offered video conferencing integrations and how they work

79
Appendix 1: eFrontPro Plugin Guide

Quick start
Can’t wait to start creating a plugin? Read on for a very quick walkthrough on how to put
together a simple plugin in just a few minutes:

1. Make sure you have a working eFrontPro installation, and you have access to its files
(with permission to change them). See Installation for instructions on how to install
eFrontPro.
2. Visit your eFrontPro system, sign in as an administrator and click on Plugins.
3. Click on the Create plugin button. Enter a name1), title and description for your
plugin, for example:
 name: AcmeReports
 title: Acme Reports
 description: This is a fully-functional plugin that is created as part of eFrontPro's
plugin guide.
Now click on Save. You will be redirected to the new plugin’s main page (which is
empty). The “Acme reports” plugin will be visible in the plugins list, where you can
deactivate or delete it.
4. The plugin has been created inside the server that hosts eFrontPro. You can find its
files at the same location where eFrontPro is installed on the disk, under
the path www/plugins/AcmeReports. You have to gain access to these files, in
order to change them according to your needs. You can either:
 Access the files directly on the server, if you have access, and edit them directly.
 Under admin→plugins, click on the download link next to the “AcmeReports”
entry, to download a zip file containing your files. You can then change them at
your local environment; once you’re done, compress them into a zip file and click
on the upgrade icon next to the entry.
Read on for a step-by-step walkthrough on how to create a general-purpose plugin.

Introduction
Creating a plugin can be a simple or complicated process, based on your requirements. We’ll
try to make your life as easy as possible, regardless of whether you’re an experienced or a
new developer. The following guide assumes you have some very basic knowledge of PHP
5. You will also need a working eFrontPro installation. If you don’t have one,
see Installationfor instructions on how to install it. If you don’t have access to a working
eFrontPro installation for development purposes,contact us.

Creating your first plugin


Based on our experience, the majority of the plugins created for an LMS are related to
reports. In this guide, we will walk you through the procedure of creating a plugin that
provides some custom reporting functionality, for a fictional company called “Acme”. Acme
has requested for a plugin that

80
 Reports on the total number of users, courses and certificates
 Presents a list of users that have not used the system recently
 Presents a list of users that have not completed a specific course
 Emails the list to a specified user
 Allows saving and retrieving past reports

Scaffolding
Plugins are always located under the www/plugins folder of your eFrontPro installation. In
general, a plugin can have any file structure its creator wants, but it’s highly recommended
that you follow this structure:

www/plugins/
---- AcmeReports
-------- assets/
------------ images/
---------------- plug.svg
------------ AcmeReportsController.php
-------- i18n/
------------ en_US/
---------------- LC_MESSAGES/
-------- Model/
------------ AcmeReports.php
------------ AcmeReportsPlugin.php
-------- View/
------------ acmeReports.tpl
-------- plugin.ini

Heads up! Don’t bother with creating all these folders and files by hand; Use the “Create
new plugin” option from admin→plugins to have the system create them for you.

Installing/Configuring
A plugin needs to include at a minimum 2 files, one for configuring it called plugin.ini,
and one for running it, called <name>Plugin.php(AcmeReportsPlugin.php in our
example)

Heads up! If you have used the “Create new plugin” button, the files described below are
already created for you, and the plugin is already installed. You can skip directly to Req. 1:
Reports on the total number of users, courses and certificates (but don’t, because it’s worth
reading nevertheless)

The file plugin.ini is used by the system to initialize the plugin. In our case, it should
contain the following:

81
[plugin]
class = Efront\Plugin\AcmeReports\Model\AcmeReportsPlugin
name = AcmeReports ;must match the path name under Plugins
title = Acme Report version = 1.0 ;The plugin version, change when
upgrade is needed
requires = 4.1.0 ;minimum supported eFrontPro version
compatibility = 4.1.0 ;maximum compatible eFrontPro version
author = John Doe
description = This is a fully-functional plugin that is created as part
of eFrontPro's plugin guide

where:

 class is the namespaced class of your plugin main file:


Efront\Plugin\<name>\Model\<name>Plugin, where <name> is your plugin’s name
 Name is the name of the plugin, as identified by the system. This should be a string
with no spaces or special characters
 Title is the plugin title that appears in the plugins list. It can be anything you like.
 Version is the current version of the plugin. It is important to keep your version number
up to date, because automatic upgrading depends on it (see Upgrading)
 Requires is the minimum eFrontPro version that this plugin can run on. If you try to
install it in an older version, an error message will appear.
 Compatibility is the most recent version of eFrontPro that this plugin has been tested
on. You can see your current eFrontPro version under Admin → Maintenance →
Registration.
 Author is the name of the creator of the plugin, you are free to put whatever you like
here.
 Description is a field you can use to describe the intended use of the plugin.

The file AcmeReportsPlugin.php serves as the glue between the core system and our
plugin. It extends the class AbstractPlugin and implements all functions defined in
the Plugin API. For now, we only need the bare minimum for this file, which is to implement
the 3 abstract functions of theAbstractPlugin class. Here is the contents it can have:

<?php namespace Efront\Plugin\AcmeReports\Model;


use Efront\Model\AbstractPlugin;

class AcmeReportsPlugin extends AbstractPlugin {


const VERSION = '1.0';
public function installPlugin() {}
public function uninstallPlugin() {}

82
public function upgradePlugin() {}
}

Heads up! You always have to implement the 3 abstract functions shown above, even if
they’re left empty

That’s it! All we have to do now is to install the plugin into our eFrontPro system (if it’s not
already installed). This can be done with 2 ways:

 Go to Admin → Plugins → Install new plugin, and click to install your plugin, which you
must have compressed as a zip file.

Note that you have to compress the files inside the plugin folder and not the folder itself

 Or copy the plugin files directly to the www/plugins/ folder on the eFrontPro server.
Then go to Admin → plugins and the plugin will appear as “not installed” in the list.
Click on the “plus” icon next to it to install it.

After the plugin is installed successfully, it will display as such in the plugins list. Use the
handles provided to deactivate it, download its files or upload a new version of your plugin.

Accessing the Plugin API


Every plugin can access the Plugin API through its AbstractPlugin inheriting class.
The AbstractPlugin provides a set of methods that are called every time a plugin can be
invoked. For example, when a page starts loading, the onPageLoadStart() method is
called for every plugin. Similarly, when the calendar is calculated,
the onLoadCalendar() method is called, with the calendar entries passed by reference. For
a complete list of available methods, consult the Plugin API Reference section.

Capturing an event
Events are fired throughout the system multiple times during the execution of the script,
for example when a user is created, a course is deleted, etc. A plugin may listen for these
events to perform some action, via the onEvent() method. onEvent() is called for every
event that happens in the system, so the plugin must make sure it picks out the one that it is
interested in and ignores the rest. For example, to perform an action each time a user signs
in or signs out, we would implement onEvent() like this:

public function onEvent(Event $event) {


switch (get_class($event)) {
case 'Efront\Model\Event\UserSignedin':

83
//perform an action for users that signed in
break;
case 'Efront\Model\Event\UserSignedout':
//perform an action for users that signed out
break;
default:
break;
}
}

For a complete list of available Events, see the Event Reference section.

Accessing the Core API


Plugins in eFrontPro are not executed in a “walled garden”; instead, they have full access to
the underlying system and functions. Although a complete reference of the Core API is not
available (and out of the context of this guide), here is a very short list with examples of
performing common operations using the core API:

Get the object of the user currently signed in:

$user = User::getCurrentUser()

Instantiate an object (for example, user with id 321):

$user = new User(321);

Update an object:

$user = new User(321);


$user->setFields(array('email'=>'jdoe@example.com'))->save();

Delete an object:

84
$user = new User(321);
$user->delete();

Query the database:

//Get the users that haven’t signed in for more than a month, order by
last_login column
Database::getInstance()->getTableData(
User::DATABASE_TABLE,
'id,name,surname,email',
'last_login<'.time()-86400,
'last_login'
);

Heads up! Although you can directly update data in the database table, it is strongly
discouraged to do so, because eFrontPro utilizes an automatic caching mechanism, and
directly changing the database will not update cached entries. Always
use $obj→setFields() to change an object’s properties and $obj→delete()to delete an
entry.

85
Setting access links and icons
Our plugin is now installed, but does nothing. Since this plugin will be used by administrators,
we will create a link to its page from the administrator’s dashboard. To do this, we employ
the Plugin API’s onLoadIconList() function, inside the AcmeReportsPlugin file:

Heads up! The […] symbol in any code snippets, refers to code created previously that is
present but has been omitted, for the sake of simplicity.

<?php namespace Efront\Plugin\AcmeReports\Model;

use Efront\Model\AbstractPlugin;
use Efront\Model\User;
use Efront\Controller\UrlhelperController;

class AcmeReportsPlugin extends AbstractPlugin {


const VERSION = '1.0'; [...]
public function onLoadIconList($list_name, &$options) {
if ($list_name == 'dashboard' &&
User::getCurrentUser()->isAdministator()) {
$options[] = array(
'text' => $this->plugin->title,
'image' => $this->plugin_url.'/assets/images/plug.svg',
'class' => 'medium',
'href' => UrlhelperController::url(array('ctg' => $this->plugin-
>name)),
'plugin' => true);
return $options;
} else {
return null;
}
}
}

The snippet above will make an icon appear in the Administrator’s dashboard.

 For determining the current user’s type, see User types and restrictions
 Each plugin can have a page of its own, for example under /AcmeReports.
See Creating URLs on how to define its link, using theURLHelperController class
 Note the 2 use statements we put on top

There are a few “icon lists” like the administrator’s dashboard in the system. Each has its
own distinctive name, which you have to specify in an if clause when implementing
the onLoadIconList() function

86
Creating a dedicated page
Now that we have a link to our plugin’s page, it’s time to create the page itlself. For this, we
will need a few new files:
Model/AcmeReports.php,
Controller/AcmeReportsController.php
View/acmereports.tpl

First, we will create a model class, that will hold the bulk of our implementation. For now,
we’ll leave it to the bare minimum:

<?php namespace Efront\Plugin\AcmeReports\Model;


use Efront\Model\BaseModel;

class AcmeReports extends BaseModel {


const PLUGIN_NAME = 'AcmeReports';
}

Now, we need to tell the system that every time the plugin page is requested, its controller
will be loaded. To do this, we implement the onCtg() method in
ourAcmeReportsPlugin class:

<?php namespace Efront\Plugin\AcmeReports\Model;


use Efront\Model\AbstractPlugin;
use Efront\Model\User;
use Efront\Controller\UrlhelperController;
use Efront\Controller\BaseController;
use Efront\Plugin\AcmeReports\Controller\AcmeReportsController;

class AcmeReportsPlugin extends AbstractPlugin {

const VERSION = '1.0'; [...]


public function onCtg($ctg) {

if ($ctg == $this->plugin->name) {
BaseController::getSmartyInstance()
->assign("T_CTG", 'plugin')
->assign("T_PLUGIN_FILE",
$this>plugin_dir.'/View/AcmeReports.tpl');

$controller = new AcmeReportsController();


$controller->plugin = $this->plugin;
return $controller;
}

87
}
}

onCtg() is called whenever we need to decide where to route a request. $ctg always
contains the first part of the request URL. For example, if our installation is installed
on http://efrontpro.example.com/ and we request http://efrontpro.example.com/foo,
then $ctg will contain ‘foo’. This determines which controller will take effect. In our case, the
controller used is AcmeReports, so the icon link we created earlier points to /AcmeReports.
Our onCtg()implementation ensures that AcmeReportsController is invoked, and that the
proper view file, AcmeReports.tpl will be used.

Heads up! If you use a name of a controller that already exists, the system will never reach
it, since plugins are checked after all controllers have failed to initialize.

Now that we have a target for our link, let’s create the controller itself, which must extend
the BaseController class:

<?php namespace Efront\Plugin\AcmeReports\Controller;


use Efront\Controller\UrlhelperController;
use Efront\Model\UserType;
use Efront\Controller\BaseController;
use Efront\Plugin\AcmeReports\Model\AcmeReports;

class AcmeReportsController extends BaseController {


public $plugin;

protected function _requestPermissionFor() {


return array(UserType::USER_TYPE_PERMISSION_PLUGINS,
UserType::USER_TYPE_ADMINISTRATOR);
}

public function index() {


$smarty = self::getSmartyInstance();
$this->_model = new AcmeReports();
$this->_base_url =
UrlhelperController::url(array('ctg' => $this->plugin->name));

$smarty->assign("T_PLUGIN_TITLE", $this->plugin->title)
->assign("T_PLUGIN_NAME", $this->plugin->name)
->assign("T_BASE_URL", $this->_base_url);
}
}

Each controller should implement 2 functions: _requestPermissionFor() is used to


perform access control. See User types and restrictions for more information. index() is the

88
function called automatically by the system. Basecontroller includes an implementation
for index(), so if you don’t implement it, the parent’s will be invoked

In the example above, we use $smarty = self::getSmartyInstance() to get the view


manager instance, which is based on Smarty3. We then call$smarty→assign(<name>,
<variable>) each time we need to pass to our template the value of a <variable> and
access it with <name>. The Base URL is the URL of your controller, and it’s very convenient
to have it handy at any given time, so we assign it to the controller and our template.

Finally, our template file can be as simple as this:

{eF_template_appendTitle title = $T_PLUGIN_TITLE link = $T_BASE_URL}

{capture name = 't_code'}


<!-- Anything you wish to display here -->
{/capture}

{eF_template_printBlock data = $smarty.capture.t_code}

The first line adds the “AcmeReports” part on the system’s breadcrumb (path) bar. The last
line prints a standard html div block, containing all the html markup defined inside the
referenced capture code. We will add more in our template right below, but see our 1-minute
introduction to smarty to get a quick idea of how smarty works.

Heads up! The plugin code, as it is created until now, can be found in Github,
as AcmeReports-initial

We are now ready to get down on implementing the actual logic of our plugin. As we
described earlier, Acme wants a plugin that:

 Reports on the total number of users, courses and certificates


 Presents a list of users that have not used the system recently
 Presents a list of users that have not received a certification for specific courses
 Emails the list to the users’ supervisors
 Allows saving and retrieving past reports
We will proceed with creating each one below

Req. 1: Reports on the total number of users, courses and certificates

Let’s create a triplet of functions that retrieve this information, inside our Model
class, AcmeReports.php:

<?php namespace Efront\Plugin\AcmeReports\Model;

use Efront\Model\BaseModel;

89
use Efront\Model\User;
use Efront\Model\Course;
use Efront\Model\UserCertificate;

class AcmeReports extends BaseModel {


const PLUGIN_NAME = 'AcmeReports';

public function getTotalUsers() {


return User::countAll();
}
public function getTotalCourses() {
return Course::countAll();
}

public function getTotalCertifications() {


return UserCertificate::countAll();
}
}

Now, let’s call these functions from our controller, AcmeReportsController.php:

<?php namespace Efront\Plugin\AcmeReports\Controller;


[...]

class AcmeReportsController extends BaseController {


[...]
public function index() {
[...]
$total_users = $this->_model->getTotalUsers();
$total_courses = $this->_model->getTotalCourses();
$total_certificates = $this->_model->getTotalCertifications();
$smarty->assign(array(
"T_TOTAL_USERS" => $total_users,
"T_TOTAL_COURSES" => $total_courses,
"T_TOTAL_CERTIFICATES" => $total_certificates,
));
}
}

Finally, we edit our template file, AcmeReports.tpl, to display these numbers inside some
pretty panels:

90
{eF_template_appendTitle title = $T_PLUGIN_TITLE link = $T_BASE_URL}

{capture name = 't_code'}


{eF_template_printPanel image = "users" header = "Total
Users"|eF_dtranslate:$T_PLUGIN_NAME body = $T_TOTAL_USERS}
{eF_template_printPanel image = "courses" header = "Total
Courses"|eF_dtranslate:$T_PLUGIN_NAME body = $T_TOTAL_COURSES}
{eF_template_printPanel image = "certificate" header = "Total
Certificates"|eF_dtranslate:$T_PLUGIN_NAME body =
$T_TOTAL_CERTIFICATES}
<div class = "clearfix"></div>
{/capture}

{eF_template_printBlock data = $smarty.capture.t_code}

That’s it! Our plugin page now displays the totals we were requested to display:

Heads up! The plugin code, as it is created until now, can be found in Github,
as AcmeReports-step1

On to the next requirement.

Req. 2: Presents a list of users that have not used the system recently

Lists are best presented using Data Grids, like those found in the system
under admin→users, admin→courses etc. To implement one, we are first going to create the
table in the view file:

{eF_template_appendTitle title = $T_PLUGIN_TITLE link = $T_BASE_URL}

{capture name = 't_code'} [...]


<!--ajax:reportsTable-->
<div class="table-responsive">

91
<table style = "width:100%;" class = "sortedTable table" data-sort =
"last_login" size = "{$T_TABLE_SIZE}" id = "reportsTable" data-ajax =
"1" data-rows = "{$smarty.const.G_DEFAULT_TABLE_SIZE}" url =
"{$smarty.server.REQUEST_URI}">
<tr>
<td class = "topTitle"
name="formatted_name">{"User"|eF_translate}</td>
<td class = "topTitle" name = "last_login" data-order="desc">{"Last
login"|eF_translate}</td>
<td class = "topTitle noSort
centerAlign">{"Operations"|eF_translate}</td>
</tr>
{foreach name = 'users_list' key = 'key' item = 'user' from =
$T_DATA_SOURCE}
<tr class = "{cycle values = "oddRowColor, evenRowColor"} {if
!$user.active}text-danger{/if}" >
<td>{$user.formatted_name}</td>
<td>{$user.last_login}</td>
<td class = "centerAlign nowrap"> <img src =
'assets/images/transparent.gif' class = 'ajaxHandle icon-trafficlight_{if
$user.active == 1}green{else}red{/if} small ef-grid-toggle-active'
data-url = "{eF_template_url url = ['ctg'=>'users','toggle'=>$user.id]}"
alt = "{"Toggle"|eF_translate}" title = "{"Toggle"|eF_translate}">
</td>
</tr>
{foreachelse}
<tr class = "defaultRowHeight oddRowColor">
<td class = "emptyCategory" colspan = "100%">-</td>
</tr>
{/foreach}
</table>
</div> <!--/ajax:reportsTable-->
{/capture}

{eF_template_printBlock data = $smarty.capture.t_code}

And the respective function in the controller:

<?php namespace Efront\Plugin\AcmeReports\Controller;


[...]
use Efront\Controller\GridController;

92
use Efront\Model\User;

class AcmeReportsController extends BaseController {


[...]

public function index() {


[...]
if (isset($_GET['ajax']) && $_GET['ajax'] == 'reportsTable') {

$this->_listUsers(); }
else {
$total_users = $this->_model->getTotalUsers();
[...]
}
}

protected function _listUsers() {


try {
$constraints = GridController::createConstraintsFromSortedTable();

$entries = User::getAll($constraints);
$totalEntries = User::countAll($constraints);
$grid = new GridController($entries,
$totalEntries,
$_GET['ajax'], true
);
$grid->show();
} catch (\Exception $e) {
handleAjaxExceptions($e);
}
}
}

You can now see a list of all users, sorted by the last_login field. However, this field appears
as timestamp, rather than in a human-readable format. We’ll fix this in
the _listUsers() function of our controller:

93
protected function _listUsers() {
try {
$constraints = GridController::createConstraintsFromSortedTable();

$entries = User::getAll($constraints);
$total_entries = User::countAll($constraints);
foreach ($entries as $key=>$value) {
$entries[$key]['last_login'] =
formatTimestamp($entries[$key]['last_login'], 'time_nosec');
}
$grid = new GridController($entries, $total_entries, $_GET['ajax'],
true);
$grid->show();
} catch (\Exception $e) {
handleAjaxExceptions($e);
}
}

That’s it! Notice that we also added a “toggle active” handle in our list, that can be used to
set a user as active/inactive. This handle does not have any implementation associated,
because it calls the core system’s UserController to perform the action. Here’s how our
plugin page now looks, after adding the datagrid:

94
Heads up! The plugin code, as it is created until now, can be found in Github,
as AcmeReports-step2

On to the next requirement!

Req. 3: Present a list of users that have not completed a specific course

We first need to create a drop-down list of courses that have a certificate associated, so that
the user can select one. In our controller, we do:

<?php namespace Efront\Plugin\AcmeReports\Controller;


[...]
use Efront\Model\Course;

class AcmeReportsController extends BaseController {


[...]
public function index() {
[...]
$courses = Course::getPairs(
array('condition'=>'archive=0 AND active=1'),
array('id', 'formatted_name')
);
$smarty->assign("T_COURSES", $courses);
}
}

The code above retrieves all active, unarchived courses and assigns them to the template.

Heads up! Users, courses and lessons may be “archived”, meaning that they have a value
set for the “archive” field. This signifies that these entries are set as “deleted” and moved to
the archive. Special care should be taken, so that such entries are never taken into account
for calculations.

We must create now a drop-down box in our template like this:

<div style = "max-width:400px;">


<select id = "ef-select-course" class = "form-control ef-select">
<option value="">{"Select a course to display certifications
for"|eF_dtranslate:$T_PLUGIN_NAME}</option>
{foreach $T_COURSES as $key=>$value}
<option value="{$key}">{$value}</option>
{/foreach}
</select>
</div>

95
Heads up! Giving the ef-select class to any <select> element, will convert it to a
searchable drop-down

The tricky part now is to have this drop-down box interact with the grid, so that it displays
only users that possess the selected course but have not completed it. We will employ some
javascript and jquery magic for this:

<script>
$('#ef-select-course').on('change', function(event) {
if ($(this).val()) {
var url =
$.fn.st.getAjaxUrl('reportsTable')
.replace(/\/courses_ID\/[\w\d]*/, '')+'/courses_ID/'+$(this)
.val();
} else {
var url =
$.fn.st.getAjaxUrl('reportsTable')
.replace(/\/courses_ID\/[\w\d]*/, '');
}

$.fn.st.setAjaxUrl('reportsTable', url);
$.fn.st.redrawPage('reportsTable', true); });

</script>

This will change our Grid’s target URL, so that it also sends the selected course’s ID. We will
need to handle this accordingly to our Controller function as well:

[...]
use Efront\Model\Courses\CourseToUser;
[...]

public function index() {


[...]
if (isset($_GET['ajax']) && $_GET['ajax'] == 'reportsTable') {
if (!empty($_GET['courses_ID'])) {
$this->_listCourseUsers($_GET['courses_ID']);
} else {
$this->_listUsers();
}
} else {
[...]
}
}

[...]

96
protected function _listCourseUsers($course_id) {
try {
$this->checkId($course_id);
$course = new Course();
$course->init($course_id);
User::getCurrentUser()->canRead($course);
$constraints = GridController::createConstraintsFromSortedTable();
$conditions = array('condition'=>'u.archive=0 AND u.active=1 and
status !="'.CourseToUser::STATUS_COMPLETED.'"');
$entries = $course->getUsers($constraints+$conditions, array('u.*'));
$total_entries = $course->countUsers($constraints+$conditions);
foreach ($entries as $key=>$value) {
$entries[$key]['last_login'] =
formatTimestamp($entries[$key]['last_login'], 'time_nosec');
}
$grid = new GridController($entries,
$total_entries,
$_GET['ajax'],
true);
$grid->show();
} catch (\Exception $e) {
handleAjaxExceptions($e);
}
}

Here’s what our plugin page looks like now:

97
Heads up! The plugin code, as it is created until now, can be found in Github,
as AcmeReports-step3

On to our next task: Create an export and email it to the specified user

Req. 4: Email the list to a specified user

All grids contain a handy export button, that dumps its output as a CSV file (next to the filter
box). Based on this functionality, we will create a button that delivers the report to the
specified recipient, instead of prompting the user to download it. First, let’s create the button
in our template file:

<a class = "btn btn-primary pull-right ef-report-handles" id = "ef-email-


list" style = "display:none">
{"Email list"|eF_dtranslate:$T_PLUGIN_NAME}
</a>

<div style = "display:none" id = "ef-select-recipient-div">


<form class="form-inline">
<div class="form-group">
<input type="text" name = "recipient" data-type = "users" class =
"form-control ef-autocomplete" style = "width:400px" placeholder =
"{"Start typing to find user"|eF_dtranslate:$T_PLUGIN_NAME}"/>
</div>
<input type = "button" class = "btn btn-primary" id = "ef-select-
recipient" value = "{"Send"|eF_translate}">
</form>
</div>

Notice how we hide it by default. This is because we want it to appear only when the user
has selected a course, so we change the ef-select-coursehandling and add the
necessary scripting:

[...]
<script>
$('#ef-email-list').on('click', function(evt) {
$.fn.efront('modal',
{'header':'Select recipient', 'id':'ef-select-recipient-div'}
);
});

$('#ef-select-recipient').on('click', function(evt) {
var url = $.fn.st.getAjaxUrl('reportsTable',
true)+'?email=reportsTable&columns=formatted_name:User,last_login:Last%20
login';

98
$.fn.efront('ajax', url, {
data: { recipients:$('input[name="recipient"]').val().replace(/users-
/,'')}
}, function(response) {
$.fn.efront('modal', { close:true});
});
});

$('#ef-select-course').on('change', function(event) {
if ($(this).val()) {
var url =
$.fn.st.getAjaxUrl('reportsTable')
.replace(/\/courses_ID\/[\w\d]*/, '')+'/courses_ID/'+$(this)
.val();
$('.ef-report-handles').fadeIn();
} else {
var url =
$.fn.st.getAjaxUrl('reportsTable')
.replace(/\/courses_ID\/[\w\d]*/, '');
$('.ef-report-handles').fadeOut();
}

$.fn.st.setAjaxUrl('reportsTable', url);
$.fn.st.redrawPage('reportsTable', true);
});

</script>
[...]

The code above will make a modal appear, where the user can select recipients for the email,
and send an ajax request to our controller. We now have to implement the logic in our
controller that handles this request:

[...]

use Efront\Model\File;
use Efront\Model\Configuration;
use Efront\Model\MailQueue;

[...]

protected function _listCourseUsers($course_id) {


try {
[...]
if (!empty($_GET['email'])) {

99
$file = $grid->exportData();
$this->_sendEmail($file, $_GET['recipients']);

$this->jsonResponse();
} else {
$grid->show();
}
} catch (\Exception $e) {
handleAjaxExceptions($e);
}
}

protected function _sendEmail(File $file, $recipients) {

if (empty($recipients)) {
throw new EfrontException("You haven't specified a recipient");
}

$ids = explode(",", $recipients);


$messages = array();

foreach ($ids as $id) {


$this->checkId($id);
$user = new User($id);
$messages[] = array(
'recipient' => $user->email,
'title' => dtranslate("A new report has been emailed to you by
%s",
Configuration::getValue(Configuration::CONFIGURATION_MAIN_URL),
AcmeReports::PLUGIN_NAME),
'body' => dtranslate("Hello %s, Please find attached the report
exported on %s",
$user->formatted_name,
formatTimestamp(time()),
AcmeReports::PLUGIN_NAME),
'attachment' => $file->id,
);
}

if (!empty($messages)) {
$mail_queue = new MailQueue();
$mail_queue->addToQueue($messages);
}
}

100
Sending an email is as simple as creating an array holding the email data (recipient email,
title, body) and adding it to a MailQueue instance. See Sending emails for more information.

Here’s how our plugin page looks now, after clicking on the “Email list” button:

Heads up! The plugin code, as it is created until now, can be found in Github,
as AcmeReports-step4

Req. 5: Allows saving and retrieving past reports

We’re almost through with our plugin, the only thing remaining is to save reports to the
database. We will employ our model for this, which will be converted to describe a database
entry. But first, we need to set up our database table, using
our AcmeReportsPlugin class’ onInstall(), onUninstall() andonUpgrade() methods:

<?php namespace Efront\Plugin\AcmeReports\Model;


[...]
use Efront\Model\Database;

class AcmeReportsPlugin extends AbstractPlugin {


const VERSION = '1.1';
public function installPlugin() {
$sql = "CREATE TABLE
if not exists plugin_acme_reports(
id mediumint not null auto_increment primary key,
timestamp int default 0,
report longtext)
ENGINE=InnoDB DEFAULT CHARSET=utf8;";

101
102
try {
Database::getInstance()->execute($sql);
} catch (\Exception $e) {
$this->uninstallPlugin();
//so that any installed tables are removed
//and we're able to restart fresh
}
return $this;
}

public function uninstallPlugin() {


$sql = "drop table if exists plugin_acme_reports";
Database::getInstance()->execute($sql);
return $this;
}

public function upgradePlugin() {


$queries = array();
if (version_compare('1.1', $this->plugin->version) == 1) {
$queries[] = "CREATE TABLE if not exists plugin_acme_reports(

id mediumint not null auto_increment primary key,


timestamp int default 0,
report longtext)
ENGINE=InnoDB DEFAULT CHARSET=utf8;";
}
foreach ($queries as $query) {
Database::getInstance()->execute($query);
}
return $this;
}

[...]

The implementation above will ensure that:

 A table called plugin_acme_reports will be created upon installation of the plugin


 The table will be deleted upon uninstallation
 The table will be created for existing plugins (such as ours). To ensure that
the onUpgrade() function runs, simply change the VERSION constant in the class.
See Upgrading for more information.

Simply refresh your page to allow the plugin’s onUpgrade() to run.Now that our database
table is in place, let’s extend our Model’s implementation:

103
<?php namespace Efront\Plugin\AcmeReports\Model;

[...]

class AcmeReports extends BaseModel {


const PLUGIN_NAME = 'AcmeReports';
const DATABASE_TABLE = 'plugin_acme_reports';
protected $_fields = array(
'id' => 'id',
'timestamp' => 'timestamp',
'report' => 'wysiwig'
);
public $id;
public $timestamp;
public $report;

[...]

That’s it! All we had to do is to define a DATABASE_TABLE constant and create an array with
the database table’s fields, as well as a public variable for each field. Being
a BaseModel class, our Model already contains all the necessary functions to
handle create/update/read/delete operations (see Creating a new Model + Database
table). We can now work on our controller to take advantage of this functionality. But first we
must create the necessary button and functionality in the View component:

[...]

<a class = "btn btn-primary pull-right ef-report-handles" id = "ef-save-


list" style = "display:none;margin-left:10px;">
{"Save list"|eF_dtranslate:$T_PLUGIN_NAME}
</a>

[...]

<script>
$('#ef-save-list').on('click', function(evt) {
var url = $.fn.st.getAjaxUrl('reportsTable',
true)+'?save=reportsTable&columns=formatted_name:User,last_login:Last%20l
ogin';
$.fn.efront('ajax', url, { data: { 'save':true } },
function(response) {
bootbox.dialog({message: '<h4>{"Report
Saved!"|eF_dtranslate:$T_PLUGIN_NAME}</h4>',

104
//title: 'Report saved',
buttons: { cancel: { label: $.fn.efront('translate', "Close"),
className: "btn-primary"}}
});
});
});

[...]

This will send a request, similar to the previous, only this time specifying we need to save
instead of emailing. Our controller implements this logic as follows:

[...]

protected function _listCourseUsers($course_id) {


try {
[...]
if (!empty($_GET['email'])) {
$file = $grid->exportData();
$this->_sendEmail($file, $_GET['recipients']);
$this->jsonResponse();
} else if (!empty($_GET['save'])) {
$file = $grid->exportData();
$this->_model->setFields(array(
'timestamp'=>time(),
'report' =>
file_get_contents(G_ROOTPATH.$file->path),
))->save();
$this->jsonResponse();
} else {
$grid->show();
}
} catch (\Exception $e) {
handleAjaxExceptions($e);
}
}

[...]

That’s it! Our plugin now saves the report, along with a timestamp. The only thing left now,
is to present the list of saved reports to the user. We will do so by implementing a second
Grid, in a different tab. First, let’s consider our template. We will create a {capture} section
that will hold our new grid:

105
[...] {capture name = "t_saved_reports"}
<!--ajax:savedReportsTable-->
<div class="table-responsive">
<table style = "width:100%;" class = "sortedTable table" data-sort =
"last_login" size = "{$T_TABLE_SIZE}" id = "savedReportsTable" data-ajax
= "1" data-rows = "{$smarty.const.G_DEFAULT_TABLE_SIZE}" url =
"{$smarty.server.REQUEST_URI}">
<tr>
<td class = "topTitle" name =
"timestamp">{"Timestamp"|eF_translate}
</td>
<td class = "topTitle noSort
centerAlign">{"Operations"|eF_translate}
</td>
</tr>
{foreach name = 'users_list' key = 'key' item = 'report' from =
$T_DATA_SOURCE}
<tr class = "{cycle values = "oddRowColor, evenRowColor"}" >
<td>{$report.timestamp}</td>
<td class = "centerAlign nowrap">
<a href = "{eF_template_url extend = $T_BASE_URL url
['view'=>$report.id]}" target = "_new">
<img src = 'assets/images/transparent.gif'
class = 'icon-search small'
alt = "{"View"|eF_translate}"
title = "{"View"|eF_translate}">
</a>
<img src = 'assets/images/transparent.gif'
class = 'ef-grid-delete ajaxHandle icon-error_delete small'
data-url = "{eF_template_url extend=$T_BASE_URL
url=['delete'=>$report.id]}" alt =
"{"Delete"|eF_translate}" title =
"{"Delete"|eF_translate}"/>
</td>
</tr>
{foreachelse}
<tr class = "defaultRowHeight oddRowColor">
<td class = "emptyCategory" colspan = "100%">-</td>
</tr>
{/foreach}
</table>
</div> <!--/ajax:savedReportsTable-->
{/capture}
[...]

106
We need this capture, to create tabs. We must add all the other code inside
another {capture}, and then create the tabs using {eF_template_printTabs}. In the end
it looks like this:

{eF_template_appendTitle title = $T_PLUGIN_TITLE link = $T_BASE_URL}

{capture name = "t_users"} [...] {/capture}


{capture name = "t_saved_reports"} [...] {/capture}
{capture name = 't_code'}

{eF_template_printPanel image = "users" header = "Total


Users"|eF_dtranslate:$T_PLUGIN_NAME body = $T_TOTAL_USERS}
{eF_template_printPanel image = "courses" header = "Total
Courses"|eF_dtranslate:$T_PLUGIN_NAME body = $T_TOTAL_COURSES}
{eF_template_printPanel image = "certificate" header = "Total
Certificates"|eF_dtranslate:$T_PLUGIN_NAME body = $T_TOTAL_CERTIFICATES}

<div class = "clearfix"></div>

{eF_template_printTabs tabs = [['key' => 'users', 'title' =>


"Users"|eF_translate, 'data' => $smarty.capture.t_users],

['key' => 'reports', 'title' => "Reports"|eF_translate, 'data' =>


$smarty.capture.t_saved_reports]]} {/capture} {eF_template_printBlock
data = $smarty.capture.t_code}

The code above prints 2 tabs, one for each grid. The saved reports grid is handled in our
controller with a _listReports() function, similar to the previous grid:

[...]

if (isset($_GET['ajax']) && $_GET['ajax'] == 'reportsTable') {


if (!empty($_GET['courses_ID'])) {
$this->_listCourseUsers($_GET['courses_ID']);
} else {
$this->_listUsers();
}
} else if (isset($_GET['ajax']) && $_GET['ajax'] == 'savedReportsTable'){
$this->_listReports();
[...]

protected function _listReports() {


try {
$constraints =
GridController::createConstraintsFromSortedTable();

107
$entries = AcmeReports::getAll($constraints);
$total_entries = AcmeReports::countAll($constraints);

foreach ($entries as $key=>$value) {


$entries[$key]['timestamp'] =
formatTimestamp($entries[$key]['timestamp'], 'time_nosec');
}

$grid = new GridController($entries,


$total_entries,
$_GET['ajax'], true
);
$grid->show();
} catch (\Exception $e) {
handleAjaxExceptions($e);
}
}

[...]

But that’s not all! Our saved reports grid also contains a couple of handles: One for
downloading a report and one for deleting it. Here’s the controller code that implements both
of these:

[...] }

else if (isset($_GET['ajax']) && $_GET['ajax'] == 'savedReportsTable') {


$this->_listReports(); } else if
(!empty($_GET['view'])) { $this-
>checkId($_GET['view']); $this->_model-
>init($_GET['view']);
$path = G_TEMPDIR."report.csv";
file_put_contents($path, $this->_model->report);
$file = new File($path);
$file->sendFile(true);
} else {
$this->deleteHandler();

the deleteHandler() function is part of the BaseController so we don’t have to actually


implement anything for the deletion. For viewing, we first dump the data to a temporary file,
and then send it using File::sendFile(true), which takes care of all the required headers
and procedures for downloading a file

108
Heads up! The plugin code, as it is created until now, can be found in Github,
as AcmeReports-final

That’s it! Congratulations, your plugin is ready to ship to Acme!

Overriding templates
One common customization requirement is to change substantially the look and feel of a
certain page. For example, someone might need to provide a totally different implementation
for the navbar, with changes that cannot be achieved using CSS and Javascript (which can
be altered using custom themes). In such a case, a plugin can be used, as follows:

1. Make sure you implement AbstractPlugin::overridesTemplate() inside


your Plugin class (AcmeReportsPlugin in our example):

public function overridesTemplate() {


return dirname(__DIR__).'/View/';
}

2. Locate the template file you wish to override. In our example, that would
be libraries/Efront/View/layout/navbar.tpl. Then create a file with the
same name at the respective folder of your plugin. In our AcmeReports example, we
would create the filewww/plugins/AcmeReports/View/layout/navbar.tpl
3. The system now will read your plugin’s file, instead of the default one. However, if you
still want to reference the original file (for example, if we simply want to add some
code), you can do this as follows:

{include file = "file:[base]layout/navbar.tpl"}


<!-- Some custom HTML code here -->

4. A different option is to extend a plugin, rather than completely overriding. In this case, if
the core file contains any named {block} sections, you can override these specifically.
For example, the file lessons/lesson_dashboard.tpl, contains the following
block for displaying the two columns in the dashboard:

{block name = "lesson_dashboard_layout"}


<div class="col-md-6">
{$smarty.capture.left_block}
</div>
<div class="col-md-6">
{$smarty.capture.right_block}
</div>
{/block}

109
[...]

You can now extend this particular piece of code in your plugin’s
lesson/lesson_dashboard.tpl file. For example, the code below would add an additional
column in the middle, making the lesson dashboard’s layout to have 3 columns, instead of
2:

{extends file = "file:[base]catalog/course.tpl"}


{block name = 'lesson_dashboard_layout'}
<div class="col-md-4">
{$smarty.capture.left_block}
</div>
<div class="col-md-4">
<!-- Some custom code here -->
</div>
<div class="col-md-4">
{$smarty.capture.right_block}
</div>
{/block}

Manipulating forms
Forms in general is a complicated issue, but in eFrontPro steps have been taken to simplify
them as much as possible. Forms are usually implemented as part of the Model class.
See Creating forms for more information on how to create a form. Every form can be
manipulated from within a plugin using
theonCreateForm(), onBeforeHandleForm() and onAfterHandleForm() functions. All of
these functions accept as argument the form name and the Formobject

 onCreateForm() is called right after the form is populated with fields, but before any
processing happens. This is suitable for adding or removing fields from the form.
 onBeforeHandleForm is called right after the submit button is pressed, but before any
actual processing takes place. This is suitable for completely overriding the default
form handling, or for pre-processing POST variables
 onAfterHandleForm() is called after all processing is finished. This is suitable for
performing post-processing operations.
Heads up! Make sure your plugin only handles the correct form, by checking its name,
otherwise it will process all forms!

Internationalization

You may have noticed that in many examples, we use translate()/dtranslate() (PHP)
and eF_translate/eF_dtranslate (template) for outputting strings that should appear
localized. That’s because eFrontPro uses Gettext to handle the translations of its

110
messages. translate() and eF_translatewill use the system’s existing translations, and
are used for cases where a string already exists in the core. For strings that are specific to
your plugin, follow a few simple steps as described below:

1. A message of your plugin which require translation, will properly be translated if you
use 2 functions. The function dtranslate(“myMessage”, “<plugin_name>”) must
be used when the message exists into a class and not a template inside your plugins
scope. In the other case (template), you have to use
the “myMessage”|eF_dtranslate:<plugin_name>. Replace <plugin_name> with the
name of your plugin
2. Visit the page /<plugin>/parse_language/1 (For
example, http://efrontpro.example.com/AcmeReports/parse_language/1). This will
create all the required language specific folders and .po files inside the plugin’s i18n
folder and a php file with name translations.php.
3. Open each .po file with poedit. Poedit can be found here.
4. Click on the “Update” button to parse the plugin files and fill the list of strings that need
translation.
5. Translate all string literals.
6. Press the “Save” button to save your work. Make sure you have write access to the
folders created in step 1.
7. Restart your server, in case that the translations aren’t changed.

Heads up! Make sure that the file “translations.php” is a valid PHP file. If it’s not, check your
template files again. All translations must be enclosed in double quotes, not single.

Sending emails
When creating a plugin, you don’t have to actually send an email. All you have to do is to
pass the email data to the MailQueue handler, and your email will queued to be delivered
upon the next iteration. Example:

<?php

[...]

$recipients = array('jdoe@example.com', 'professor@example.com',


'admin@example.com');
$title = "Hello world";
$body = "Hello, this is an email to test emailing from a plugin";
$timestamp = time();
$messages = array();
foreach ($recipients as $recipient) {
$messages[] = array(
'recipient' => $recipient,
'title' => $title,

111
'body' => $body,
'timestamp' => $timestamp
);
}
$mail_queue = new MailQueue();
$mail_queue->addToQueue($messages);

That’s it! You have now 3 emails in the mail queue, waiting to be delivered. You can examine
the queue’s contents from admin→Notifications→Queue

Heads up! Setting the email’s timestamp at some point in the future, will make the email
stay in queue until then.

Error handling
It is a good practice to have your code throw an exception whenever an error occurs. When
catching exceptions, you should discriminate between exceptions that are thrown during the
normal flow of your program, or during an ajax request, and handle them differently,
using handelNormalFlowExceptions() orhandleAjaxExceptions() respectively:

<?php

[...]

try {
//some normal flow stuff here
throw new \Exception("Testing exceptions");
} catch (\Exception $e) {
handleNormalFlowExceptions($e);
}

if (!empty($_GET[‘ajax’])) {
try {
//some ajax flow stuff here
throw new \Exception("Testing exceptions");
} catch (\Exception $e) {
handleAjaxExceptions($e);
}
}

This will ensure that the error message will always display properly in the end user.

Heads up! If your plugin throws an exception while handling an event, using
the onEvent() call, the exception will be suppressed, to prevent the operation from stopping.

112
You should handle any exceptions that your plugin might generate during an onEvent() call
yourself

Upgrading
A plugin typically requires upgrade, when its associated database schema needs changing.
The plugin upgrading process can be automated in eFrontPro and is described as a step-
by-step process:

Imagine that you have a plugin named “AcmeReports” which is in version 1.0 and needs to
run an alter table query.

1. Edit the plugin class file that extends AbstractPlugin and change the VERSION
constant to a larger number, for example 1.1
2. Edit your upgradePlugin() function to include the SQL code that must be ran. For
example, in order to add a field to a table:

[...]

public function upgradePlugin() {


if (version_compare('1.0', $this->plugin->version) == 1) {

Database::getInstance()
->execute("alter table plugin_acme_reports add timestamp
int default null");
}
return $this;
}

[...]

3. Once you run any page in your system (e.g. sign in as administrator) The system will
detect that the plugin’s stored version number is different than the one specified in
VERSION, and will execute the plugin’s upgradePlugin() function.

4. Each time a new change is required, increase the VERSION and add the proper lines
inside upgradePlugin(). For example, for 1.2, the function will become:

[...]

public function upgradePlugin() {

if (version_compare('1.1', $this->plugin->version) == 1) {

Database::getInstance()

113
->execute("alter table plugin_acme_reports add timestamp int
default null");
}

if (version_compare('1.2', $this->plugin->version) == 1) {

Database::getInstance()
->execute("alter table plugin_acme_reports add comments
text");
}

return $this;
}

[...]

Heads up! When changing the version, make sure you change it inside your plugin’s
plugin.ini file. In addition, don’t forget to make the same database changes inside
your onInstall() function, and add proper routines in onUninstall(), if needed

More plugin examples

The Demo plugin


eFrontPro ships with a plugin called “Demo”, which serves as a testbed for all Plugin calls. It
implements all possible calls found in AbstractPlugin while at the same time serving as a
fully functional plugin, complete with its own database table and Grid. Feel free to download,
explore and change it to learn more about plugins

Taking advantage of the REST API


eFrontPro provides a REST API that allows 3rd-party systems to exchange data and perform
operations, using the associated API key. A plugin may take advantage of the REST API’s
mechanism of exchanging data, via the onApiCall() method. See the documentation on
the REST API and the Plugin API Reference for more information

Considerations

User types and restrictions


There are 3 basic user types in efront, which determine the interface that displays to the
user: Administrator, professor and student. Based on these, an administrator may create
subtypes, with different permission levels. In addition, an administrator-type user that is
assigned to a branch, is called a “Supervisor” and has admistrator rights only in his/her own

114
branch context. In order to determine a user object’s type, the simplest way is to call one of
these functions:

$user = new User(321);


$user->isAdministrator();
//returns true if the $user type is based
//on the “administrator” basic type
$user->isSuperisor();
//returns true if the $user type
//is based on the “administrator” AND is assigned to a branch
$user->isProfessor();
//returns true if the $user type is based
//on the “professor” basic type
$user->isStudent();
//returns true if the $user
type is based on the “student” basic type

When editing a template file, these functions have their smarty counterparts:

{if $T_CURRENT_USER_IS_ADMINISTRATOR}
{elseif $T_CURRENT_USER_IS_SUPERVISOR}
{elseif $T_CURRENT_USER_IS_PROFESSOR}
{elseif $T_CURRENT_USER_IS_STUDENT}
{/if}

When inside a controller, if we need to restrict access to a specific basic type, we must
implement the _requestPermissionFor() function. For example, the following
implementation limits the current plugin to administrator types only:

[...]

class AcmeReportsController extends BaseController {

protected function _requestPermissionFor() {


return array(UserType::USER_TYPE_PERMISSION_PLUGINS,
UserType::USER_TYPE_ADMINISTRATOR);
}

[...]

…and the following to administrators and professors:

115
[...]

class AcmeReportsController extends BaseController {


protected function _requestPermissionFor() {
return array(
UserType::USER_TYPE_PERMISSION_PLUGINS,
array(UserType::USER_TYPE_ADMINISTRATOR,
UserType::USER_TYPE_PROFESSOR));
}

[...]

… and the following, to any logged-in user, regardless of type:

[...]

class AcmeReportsController extends BaseController {

protected function _requestPermissionFor() {


return array(UserType::USER_TYPE_PERMISSION_PLUGINS);
}

[...]

In order to determine whether a user can access or change an entity, one can utilize the
usertype object:

//determine if a user can change a course, based on his/her user type


$user = new User(123);
$user_type = new UserType($user->user_types_ID);
$access_level = $user_type
->getAccessLevel(UserType::USER_TYPE_PERMISSION_COURSES);

if ($access_level == UserType::USER_TYPE_LEVEL_WRITE) {
//the $user can create/change a course
} else if ($access_level == UserType::USER_TYPE_LEVEL_READ) {
//the $user can only read a course, but not change or delete it,
neither create a new one
} else {
//the $user has no access on course information whatsoever
}

116
To simplify things, all controllers that extend BaseController already include the current
user’s access_level for the entity specified in_requestPermissionFor() (the first
argument), so inside a controller it’s sufficient to do something like this:

//determine if a user can change a course, based on his/her user type


$user = new User(123);
if ($this->_access_level == UserType::USER_TYPE_LEVEL_WRITE) {
//the $user can create/change a course
} else if ($this->_access_level == UserType::USER_TYPE_LEVEL_READ)
//the $user can only read a course,
//but not change or delete it, neither create a new one
} else {
//the $user has no access on course information whatsoever }

Heads up! Permission levels vary from 0 (USER_TYPE_LEVEL_NONE) to 1


(USER_TYPE_LEVEL_READ) and 10 (USER_TYPE_LEVEL_WRITE). However, values between 1
and 10 are possible. Consult the UserType object for an overview of available access levels
(or see admin→user types)

When inside a template, a similar approach is possible, especially since all access levels are
already available, as the $T_USER_TYPE_ACCESS variable. For example, if we were to decide
whether to display an “edit” link to a user, we would do:

{if
$T_USER_TYPE_ACCESS['\Efront\Model\UserType::USER_TYPE_PERMISSION_USERS'|
constant] != '\Efront\Model\UserType::USER_TYPE_LEVEL_NONE'|constant}
<a href = "{eF_template_url url=['ctg'=>'users','edit'=>$user.id]}" class
= "editLink">
{$user.formatted_name}
</a>
{else}
{$user.formatted_name}
{/if}

In order to ensure that a user has permissions to view/change an entity, one has to consider
other parameters, besides its user type: For example, if a professor tries to access a course,
is he actually enrolled to it? What about a supervisor trying to view information about a user,
is that user part of his/her branch tree? For such cases, there is a pair of handy functions
one can use, User::canRead() and User::canChange()

$current_user = User::getCurrentUser();
//The currently logged-in user
$course = new Course(321);
//some course that the user is trying to access

117
$user->canRead($course);
//will throw an exception if the user
// should not access the course
$user->canChange($course);
//will throw an exception if the user
//should not update/delete the course

Heads up! canRead() and canWrite() accept as an argument any object deriving from
the BaseModel class. However, they are expensive functions and should never be used in
loops, but only as a last safety precaution.

Prioritization
Plugins in eFrontPro are executed in a “first installed-first served” fashion. This means that,
when waiting for a call from the plugin API, your plugin might not be the first to handle it, so
the output might have changed. In the future, we might add prioritization in plugins, so take
care to not rely on this behaviour.

Maintaining core compatibility


Being an actively developed project, eFrontPro will bring updates from time to time, that
might break support for your plugin, one way or another. You should take special care to
verify your plugin’s compatibility with current versions. In the future, the system will
automatically disable plugins that do not explicitly state their compatibility with the current
version of the LMS (the ‘compatibility’ entry inside the plugin’s plugin.ini file).

Maintaining template compatibility


If you implement a plugin that overrides or extends a template file, then it’s very likely that at
some point, the original file will change in the core, after an upgrade. You should manually
verify that your plugin’s versions of the template files incorporate any changes brought by a
new eFrontPro version

Coding standards
eFrontPro does not impose any strict coding standards, but encourages the user of the PSR-
2 guidelines, which ensure readability and tidiness.

Best practices / common pitfalls


 Avoid directly executing queries when possible, especially using
the Database::execute() method. BaseModel usually provides all the tools
necessary for querying the database.
 Every database table should have a model class representing it, inheriting the
BaseModel class
 Make sure you account for Supervisors (branch administrators), when presenting data
lists. These accounts should never have access to data generated from other,
unrelated branches

118
 Make sure you leave out archived users, courses and lessons when making
calculations. Archived entities are equivalent to deleted; you can tell that an entity is
archived, because it will have a timestamp for its “archive” field (normal entities have 0
in this field)
 All entities are cached, when a caching engine is present. Thus changing an entity
directly in the database (either using the Database class or directly from the command
line) will not have an apparent effect, unless the cache is cleared (with a webserver
restart or from admin→Maintenance→Cache)

Troubleshooting / debugging
Inevitably, you’ll run into all sorts of errors and abnormal situations. Here’s a list of the most
common and their causes

Heads up! Call debug() at any point in your script to turn on full error reporting, and a dump
of all queries executed, until the script ends or debug(false) is called.

 Blank screen: This is caused by a fatal error at some very early stage of the system
execution. If the web server’s error log file doesn’t say anything about the error, then
you might have to dive into the core code itself: Edit the
file libraries/Controller/MainController.php, locate thesetup() function
and change the line where it says error_reporting( E_ERROR
); to error_reporting( E_ALL );ini_set(“display_errors”,
true);define(“G_DEBUG”, 1);
 Murphy’s law: The standard error page for unhandled errors states quotes Murphy.
Usually this page also displays the error message itself, as well as the file and line
where it occurred. If it’s not clear by the message, then try adding a debug() call early
in your script to help you find out what’s wrong.
 Smarty error: The most common error in smarty templates, is when some Javascript
codes contains an opening bracket immediately followed by a character, without a
space, for example {'foo':'bar'}. Change this to { 'foo':'bar'} to prevent
smarty from trying to parse it. Other errors, such as syntax errors, usually display with a
clear message and the file and line number where they occur.
 Invalid CSRF Token: This is common when trying to open an ajax request in a new
window. It happens because of an aggressive CSRF filter the system employs in all
Ajax requests. You should only debug ajax calls via your browser’s console.
 SyntaxError: Unexpected token <: This error is usually thrown from an ajax request that
did not receive an JSON response, but rather an HTMLresponse. Probable causes are:
 You made an ajax request to a controller, but the controller did not provide a JSON
response
 The controller responds properly, but you forgot to exit after the response
 An error occurred that was not handled with handleAjaxRequest()

Heads up! Streamline your ajax responses, by calling the


controller’s jsonResponse() function.

119
Plugin API Reference
Below you can find all functions that you can override inside your Plugin class, as found
inside the AbstractPlugin class

/**
* This function is executed every time an event is fired.
* @param Event $event The Event object
*/
public function onEvent(Event $event) { }

/**
* This function is executed right after a form is submitted, but before
* any processing takes place. It may be used to manipulate submitted
values.
* You have to use the $form_name, which is unique for every for, to
* discriminate between various forms
* @param string $from_name The form name
* @param Form $form The form object
*/
public function onBeforeHandleForm($form_name, Form $form) { }

/**
* This function is executed right before a form is submitted.
* It may be used in order to add fields or manipulate existing ones
* You have to use the $form_name, which is unique for every for, to
* discriminate between various forms
* @param string $from_name The form name
* @param Form $form The form object
*/
public function onCreateForm($form_name, Form $form) { }
/**
* This function is executed after a form is submitted and its
* values are processed. It may be used to perform any post-processing
* tasks. You have to use the $form_name, which is unique for every
* for, to discriminate between various forms
* @param string $from_name The form name
* @param Form $form The form object
*/
public function onAfterHandleForm($form_name, Form $form) { }

/**
* This function is called when the controller to be ran is decided,
* or the default controller is about to take over. It can be used in two
* ways: Either to execute some code when a specific controller (page) is
* executed, or to provide a means to access a plugin-specific controller

120
* @param string $ctg The requested controller in the browser, e.g.
'users' or 'lessons' * @return mixed null or a BaseController object
*/

public function onCtg($ctg) { }

/**
* This function is called by each controller, every time its index
function is executed.
* @param BaseController $controller
*/
public function onControllerIndex(BaseController $controller) { }

/**
* This function is executed every time an icon list is loaded. Each icon
list
* has a distinctive name, so the plugin must discriminate based on the
$list_name
* provided. The icons array is passed by reference, so the plugin may
manipulate
* the list or add icons. This is usually used to add a plugin icon, which
provides
* a link to the plugin page
* @param string $list_name The icon list name
* @param $options The current icon options list
*/

public function onLoadIconList($list_name, &$options) { }


/**
* This function is executed every time a lesson dashboard is loaded
* @param Course $course The current course
* @param Lesson $lesson The current lesson
* @param LessonProgress $lesson_progress The progress object (optional)
*/
public function onLessonDashboard(Course $course, Lesson $lesson,
LessonProgress $lesson_progress = null) { }

/**
* This function is executed every time the system gets a lesson's
options.
* It can be used to augment or manipulate the options list, which is
passed
* by reference
* @param Lesson $lesson The lesson used
* @param array $lesson_settings The list of current lesson settings
*/
public function setLessonOptions(\Efront\Model\Lesson $lesson, array

121
&$lesson_settings) { }

/**
* This function is executed before any controller takes action
*/

public function onPageLoadStart() { }

/**
* This function is called before the calendar is displayed. It can be
used
* to manipulate calendar entries, or add new ones
* @param array $calendar_entries The calendar's entries
*/
public function onLoadCalendar(array &$calendar_entries) {
}

/**
* This function is called from the REST API, using a POST method,
* and passes the POST payload to the plugin. It then returns the
* plugin's return value to the caller.
* @param string $method The method used (currently only POST supported)
* @param mixed $data The data passed from the POST request
* @return mixed Any response the plugin needs to send to the requester
*/
public function onApiCall($method, $data) { }

/**
* Implement this function with all the required queries and actions to
* install the plugin
*/
abstract public function installPlugin();

/**
* Implement this function with all the required queries and actions to
* remove the plugin
*/
abstract public function uninstallPlugin();

/**
* Implement this function with all the required queries and actions to

122
* upgrade the plugin to a new version
*/
abstract public function upgradePlugin();

123
Event Reference
Events are fired in various parts of the script’s lifetime. Each event bears one or more objects
as arguments, for example the user that caused the event, the entity it affects etc. Each
event has its own associated class, and you can refer to it for a list of the available properties.
Below is a list of the currently available events:

const EVENT_BRANCH_CREATED = 'branch_created';


const EVENT_BRANCH_UPDATED = 'branch_updated';
const EVENT_BRANCH_DELETED = 'branch_deleted';
const EVENT_JOB_CREATED = 'job_created';
const EVENT_JOB_UPDATED = 'job_updated';
const EVENT_JOB_DELETED = 'job_deleted';
const EVENT_USER_JOB_ADDED = 'user_job_added';
const EVENT_USER_JOB_REMOVED = 'user_job_removed';
const EVENT_EXTENDED_FIELD_DELETED = 'extended_field_deleted';
const EVENT_USER_TYPE_DELETED = 'user_type_deleted';
const EVENT_DISCUSSION_TOPIC_CREATED = 'discussion_topic_created';
const EVENT_DISCUSSION_TOPIC_UPDATED = 'discussion_topic_updated';
const EVENT_DISCUSSION_CREATED = 'discussion_created';
const EVENT_USER_CREATED = 'user_created';
const EVENT_USER_UPDATED = 'user_updated';
const EVENT_USER_ARCHIVED = 'user_archived';
const EVENT_USER_DELETED = 'user_deleted';
const EVENT_USER_SIGNIN = 'user_signin';
const EVENT_USER_SIGNOUT = 'user_signout';
const EVENT_USER_SIGNUP = 'user_self_signup';
const EVENT_USER_ENABLED = 'user_enabled';
const EVENT_USER_REQUESTED_ACTIVATION = 'user_requested_activation';
const EVENT_USER_REQUESTED_MAIL_ACTIVATION =
'user_requested_mail_activation';
const EVENT_USER_REQUESTED_PASSWORD = 'user_requested_password';
const EVENT_USER_RECEIVED_PERSONAL_MESSAGE =
'user_received_personal_email';
const EVENT_USER_COURSE_COMPLETED = 'user_course_completed';
const EVENT_USER_COURSE_FAILED = 'user_course_failed';
const EVENT_USER_CONTENT_COMPLETED = 'user_content_completed';
const EVENT_USER_CONTENT_FAILED = 'user_content_failed';
const EVENT_USER_LESSON_COMPLETED = 'user_lesson_completed';
const EVENT_USER_LESSON_FAILED = 'user_lesson_failed';
const EVENT_USER_COURSE_REMOVED = 'user_course_removed';
const EVENT_USER_COURSE_ADDED = 'user_course_added';
const EVENT_COURSE_BOOKING_CREATED = 'course_booking_created';
const EVENT_COURSE_BOOKING_CHANGED = 'course_booking_changed';
const EVENT_COURSE_BOOKING_CANCELLED = 'course_booking_cancelled';
const EVENT_EXPRESSED_INTEREST_USER = 'expressed_interest_user';

124
const EVENT_USER_CURRICULUM_ADDED = 'user_curriculum_added';
const EVENT_USER_CURRICULUM_REMOVED = 'user_curriculum_removed';
const EVENT_USER_CURRICULUM_COMPLETED = 'user_curriculum_completed';
const EVENT_USER_CURRICULUM_FAILED = 'user_curriculum_failed';
const EVENT_USER_CERTIFICATE_AWARDED = 'user_certificate_awarded';
const EVENT_USER_CERTIFICATE_EXPIRED = 'user_certificate_expired';
const EVENT_USER_CERTIFICATE_REVOKED = 'user_certificate_revoked';

125
Core API Notes

Creating URLs
It is generally discouraged to hard-code URLs in eFrontPro, but use
the UrlHelperController class for this task. Here are a few usage examples:

$url = UrlHelperController::url(array('ctg' => 'users', 'edit'=>123));


//will output /users/edit/123
$url = UrlHelperController::extendUrl($url, array('tab'=>'courses'));
//will output /users/edit/123/tab/courses
$url = UrlHelperController::redirect(array('ctg' => 'users',
'edit'=>123));
//will redirect the user to /users/edit/123

You can create a url/link in a template file, using the {eF_template_url} smarty function:

{eF_template_url url = ['ctg' => 'users', 'edit'=>123]}


{eF_template_url extend = $T_SOME_URL url = ['tab'=>'courses']}

And in javascript:

<script> $.fn.efront('url', {'ctg':'users','edit':123}) </script>

Creating a new Model + Database table


Every database table in eFrontPro must be accompanied from a Class that represents it. For
example, let’s consider a table called “plugin_logs” with the following definition:

CREATE TABLE `plugin_logs` (


`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`time` INT(10) UNSIGNED DEFAULT NULL,
`title` text,
`content` text,
PRIMARY KEY (`id`) )
ENGINE=InnoDB DEFAULT CHARSET=utf8

For this table, we would create a class called Log, with the following contents (we use
the AcmeReports namespace, from our earlier example):

126
<?php namespace Efront\Plugin\AcmeReports\Model;

use Efront\Model\BaseModel;

class AcmeReports extends BaseModel {


const DATABASE_TABLE = 'logs';
protected $_fields = array(
'id' => 'id',
'time' => 'timestamp',
'title' => '',
'content' => '',
);
public $id;
public $timestamp;
public $title;
public $content;
}

Since our class inherits BaseModel, it comes with a complete set of functions for performing
CRUD operations (Create/Read/Update/Delete). We only have to specify the database
table name, and its fields. The protected $_fields array is a key-value array, where keys
are the field names and values are optional type-checking attributes. For example, the
line 'id'⇒'id' specifies that, when updating, the value of the “id” element should conform
to the restrictions for an “id” value (positive integer). Similarly, 'time' ⇒
'timestamp' means that the value of the field ‘time’ should be a timestamp (positive
integer, 10 digits). When left empty, the value is only checked against the “generic” type, that
imposes scalar values (and throws an error for arrays, objects etc).

Heads up! If you don’t specify a type check, when saving an object the passed value will be
XSS-filtered. If you want to keep any HTML code present in the value, then use the ‘wysiwig’
value for the field.

After creating the class, you can use it to perform CRUD operations:

$log = new Log();


//create an empty Log object
$log->setFields(array(
'time'=>time(),
'title'=>'A sample log entry',
'content'=>'This is a sample log entry, for the sake of the
example'));
$log->save(); //Actually creates the database entry;
$id = $log->id;
$log2 = new Log($id); //Create a Log object and instantiate from the
database
$log2->setFields(array('title'=>'Changed title'))->save(); //Update the

127
database entry
$log2->delete(); //Delete the database entry

Heads up! Always use the setFields() and save() functions to alter a database entry and
the delete()function to delete one. Otherwise, the built-in cache manager may not be
updated, leading to unpredictable results.

Creating forms
Forms are easy to create and display. The simplest scenario is when we create a form for a
class that represents a database table. For our previous Logexample, we could add a form
like in the example below:

<?php namespace Efront\Plugin\AcmeReports\Model;

use Efront\Model\BaseModel;
use Efront\Model\Form;

class AcmeReports extends BaseModel {

const DATABASE_TABLE = 'logs';


protected $_fields =
array('id' => 'id',
'time' => 'timestamp',
'title' => '',
'content' => '',
);
public $id;
public $timestamp;
public $title;
public $content;

public function form($url) {


$form = new Form("log_form", "post", $url, "", null, true);
try {
$form->addElement(text', 'title', translate("Title"),
'class = "form-control"');
$form->addElement('textarea', 'content',
translate("Content"), 'class = "form-control ef-editor"');
$form->addElement('submit', 'submit', translate("Submit"),
'class = "btn btn-primary"');
$form->setDefaults($this->getFields());

if ($form->isSubmitted() && $form->validate()) {


try {
$values = $form->exportValues();

128
$values['body'] = $form
->handleInlineImages($values['body']);
$fields = array(
'title' => $values['title'],
'content' => $values['content']);

$this->setFields($fields)->save();
$form->success = true;
} catch (\Exception $e) {
handleNormalFlowExceptions($e);
}
}
} catch (\Exception $e) {
handleNormalFlowExceptions($e);
}
return $form;
}
}

In order to output the form, in your controller you must call the form and assign it to the
template:

$log = new Log();


$form = $log
->form(UrlHelperController::url(array('ctg'=>'AcmeReports','add'=>1)));
$smarty->assign("T_FORM", $form->toArray());

129
And display it in your template:

{eF_template_printForm form=$T_FORM}

That’s it! The fields will display in the order they were
defined.printForm calls TemplateController::printForm() which supports very
elaborate structures, consult that function’s source for more information.

Heads up! If you use a controller that inherits from BaseController, then
calling parent::index() in your controller will automatically call your
model’s form() function, if the URL contains the /add/1 or /edit/<id>parameters. It will also
assign the form to your template, inside the $T_FORM variable

Javascript functions
eFrontPro comes with a number of high-level javascript functions to simplify common tasks,
through the $.fn.efront extension to jquery

1. Display a modal (popup) window, based on Bootstrap’s modal:

<script>
$.fn.efront('modal', {'header':'My modal title', 'body':'Modal
content'}); //Display a modal with this title and content
</script>

2. Display a confirmation box, based on bootboxjs:

<script>
$.fn.efront(
'confirm',
{
'title':'Confirm',
'body':'Are you sure?',
'success': {
'class_name':'btn-danger',
'label':'Yes',
'callback': function(result) {
/*do something if Yes is clicked */
}
},

'fail': {
'callback': function(result) {
/*do something if No is clicked */
}

130
}
});
</script>

3. Perform an ajax request, with built-in error handling, based on jquery’s


$.ajax() call:

<script>
$.fn.efront('ajax', location.toString(), { data:{ 'ajax':1}},
function(response, textStatus, jqXHR) { /*executes on success*/ },
function(response, textStatus, jqXHR) { /*executes on failure*/ } );
</script>

1-minute introduction to smarty


So, it seems that for creating a plugin you need to learn yet another language? Fear not,
smarty is painfully easy to use Assigning a variable from PHP to Smarty…

<?php
$variable = "John Doe";
$smarty->assign(“T_VAR”, $variable);
?>

…and accesing it in the template file:

Hello mr {$T_VAR}, how are you today?

Conditionals:

<div class = "world">


{if $some_var_value} Goodmorning world! {else} Goodnight world! {/if}
</div>

131
Loops:

<ul>
{foreach $array_variable as $value}
<li>$value</li>
{/foreach}
</ul>

Variables:

{$simple_var = "John doe"}


{capture name = "much_code"} John Doe’s CV: blah blah blah {/capture}
Here you can see {$simple_var}’s CV: {$smarty.capture.much_code}

Javascript: Always leave a space after opening brackets, to keep smarty from parsing it as
smarty code:

//will throw a smarty error:


<script>var obj = {name:'test',value: 'test'}</script>
//Correct!
<script>var obj = { name: 'test',value:'test }</script>

eFrontPro specific functions:

{eF_template_printBlock data = $data}


//Prints $data wrapped inside a standard block
{eF_template_printForm form = $form}
//Prints $form, where $form is a standard efrontpro $form array

Had enough yet? Access the Smarty3 manual for the complete documentation

1)
Spaces and special or international characters are not allowed for the plugin name

132

You might also like