CASH Music

12 min read Original article ↗

Platform documentation


The CASH Music platform gives all musicians access to tools that let them manage, promote, and sell their music online — all owned and controlled themselves.

The whole thing is designed to work as a freestanding API or integrated with publishing and CMS systems like Wordpress or Drupal. The standard repo contains the core framework, installers, an admin webapp, APIs, demos, and a full suite of tests.

github / twitter / facebook / development group

Setup and requirements

One of our goals is for this to run in as many places as possible, so we've worked hard to keep the requirements as minimal as possible:

  • PHP 5.2.7+
  • PDO and MySQL OR SQLite
  • mod_rewrite (for admin)
  • fopen wrappers OR cURL

Installation: Just fork/clone this repo, cd into the new /DIY folder, and run:

make install

choosing SQLite will get you up and running fastest. Next just point Apache or MAMP at the /DIY directory and view http://localhost/ in a browser.

There's a web installer for non-coders here. The idea is that we make it easy to deploy on any shared server.

Code standards

When in doubt, code for legibility and easy adoption. Capitalization and CamelCase should be used for class names, camelCase starting with lowercase for function names, and variable names in snake_case (lowercase and underscores.) Indentation has been kept simple — a single hard tab for each level, with curly brackets on the same line as the control statement.

So a simplified file will look something like:

/**
 * Description
 *
 * @package seed.org.cashmusic
 * @author CASH Music
 * @link http://cashmusic.org/
 *
 * Copyright (c) 2012, CASH Music
 * Licensed under the Affero General Public License version 3.
 * See http://www.gnu.org/licenses/agpl-3.0.html
 *
 */class ClassName {
    protected $variable;

    /**
     * Function Description
     *
     * @return value
     */public function functionName($input_variable) {
        $variable_name = 'text';
        return $variable_name;
    }
} // END class 

Each class should have a file of it's own.

No class is final without formatted comments.

Core framework PHP API

All functionality of the core platform is accessed through a single and consistent PHP-based API. No direct function calls should be made — instead data should be accessed and set through a secure and standard request / response model consistent with any HTTP GET/POST requests.

Request / response format

For developers looking to build custom functionality we've built a request/response process as the primary interface to the PHP framework. It mimics a REST-style API and standardizes calls and responses across the methods...so the PHP interaction will be nearly identical to future REST or verbose interactions.

Every request is made with a specific type and action, plus any required or optional parameters. It's response will contain an http-esque status code, a uid containing type/action/code, a human-readable status message, a more detailed contextual message, an echo of the request type and action, a payload with the full response data or false if the request failed, the api version, and a timestamp.

The PHP Request/Response looks like this:

<?php 
    $sample_request = new CASHRequest(
        array(
            'cash_request_type' => 'calendar', 
            'cash_action' => 'getevent',
            'id' => 43
        )
    );

    $sample_request->resonse:
    {
        "status_code":404, // http-style status code
        "status_uid":"calendar_getevent_404", // uid of the response (request + status)
        "status_message":"Not Found", // http-style status message
        "contextual_message":"Event not found", // more specific error message
        "request_type":"calendar", // echo of the request type
        "action":"getevent", // echo of the request action
        "payload":false, // contents of the response, or false if error
        "api_version":2, // version number
        "timestamp":1335416260 // request timestamp
    }
?>

System requests

All actions defined for 'system' type requests:

system / addlogin

Allowed methods: direct

Parameters
address (REQUIRED)
password (REQUIRED)
is_admin (default: 0)
username (default: '')
display_name (default: 'Anonymous')
first_name (default: '')
last_name (default: '')
organization (default: '')
address_country (default: '')
force52compatibility (default: false)
data (default: '')

system / addlockcode

Allowed methods: direct

Parameters
scope_table_alias (REQUIRED)
scope_table_id (REQUIRED)
user_id (default: 0)

system / deletesettings

Allowed methods: direct

Parameters
user_id (REQUIRED)
type (REQUIRED)

system / deletetemplate

Allowed methods: direct

Parameters
template_id (REQUIRED)
user_id (default: false)

system / getapicredentials

Allowed methods: direct

Parameters
user_id (REQUIRED)

system / getlockcodes

Allowed methods: direct

Parameters
scope_table_alias (REQUIRED)
scope_table_id (REQUIRED)
user_id (default: false)

system / getnewesttemplate

Allowed methods: direct

Parameters
user_id (REQUIRED)
type (default: 'page')
all_details (default: false)

system / getsettings

Allowed methods: direct

Parameters
user_id (REQUIRED)
type (REQUIRED)
return_json (default: false)

system / gettemplate

Allowed methods: direct

Parameters
template_id (REQUIRED)
user_id (default: false)
all_details (default: false)

system / gettemplatesforuser

Allowed methods: direct

Parameters
user_id (REQUIRED)
type (default: false)

system / migratedb

Allowed methods: direct

Parameters
todriver (REQUIRED)
tosettings (REQUIRED)

system / redeemlockcode

Allowed methods: direct, get, post

Parameters
code (REQUIRED)
scope_table_alias (default: false)
scope_table_id (default: false)
user_id (default: false)

system / setapicredentials

Allowed methods: direct

Parameters
user_id (REQUIRED)

system / setlogincredentials

Allowed methods: direct

Parameters
user_id (REQUIRED)
address (default: false)
password (default: false)
username (default: false)

system / setresetflag

Allowed methods: direct

Parameters
address (REQUIRED)

system / setsettings

Allowed methods: direct

Parameters
user_id (REQUIRED)
type (REQUIRED)
value (REQUIRED)

system / settemplate

Allowed methods: direct

Parameters
user_id (REQUIRED)
type (default: false)
name (default: false)
template (default: false)
template_id (default: false)

system / validateapicredentials

Allowed methods: direct

Parameters
api_key (REQUIRED)
api_secret (default: false)

system / validatelogin

Allowed methods: direct

Parameters
address (REQUIRED)
password (REQUIRED)
require_admin (default: false)
verified_address (default: false)
browserid_assertion (default: false)
element_id (default: NULL)
keep_session (default: false)

system / validateresetflag

Allowed methods: direct, get, post

Parameters
address (REQUIRED)
key (REQUIRED)

Asset requests

All actions defined for 'asset' type requests:

asset / addasset

Allowed methods: direct

Parameters
title (REQUIRED)
description (REQUIRED)
user_id (REQUIRED)
location (default: '')
connection_id (default: 0)
hash (default: '')
size (default: 0)
public_url (default: '')
type (default: 'file')
tags (default: false)
metadata (default: false)
parent_id (default: 0)
public_status (default: 1)

asset / addlockcode

Allowed methods: direct

Parameters
asset_id (REQUIRED)

asset / claim

Allowed methods: get, post, direct

Parameters
id (REQUIRED)
element_id (default: 0)

asset / deleteasset

Allowed methods: direct

Parameters
id (REQUIRED)
user_id (default: false)

asset / editasset

Allowed methods: direct

Parameters
id (REQUIRED)
hash (default: false)
size (default: false)
location (default: false)
title (default: false)
description (default: false)
public_url (default: false)
connection_id (default: false)
type (default: false)
parent_id (default: false)
public_status (default: false)
user_id (default: false)
tags (default: false)
metadata (default: false)

asset / finalizeupload

Allowed methods: direct

Parameters
connection_id (REQUIRED)
filename (REQUIRED)

asset / findassets

Allowed methods: direct

Parameters
query (REQUIRED)
user_id (REQUIRED)
page (default: 1)
max_returned (default: 10)

asset / getanalytics

Allowed methods: direct

Parameters
analtyics_type (REQUIRED)
user_id (REQUIRED)

asset / getasset

Allowed methods: direct

Parameters
id (REQUIRED)
user_id (default: false)

asset / getassetsforconnection

Allowed methods: direct

Parameters
connection_id (REQUIRED)

asset / getassetsforparent

Allowed methods: direct

Parameters
parent_id (REQUIRED)

asset / getassetsforuser

Allowed methods: direct

Parameters
user_id (REQUIRED)
type (default: false)
parent_id (default: false)

asset / getasseturl

Allowed methods: direct

Parameters
connection_id (REQUIRED)
user_id (REQUIRED)
asset_location (REQUIRED)
params (default: false)

asset / getfulfillmentassets

Allowed methods: direct

Parameters
asset_details (REQUIRED)
type (default: 'fulfillment')

asset / getuploadparameters

Allowed methods: direct

Parameters
connection_id (REQUIRED)
user_id (REQUIRED)

asset / makepublic

Allowed methods: direct

Parameters
id (REQUIRED)
user_id (default: false)

asset / redeemcode

Allowed methods: direct, get, post

Parameters
code (REQUIRED)
user_id (default: false)
element_id (default: false)

asset / unlock

Allowed methods: direct

Parameters
id (REQUIRED)

People requests

All actions defined for 'people' type requests:

people / addaddresstolist

Allowed methods: direct

Parameters
address (REQUIRED)
list_id (REQUIRED)
do_not_verify (default: false)
initial_comment (default: '')
additional_data (default: '')
name (default: 'Anonymous')
force_verification_url (default: false)
request_from_service (default: false)
service_opt_in (default: true)
extra_querystring (default: '')
first_name (default: '')
last_name (default: '')

people / addcontact

Allowed methods: direct

Parameters
email_address (REQUIRED)
user_id (REQUIRED)
first_name (default: '')
last_name (default: '')
organization (default: '')
address_line1 (default: '')
address_line2 (default: '')
address_city (default: '')
address_region (default: '')
address_postalcode (default: '')
address_country (default: '')
phone (default: '')
notes (default: '')
links (default: '')

people / addmailing

Allowed methods: direct

Parameters
user_id (REQUIRED)
list_id (REQUIRED)
connection_id (REQUIRED)
subject (REQUIRED)
template_id (default: 0)
html_content (default: '')
text_content (default: '')
from_name (default: '')

people / addlist

Allowed methods: direct

Parameters
name (REQUIRED)
user_id (REQUIRED)
description (default: '')
connection_id (default: 0)

people / checkverification

Allowed methods: direct

Parameters
address (REQUIRED)
list_id (REQUIRED)

people / deletelist

Allowed methods: direct

Parameters
list_id (REQUIRED)
user_id (default: false)

people / editcontact

Allowed methods: direct

Parameters
id (REQUIRED)
email_address (default: false)
first_name (default: false)
last_name (default: false)
organization (default: false)
address_line1 (default: false)
address_line2 (default: false)
address_city (default: false)
address_region (default: false)
address_postalcode (default: false)
address_country (default: false)
phone (default: false)
notes (default: false)
links (default: false)
user_id (default: false)

people / editlist

Allowed methods: direct

Parameters
list_id (REQUIRED)
name (default: false)
description (default: false)
connection_id (default: false)
user_id (default: false)

people / editmailing

Allowed methods: direct

Parameters
mailing_id (REQUIRED)
send_date (default: false)
subject (default: false)
html_content (default: false)
text_content (default: false)
user_id (default: false)
from_name (default: false)

people / getaddresslistinfo

Allowed methods: direct

Parameters
address (REQUIRED)
list_id (REQUIRED)

people / getanalytics

Allowed methods: direct

Parameters
analtyics_type (REQUIRED)
user_id (default: 0)
list_id (default: false)

people / getcontact

Allowed methods: direct

Parameters
id (REQUIRED)
user_id (default: false)

people / getcontactsbyinitials

Allowed methods: direct

Parameters
user_id (REQUIRED)
initial (REQUIRED)

people / getcontactinitials

Allowed methods: direct

Parameters
user_id (REQUIRED)

people / getlistsforuser

Allowed methods: direct

Parameters
user_id (REQUIRED)

people / getlist

Allowed methods: direct, api_key

Parameters
list_id (REQUIRED)
user_id (default: false)

people / getmailing

Allowed methods: direct

Parameters
mailing_id (REQUIRED)
user_id (default: false)

people / getmailinganalytics

Allowed methods: direct

Parameters
mailing_id (REQUIRED)
user_id (default: false)

people / getuser

Allowed methods: direct

Parameters
user_id (REQUIRED)

people / getuseridforaddress

Allowed methods: direct

Parameters
address (REQUIRED)
with_security_credentials (default: false)

people / getuseridforusername

Allowed methods: direct

Parameters
username (REQUIRED)

people / processwebhook

Allowed methods: direct, api_key

Parameters
origin (REQUIRED)
user_id (REQUIRED)
list_id (default: 0)
type (default: false)
data (default: false)
mandrill_events (default: false)

people / recordmailinganalytics

Allowed methods: direct

Parameters
mailing_id (REQUIRED)
sends (default: 0)
opens_total (default: 0)
opens_mobile (default: 0)
opens_country (default: false)
opens_id (default: false)
click_url (default: false)
failures (default: 0)
user_id (default: false)

people / removeaddress

Allowed methods: direct, post, get, api_key

Parameters
address (REQUIRED)
list_id (REQUIRED)

people / sendmailing

Allowed methods: direct

Parameters
mailing_id (REQUIRED)
user_id (default: false)

people / signintolist

Allowed methods: post, get, direct, api_key

Parameters
address (REQUIRED)
password (REQUIRED)
list_id (REQUIRED)
browserid_assertion (default: false)
element_id (default: NULL)

people / signup

Allowed methods: direct, post, get, api_key

Parameters
list_id (REQUIRED)
address (REQUIRED)
user_id (default: false)
comment (default: '')
name (default: 'Anonymous')
element_id (default: false)
first_name (default: '')
last_name (default: '')
additional_data (default: '')

people / verifyaddress

Allowed methods: direct, post, get

Parameters
address (REQUIRED)
list_id (REQUIRED)
verification_code (REQUIRED)

people / viewlist

Allowed methods: direct

Parameters
list_id (REQUIRED)
unlimited (default: false)
user_id (default: false)

Commerce requests

All actions defined for 'commerce' type requests:

commerce / additem

Allowed methods: direct

Parameters
user_id (REQUIRED)
name (REQUIRED)
description (default: '')
sku (default: '')
price (default: 0)
flexible_price (default: 0)
available_units (default: -1)
digital_fulfillment (default: 0)
physical_fulfillment (default: 0)
physical_weight (default: 0)
physical_width (default: 0)
physical_height (default: 0)
physical_depth (default: 0)
variable_pricing (default: 0)
fulfillment_asset (default: 0)
descriptive_asset (default: 0)

commerce / addorder

Allowed methods: direct

Parameters
user_id (REQUIRED)
order_contents (REQUIRED)
transaction_id (default: -1)
physical (default: 0)
digital (default: 0)
cash_session_id (default: '')
element_id (default: 0)
customer_user_id (default: 0)
fulfilled (default: 0)
canceled (default: 0)
notes (default: '')
country_code (default: '')
currency (default: 'USD')

commerce / addtransaction

Allowed methods: direct

Parameters
user_id (REQUIRED)
connection_id (REQUIRED)
connection_type (REQUIRED)
service_timestamp (default: '')
service_transaction_id (default: '')
data_sent (default: '')
data_returned (default: '')
successful (default: -1)
gross_price (default: 0)
service_fee (default: 0)
status (default: 'abandoned')
currency (default: 'USD')

commerce / deleteitem

Allowed methods: direct

Parameters
id (REQUIRED)
user_id (default: false)

commerce / edititem

Allowed methods: direct

Parameters
id (REQUIRED)
name (default: false)
description (default: false)
sku (default: false)
price (default: false)
flexible_price (default: false)
available_units (default: false)
digital_fulfillment (default: false)
physical_fulfillment (default: false)
physical_weight (default: false)
physical_width (default: false)
physical_height (default: false)
physical_depth (default: false)
variable_pricing (default: false)
fulfillment_asset (default: false)
descriptive_asset (default: false)
user_id (default: false)

commerce / editorder

Allowed methods: direct

Parameters
id (REQUIRED)
fulfilled (default: false)
canceled (default: false)
notes (default: false)
country_code (default: false)
customer_user_id (default: false)
order_contents (default: false)
transaction_id (default: false)
physical (default: false)
digital (default: false)
user_id (default: false)

commerce / edittransaction

Allowed methods: direct

Parameters
id (REQUIRED)
service_timestamp (default: false)
service_transaction_id (default: false)
data_sent (default: false)
data_returned (default: false)
successful (default: false)
gross_price (default: false)
service_fee (default: false)
status (default: false)

commerce / getanalytics

Allowed methods: direct

Parameters
analtyics_type (REQUIRED)
user_id (REQUIRED)
date_low (default: false)
date_high (default: false)

commerce / getitem

Allowed methods: direct

Parameters
id (REQUIRED)
user_id (default: false)

commerce / getitemsforuser

Allowed methods: direct

Parameters
user_id (REQUIRED)

commerce / getorder

Allowed methods: direct

Parameters
id (REQUIRED)
deep (default: false)
user_id (default: false)

commerce / getordersforuser

Allowed methods: direct

Parameters
user_id (REQUIRED)
include_abandoned (default: false)
max_returned (default: false)

commerce / gettransaction

Allowed methods: direct

Parameters
id (REQUIRED)
user_id (default: false)

commerce / finalizepayment

Allowed methods: get, post, direct

Parameters
order_id (REQUIRED)
creation_date (REQUIRED)
direct_post_details (default: false)

commerce / initiatecheckout

Allowed methods: get, post, direct, api_public

Parameters
user_id (REQUIRED)
connection_id (REQUIRED)
order_contents (default: false)
item_id (default: false)
element_id (default: false)
total_price (default: false)
return_url_only (default: false)

Calendar requests

All actions defined for 'calendar' type requests:

calendar / addevent

Allowed methods: direct

Parameters
date (REQUIRED)
user_id (REQUIRED)
venue_id (REQUIRED)
purchase_url (default: '')
comment (default: '')
published (default: 0)
cancelled (default: 0)

calendar / addvenue

Allowed methods: direct

Parameters
name (REQUIRED)
city (REQUIRED)
address1 (default: '')
address2 (default: '')
region (default: '')
country (default: '')
postalcode (default: '')
url (default: '')
phone (default: '')

calendar / deletevenue

Allowed methods: direct

Parameters
venue_id (REQUIRED)

calendar / editevent

Allowed methods: direct

Parameters
event_id (REQUIRED)
date (default: false)
venue_id (default: false)
purchase_url (default: false)
comment (default: false)
published (default: false)
cancelled (default: false)
user_id (default: false)

calendar / editvenue

Allowed methods: direct

Parameters
venue_id (REQUIRED)
name (default: false)
address1 (default: false)
address2 (default: false)
city (default: false)
region (default: false)
country (default: false)
postalcode (default: false)
url (default: false)
phone (default: false)

calendar / findvenues

Allowed methods: direct

Parameters
query (REQUIRED)
page (default: 1)
max_returned (default: 12)

calendar / getallvenues

Allowed methods: direct

Parameters

calendar / geteventsbetween

Allowed methods: direct

Parameters
user_id (REQUIRED)
offset (default: 0)
cutoff_date_low (default: 'now')
cancelled_status (default: 0)
published_status (default: 1)
cutoff_date_high (default: 2051244000)

calendar / getevent

Allowed methods: direct

Parameters
event_id (REQUIRED)

calendar / getevents

Allowed methods: direct

Parameters
user_id (REQUIRED)
visible_event_types (REQUIRED)
offset (default: 0)
published_status (default: 1)
cancelled_status (default: 0)

calendar / getvenue

Allowed methods: direct

Parameters
venue_id (REQUIRED)

Element requests

All actions defined for 'element' type requests:

element / addelement

Allowed methods: direct

Parameters
name (REQUIRED)
type (REQUIRED)
options_data (REQUIRED)
user_id (REQUIRED)

element / addlockcode

Allowed methods: direct

Parameters
element_id (REQUIRED)

element / deleteelement

Allowed methods: direct

Parameters
id (REQUIRED)
user_id (default: false)

element / editelement

Allowed methods: direct

Parameters
id (REQUIRED)
name (REQUIRED)
options_data (REQUIRED)
user_id (default: false)

element / getanalytics

Allowed methods: direct

Parameters
analtyics_type (REQUIRED)
user_id (REQUIRED)
element_id (default: 0)

element / getelement

Allowed methods: direct

Parameters
id (REQUIRED)

element / getelementsforuser

Allowed methods: direct

Parameters
user_id (REQUIRED)

element / getelementtemplate

Allowed methods: direct

Parameters
element_id (REQUIRED)
return_template (default: false)

element / getmarkup

Allowed methods: direct

Parameters
id (REQUIRED)
status_uid (REQUIRED)
original_request (default: false)
original_response (default: false)
access_method (default: 'direct')
location (default: false)

element / getsupportedtypes

Allowed methods: direct

Parameters

element / redeemcode

Allowed methods: direct, get, post

Parameters
code (REQUIRED)
element_id (REQUIRED)

element / setelementtemplate

Allowed methods: direct

Parameters
element_id (REQUIRED)
template_id (REQUIRED)
user_id (default: false)

Elements

Elements are like a plugin, or functional bundle, for the CASH platform. Each one is a standalone package containing descriptive metadata, a controller class, view templates, and forms to plug into the admin app. Specifically, each element consists of:

  • A main controller class file
  • A support directory containing:
    • templates directory for mustache template views for every state (plus admin)
    • admin.php as a controller for the amdin template
    • image.jpg as a header/descriptive image
    • metadata.json containing a version number, friendly name, description, etc

Data for each instance of an element is stored as a JSON string in the database, so the data itself can be pretty flexible for each element type.

The public-facing code in the element is designed to respond to targeted POST and/or GET requests — so a CASH Request is made and the element responds to the CASH Response if the correct element_id was set along with the request. So an element is embedded with a single function call, and will respond automatically when interacted with. The whole idea being that it's a simple to use structure that can be powerful and flexible enough to innovate on top of the PHP API.

As a starting point, look at the StaticContent element.

Admin app

The admin app for the platform (/interfaces/php/admin) is a fairly straight-forward MVC-style webapp built with a front controller, individual controllers for each route, mustache views, and using the framework for the model instead of a traditional database layer. Basically it's dog-fooding the PHP API but building a much more complex app than a simple element.

Like the framework, the admin app is built with minimal requirements, not using any more robust PHP app frameworks. The reason for this decision was the distributed version of the platform — what we lose in functionality we gain in portability, which is a major concern.

In terms of structure, it's fairly simple:

  • At the root there's an .htaccess redirect pointing all incoming traffic at controller.php, which pulls in settings from constants.php
  • A page is rendered based on pieces found in the /components directory
  • Each page/route has a controller in /components/pages/controllers and the controller calls a mustache template from /components/pages/templates
  • We're in the process of moving localized text to the /components/text directory, and similarly menus are pulled out by language in the /components/menu directory
  • Two simple helper classes are found in the /classes directory
  • The main page UI is a simple mustache-based template found in /ui/default — there's not currently a setting in the admin to allow theming but it's essentially just a path change away

Currently the admin is more of a code-wrapper than an application with elegant UI/UX. Our prime focus is improving that, making each section of the admin feel intuitive and easy as well as adding more help infrastructure.

It shouldn't be lost that the admin app is structured to mirror the Request/Response types — this is very much on purpose with the goal of getting musicians and developers speaking the same language.

Also, Jackson.