Skip to content

Instantly share code, notes, and snippets.

@stevewithington
Forked from mattlevine/7_1_notes.md
Created January 18, 2018 21:16
Show Gist options
  • Save stevewithington/6332dbd4e43d23923cb4a61d582410f2 to your computer and use it in GitHub Desktop.
Save stevewithington/6332dbd4e43d23923cb4a61d582410f2 to your computer and use it in GitHub Desktop.

DOCKER FIRST (Webinar)

7.1 was designed with a Docker first work flow in mind.

Docker allows increased support for Continuous Deployment and Testing, Multi-Cloud Platforms, Environment Standardization and Version Control. As well as better Isolation and Security (stolen from https://dzone.com/articles/5-key-benefits-docker-ci)

  • Continuous Deployment
    • Challenge meets Skill Level (Expert)
    • Eliminates Distractions
    • Reduces Worry of Failure
  • Testing
    • Clear Goals Established
    • Clear and Timely Feedback
    • Challenge meets Skill Level (Expert)
    • Reduces Worry of Failure
  • Multi-Cloud Platform support
    • Challenge meets Skill Level (Expert)
    • Eliminates Distractions
    • Reduces Worry of Failure
  • Isolation
    • Reduces Worry of Failure
  • Security
    • Reduces Worry of Failure

Base Lucee Image: https://bitbucket.org/blueriver/lucee/src/5d269b26a6e28bffdb21ac70b35325542009656b/5.2.3.35/?at=master

Official Image: https://hub.docker.com/r/blueriver/muracms/

Official Image: https://hub.docker.com/r/blueriver/mura/

Example Dockerfiles: https://github.com/blueriver/docker-muracms

SETTINGS.INI.CFM Variables

  • Eliminates Distractions
  • Reduces Worry of Failure

All settings.ini.cfm variables can be set by environmental variables. This is important with stateless cluster and Docker. You can now more easily run your code in different environments from a single repository branch.

You can see examples of how that works in the docker-compose.yml files. Essentially the setting.in.cfm file may not be used in many cases.

https://github.com/blueriver/MuraCMS/blob/7.1/core/docker/local-mysql/docker-compose.yml#L14-L26

Easy S3 Integration with Environment Variables

In today's modern world where applications are deployed as clustered, stateless, immutable services it's more important than ever to be able configure Mura to store dynamic assets in a scallable object store. This allow any upload asset to immediately available to all services that may request access. This allows you to scale up or down cluster instances as needed.

  • Eliminates Distractions
  • Reduces Worry of Failure
MURA_ASSETPATH: "https://s3-us-west-1.amazonaws.com/{your_bucket}/"
MURA_S3ASSETS: "s3://{client_id}:{client_secret}@/{your_bucket}/"
MURA_ASSETDIR: "/s3assets"
MURA_FILEDIR: "/s3assets"

Easy Integration with External Caches

In today's modern world where applications are deployed as clustered, stateless, immutable services it's more important than ever to be able configure Mura to store session, data and output caches to use a external services. This allows you to scale up or down cluster instances as needed.

  • Eliminates Distractions
  • Reduces Worry of Failure

{mura_root}/config/cfapplication.cfm

<cfscript>
	this.cache.connections["sessions"] = {
		  class: 'org.lucee.extension.io.cache.memcache.MemCacheRaw'
		, bundleName: 'memcached.extension'
		, bundleVersion: '3.0.2.29'
		, storage: true
		, custom: {
			"socket_timeout":"30",
			"initial_connections":"1",
			"alive_check":"true",
			"buffer_size":"1",
			"max_spare_connections":"32",
			"storage_format":"Binary",
			"socket_connect_to":"3",
			"min_spare_connections":"1",
			"maint_thread_sleep":"5",
			"failback":"true",
			"max_idle_time":"600",
			"max_busy_time":"30",
			"nagle_alg":"true",
			"failover":"true",
			"servers": "memcached:11211"
		}
		, default: ''
	};
	this.sessionCluster = true;
	this.sessionStorage = "sessions";

        /*
	{siteid}-data Cache connection for the default site's data cache
	This will be used if you have set advancedCaching=true in /config/settings.ini.cfm
	or set Mura_ADVANCEDCACHING="true" environment variable
	*/
        this.cache.connections["default-data"] = {
		  class: 'org.lucee.extension.io.cache.memcache.MemCacheRaw'
		, bundleName: 'memcached.extension'
		, bundleVersion: '3.0.2.29'
		, storage: true
		, custom: {
			"socket_timeout":"30",
			"initial_connections":"1",
			"alive_check":"true",
			"buffer_size":"1",
			"max_spare_connections":"32",
			"storage_format":"Binary",
			"socket_connect_to":"3",
			"min_spare_connections":"1",
			"maint_thread_sleep":"5",
			"failback":"true",
			"max_idle_time":"600",
			"max_busy_time":"30",
			"nagle_alg":"true",
			"failover":"true",
			"servers": "memcached:11211"
		}
		, default: ''
	};
	
	 /*
	{siteid}-output Cache connection for the default site's output cache
	This will be used if you have set advancedCaching=true in /config/settings.ini.cfm
	or set Mura_ADVANCEDCACHING="true" environment variable
	*/
	this.cache.connections["default-output"] = {
		  class: 'org.lucee.extension.io.cache.memcache.MemCacheRaw'
		, bundleName: 'memcached.extension'
		, bundleVersion: '3.0.2.29'
		, storage: true
		, custom: {
			"socket_timeout":"30",
			"initial_connections":"1",
			"alive_check":"true",
			"buffer_size":"1",
			"max_spare_connections":"32",
			"storage_format":"Binary",
			"socket_connect_to":"3",
			"min_spare_connections":"1",
			"maint_thread_sleep":"5",
			"failback":"true",
			"max_idle_time":"600",
			"max_busy_time":"30",
			"nagle_alg":"true",
			"failover":"true",
			"servers": "memcached:11211"
		}
		, default: ''
	};
</cfscript>

CaaS (Webinar)

With Mura's robust Docker support and full API it can easily be used and content distribution endpoint or be used as a headless CMS.

  • Challenge meets Skill Level (Beginner, Novice, Expert)
  • Eliminates Distractions

MuraORM

Scaffolder/Assembler

With Mura Scaffolding custom Mura ORM entities can be managed with simple convention based UI. Great for flushing out content to that can be made available via Mura's JSON API.

  • Challenge meets Skill Level (Expert)
  • Eliminates Distractions
  • Reduces Worry of Failure

With Mura's new Assembler super users can now easily define custom Mura entities withou any need to touch code.

  • Challenge meets Skill Level (Beginner, Novice)
  • Eliminates Distractions
  • Reduces Worry of Failure

Auto Generated Swagger Definitions

Mura 7.1 now automatically generates swagger.json files for Mura ORM entities, enabling use of the world's largest api tooling framework.

  • Eliminates Distractions
  • Reduces Worry of Failure
  • Challenge meets Skill Level (Expert)

http://domain.com/index.cfm/_api/json/v1/{siteid}/swagger

http://domain.com/index.cfm/_api/json/v1/{siteid}/swagger?entities={entityname}

https://swagger.io/

Mura Feed Aggregate Queries

Mura 7.1 introduces the ability to do aggregate queries greatly decreasing instances where developers would need to write api helper methods with custom queries against Mura ORM generated schema.

  • Eliminates Distractions
  • Reduces Worry of Failure
  • Challenge meets Skill Level (Beginner, Novice, Expert)

JS

<script>
  //This returns generic beans
  Mura.getFeed('car')
        .aggregate('count','*') //count 
        .aggregate('sum','price') //sum_price
        .aggregate('min','price') //min_price
        .aggregate('max','price') //max_price
        .aggregate('avg','price') //avg_price
        .getQuery()
        .then(function(resp){
          console.log(resp.getAll());
        });
</script>

CFML

<cfscript>
  rs=Mura.getFeed('car')
        .aggregate('count','*') //count 
        .aggregate('sum','price') //sum_price
        .aggregate('min','price') //min_price
        .aggregate('max','price') //max_price
        .aggregate('avg','price') //avg_price
        .getQuery();
        
  //This returns generic beans
  iterator=Mura.getFeed('car')
        .aggregate('count','*') //count 
        .aggregate('sum','price') //sum_price
        .aggregate('min','price') //min_price
        .aggregate('max','price') //max_price
        .aggregate('avg','price') //avg_price
        .getIterator();
</cfscript>

Mura.js

When the maturity of Mura's containerization and JSON API Mura's javascript utility (Mura.js) is now managed as a separate project. It can easily be embeded in third part evironments and interact with Mura purely as a service through Mura.js JS classes.

  • Eliminates Distractions
  • Reduces Worry of Failure

https://github.com/blueriver/MuraJS

https://www.npmjs.com/package/mura.js

const express = require('express')
const app = express()
const Mura=require('../index');

Mura.init({
  siteid:'default',
  rootpath:'http://localhost:8080'
});

app.get('/', function (req, res) {
  Mura.getRequestContext(req, res).renderFilename('about').then(
    function(content){
      res.send("<br/>rendered content:<pre>" + JSON.stringify(content.getAll()) + "</pre>")
    },
    function(error){
      console.log(error);
    }
  );
})

Default Theme (Webinar)

There is no theme in Mura 7.1 core. There is a new defaultThemeURL settings.ini.cfm attribute

https://github.com/blueriver/MuraCMS/blob/7.1/core/mura/configBean.cfc#L58

That Mura will pull down from on install if no default site theme is found.

https://github.com/blueriver/MuraCMS/blob/7.1/core/appcfc/onApplicationStart_include.cfm#L229-L275

If Mura can't get out of the network on install it use it's backup theme

https://github.com/blueriver/MuraCMS/blob/7.1/core/templates/theme.zip.cfm

New 7.1 eventHandler capabilities (Blog)

Mura 7.1 add support for more granual event management syntax. In addidiotn, developers are no longer required to register eventHandlers across entire site or entities classes. You can now register events for specific entities. This allows for more focused business logic and code clarity.

  • Eliminates Distractions
  • Reduces Worry of Failure

CFML

<cfscript>
  function onApplicationLoad(Mura){

    Mura.getBean('content')
        .loadBy(filename='contact')
        .on('renderStart',function(Mura){
          //WriteDump('test1');abort;
        }
      );

    Mura.siteConfig()
        .on('renderStart',function(Mura){
          //WriteDump('test2');abort;
        }
      );

    Mura.globalConfig()
        .on('renderStart',function(Mura){
          //WriteDump('test3');abort;
        }
      );

    Mura.getBean('content')
        .loadBy(title='My Form')
        .on('submitSave',function(Mura){
          //WriteDump('test1');abort;
        }
      ).on('submitResponseRender',function(Mura){
        //WriteDump('test1');abort;
        }
      );

    Mura.getBean('widget')
        .loadBy(id='...')
        .on('beforeSave',function(Mura){
            //WriteDump('test1');abort;
          }
        ).on('save',function(Mura){
          //WriteDump('test1');abort;
        }).on('afterWidgetSave',function(Mura){
          //WriteDump('test1');abort;
          }
        ).addEventHandler({
          beforeSave=function(Mura){

          },
          save=function(Mura){

          },
          afterSave=function(Mura){

          }
        });

    Mura.siteConfig()
      .on('beforeWidgetSave',function(Mura){
          //WriteDump('test1');abort;
        }
      ).on('widgetSave',function(Mura){
        //WriteDump('test1');abort;
      }).on('afterWidgetSave',function(Mura){
        //WriteDump('test1');abort;
        }
      ).addEventHandler({
        renderStart=function(Mura){
          
        },
        widgetSave=function(Mura){

        },
        afterWidgetSave=function(Mura){

        }
      });

    Mura.globalConfig()
      .on('beforeWidgetSave',function(Mura){
          //WriteDump('test1');abort;
        }
      ).on('widgetSave',function(Mura){
        //WriteDump('test1');abort;
      }).on('afterWidgetSave',function(Mura){
        //WriteDump('test1');abort;
        }
      ).addEventHandler({
        beforeWidgetSave=function(Mura){

        },
        widgetSave=function(Mura){

        },
        afterWidgetSave=function(Mura){

        }
      });

  }
</cfscript>

JS

<script>
Mura(".myclass").addEventHandler(
 {
    click:function(a){
      
    },
    touch:function(a){
       
     }
  }
);
</script>

New Events

These are fired when a structured image (associated image) is re-cropped, flipped or rotated and would primarily be use to tell a CDN to clear the existing version from cache

  • onBeforeImageManipulation
  • onAfterImageManipulation

General (blog)

Pathing to core

https://github.com/blueriver/MuraBootstrap3/blob/7.1/templates/inc/html_head.cfm#L16-L18

Auto Updating

  • Reduces Worry of Failure

In order to prevent Mura instances from having out of sync code bases we have changed the autoupdater to only do complete updates. In addition you can edit the url where it pull from with the new autoupdaterurl settings.ini.cfm atttribute. This allows organizations to use their own code distribution endpoint.

https://github.com/blueriver/MuraCMS/blob/7.1/core/mura/configBean.cfc#L51

New Directory Structure

Site Files

  • Eliminates Distractions
  • Reduces Worry of Failure

In order to reduce un-expected version conflicts between site and core file versions we have eleminated site files. The default theme gets installed in the root/themes directory and the display objects live here:

https://github.com/blueriver/MuraCMS/tree/7.1/core/modules/v1

If we need to make a major change in modules we can add a v2 directory and a contentRenderer.cfc variables to tell each site which modules version to use.

Build Process

New buddy.works build process that will allow anyone to release a new build.

We probably don't really mention this one. It's basically all internal and it's us basically doing what we are supposed to do. In addition the Buddy.works pipelines are NOT public.

First Run tests https://app.buddy.works/blueriver/muracms/pipelines/pipeline/50718/executions

Tests live here: https://github.com/blueriver/MuraCMS/tree/7.1/core/tests

Then Deploy https://app.buddy.works/blueriver/muracms/pipelines/pipeline/51126/executions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment