Before you begin

Myna FlightPath is an application template that implements much of the infrastructure web developers typically have to create to start working on a web application. This allows you to write your business logic as plain JavaScript functions, your displays as EJS templates, and have your data objects automatically generated from the database, nearly eliminating the need to write SQL.

FlightPath Features

MVC framework

Strong separation of data, business logic and display.Each of these can be manipulated independent of the others.

Automatic model generation

If your application has a single datasource, FlightPath will create models for that datasource automatically, just when needed. FlightPath will also analyze foreign key relationships and create related models. Data type constraints are also analyzed and become validators. See: Model

URL “routes”

It is possible with FlightPath to map virtually any URL to an action. “appdir/book/get/12”, “appdir/mypage.html”, “appdir/index.sjs?controller=test&action=run” are all valid URLs. An action can even have multiple routes assigned to it.

A function on a Controller that takes input from a web request, sets data on the controller instance, and picks a View to render the data back to the browser.

bean

An instance of a beanClass. Represents a single object from a Model data store.

beanClass

A class associated with a Model that represents a “row” of data from that model. This class contains functions for getting and setting values, validating values, field metadata, etc. Also contains liks to related beans from related <models>

Behavior

A mixin class that overrides, alters, or appends functionality to a class. Behaviors can be applied to either Controllers or Models. See: Behaviors

camelCase

name format where all words are lower case, first letter of each word after the first capitalized, with no separation. ex: employeeAction

Controller

Refers to either a Controller class or instance. Controllers contain Actions manage Layouts, an contain Behaviors, and Filters

Element

Specialized View template for containing output snippets to be included in a View

Filter

A function applied in the init() function of a Controller to be executed before or after an Action. This can be used to alter how actions are performed without changing the actions themselves. For example authentication and permissions checks can be performed in filters and certain actions can be denied or audited. See: Controller.addFilter

file_case

a name format where all words are lower case, and separated by underbars(_). ex: employee_action

Helpers

Helpers are function libraries used inside of Views and Actions for repetitive tasks, usually related to generating output. See: $FP.helpers.Html

Layout

Specialized View template set in a Controller to wrap content created by an Action, See: Layouts

Model

Refers to either a Model class or instance. Models in FlightPath are static singletons (Only one instance per request). Model Functions can return one or more beanClass instances that contain the actual model data

ProperCase

name format where all words are lower case, first letter capitalized with no separation. ex: EmployeeAction

Route

A URL pattern that maps to a controller an d action. A FlightPath application can support multiple routes. See: Routes

url-case

a name format where all words are lower case, and separated by underbars(_) or dashs(-). ex: employee-action, employee_action

View

An .ejs template intended to be sent to the browser. There are also specialized views: Layouts and Elements

Getting Started

To create a FlightPath template, navigate to the Myna Administrator and select “Add/Update FlightPath App”, and enter a path and folder name, relative to the Myna web root. If this directory does not exist, it will be created. Once The FlightPath template has been unpacked you will see a directory structure like this:

+-application.sjs+-app/ +...+-framework/ +...

The “framework” folder contains the FlightPath framework code. These files will be overwritten future uses of the “Add/Update FlightPath App” feature. Here you will find built-in controllers and behaviors such as Controller: Direct and Behavior: MynaAuth. You should not modify any files in this folder.

”app” sub-folders

Stores Controller files. File names should be lower case with underbars (_) between words and “_controller” on the end, e.g. MyItem becomes my_item_controller.sjs. The global.sjs file is included before every controller file. Use this file for global initialization and/or to add common functions to all controllers. The init() in the global.sjs file is executed before the controller’s init()

models

Stores Model files. File names should be lower case with underbars (_) between words and “_model” on the end, e.g. MyItem becomes my_item_model.sjs. The global.sjs file is included before every model file. Use this file for global initialization and/or to add common functions to all models. The init() in the global.sjs file is executed before the model’s init()

modules

Modules are self-contained FlightPath applications that can be embedded in other applications. These controllers, models and views can be accessed as if they were in the main application. See: Modules

static

This folder contains static content that will not be interpreted as Myna or FlightPath code. These files are accessed via http://server.tld/appname/static/filename This is a good place for images, client-side JavaScript files and css files

views

This folder contains a sub-folder for each controller that has views. For example the view for the Main controller’s index() action would be views/main/index.ejs

All that extra HTML wrapping your view is coming from the default layout in app/views/layouts/default.ejs. Unless you make a call to Controller.setLayout all views in your app will be wrapped in this layout. You can manipulate the metadata in this layout by setting properties on Controller.$page. Let’s set a title for our page.

This creates a local database with some example tables for a blog application. Have a look at Myna.Admin, Myna.Database and Myna.Table for more details. If you were including this in a real application, you might limit it to development environments or at least move it to onApplicationStart which runs less often.

Notice that the names are plural, and the primary and foreign keys are defined. This is important for the Models to properly auto generate (See: Model.Model Conventions).

Creating a post editor

Lets create a way to edit our posts.

//in app/controllers/post_controller.sjsfunction edit(params){ // Generate ID for new record if none-supplied. That way ID will be in // the URL and refreshing the page won't create a new record if (!params.id){ $FP.redirectTo({ id:this.model.genKey() }) }

// only get here if not re-directed this.set("bean",this.model.get(params));}

Here we’re creating an “edit” action that can be used for both new posts and existing posts. New posts will generate a unique key that will be used when the post is saved. If you looks at ManagerObject.genKey, you will see that for tables with a varchar primary key, the default key generator outputs UUID’s. This can be overridden in Model definitions. See $FP.redirectTo for how redirects work.

Finally, we set a local “bean” property with the result of “this.model.get(params)” (See: Model.get). This creates a temporary bean that contains either the data of an existing bean, or the default values for a new bean

Note the form action. Here we are using the Html helper (see: $FP.helpers.Html) to make a URL for our “save” action. Next, note that the “bean” property we set in the action is now a global variable in the view (See: Views). We’re using <Model.beanClass.getLabel> to get a label for each field. This allows for centralized field name definition in Model files, and potentially even international language translation.

The bean’s getters (get_created, get_slug, etc) will return either the current value or the default value defined in the Model file, depending on whether this is a new or an existing record.

Notice the line containing “bean.Author()”. This is accessing the related parent author bean. Myna knows that Posts belongTo Authors because of the foreign key defined on the posts table. If this is a new post then there will not be an associated parent Author record. In this case a new parent record will be created. Normally you would probably want to have a <select> here and have a separate Author controller manage Author records. On the next line, notice that the name for the input field is “Author.name”. Myna recognizes structure and array notation in query variables and attempts to reconstruct complex objects from them (See: $req.data and Object.setByPath) This means that the “params” object passed the “save” action will have an Author object with a “name” property. Because the Post model knows that it belongsTo Author, it will automatically create or load the related Author record and set its “name” property. More on that when we get to save()

Notice that we are doing something similar with PostContent. Because the post_contents table has a foreign key to posts, the Post model knows it potentially has a “hasMany” or “hasOne” relationship with post_contents. By using “PostContent.content” we are using the “hasOne” relationship to create a content row and associate it with this post.

Here we create a temporary bean via Model.get and the attempt to save it via <Model.beanClass.save>, which returns a Myna.ValidationResult. If successful we redirect to the index page, otherwise back to the edit page. The extra parameters to redirectTo (“success” and “error”) are converted into $flash messages and displayed via the default layout

”ds”

This structure lists data sources and their manager aliases, where the property is the alias, and the value is the DS name. Normally you only need the default data source. However, if you need access to models from multiple data sources, list them here. Note that you also need to set the manager property of the model to match the manager alias defined here, for any models beyond the default model/DS

”homeRoute”

Defines the default route the will be executed when no url is provided, i.e. “http/server.tld/appname/”. This structure should include everything that should be passed as “params” to the action

”routes”

”frameworkFolder”

Defaults to “framework”. This is the MynaPath to where the framework folder is located. Setting this to a central location will allow all FlightPath apps to share these files and be upgraded at once. Using the example path of “file:/home- /mark- /myna- /web- /shared- /js- /FlightPath- /framework” will cause the app to always use the version of the FlightPath framework included with the server. When Myna is upgraded, this folder is as well.

”MyCustomProperty”

All properties in the config will be applied to $FP and are available there from any model, controller or view

Behaviors

Behaviors are functions that are applied to the current object.

Behaviors can be applied to either models or controllers to modify their functionality. If you want to add a set of functions multiple controllers or models behaviors are a good mechanism.

In the case of a name conflict, custom behaviors hide built-in behaviors

Example

//in some_controller.sjsfunction init(){ // loads the built-in PDF andJSON filters // Each of these has an "init" function that adds the appropriate // before and after filters this.applyBehavior([ "FormatPdf", "FormatJson" ]);

See

Layouts

A layout file is a specialized view (see: Views) that is intended to wrap content before sending it to the browser.

Layout Locations

Global Default

app/views/layouts/default.ejs

Controller Default

app/views/layouts/<controller name>/default.ejs

General Layouts

app/views/layouts/<layout name>.ejs

General layouts are stored in app/views/layouts/<layout name>.ejs. The global default layout is stioreController default layouts are store Layouts are applied by calling Controller.addLayout or Controller.setLayout

Layouts can wrap other layouts. For example the global default layout wraps the controller Layouts are layered like so:

Modules

Modules are self-contained FlightPath applications that can be embedded in other applications. These controllers, models and views can be accessed as if they were in the main application.

A module can be created from a FlightPath application by copying its “app” folder to the new application’s “app/modules” folder and then renaming it to the module name. Then all folders except “models”, “controllers” and “views” should be removed. Local models, controllers and views are always found before module models, controllers and views, so published modules should have names that are unique for these objects.

Routes

Routes are URL patterns that can be mapped to controllers and actions. Routes are defined in the config section of the application.sjs for your app (See: FlightPath Config). An incoming URL is matched against the routes array from top to bottom, exiting early if a match is found

Variable placeholders start with $ and can only consist of letters, numbers and the underbar (_). Variable placeholders capture the token in the URL at the position where they appear and assign that value to the route property that has the same value as the placeholder.

Views

View Templates are .ejs templates used to render the result of an action. They are stored in app/views. Normally views are loaded automatically for a given controller and action by looking in app/views/<controller name>/<controller_name>_<action_name>.ejs. Views can also be directly rendered via Controller.render