Coded something up in Couch in an interesting way? Have a snippet or shortcode to share? Post it here for the community to benefit.
26 posts Page 1 of 3
Hi,

There should be more information about reusable code, I guess.
In hopes this topic expands daily usable skills towards more comfortable re-use of shared code.

Functions are good, because we can send different data there and receive results without rewriting / adapting code each time. Variable names and content, in practice, are different but operations are the same.

UPDATE: See KK's release of functions to CouchCMS and new tutorial

UPDATE 2: Repository CmsFu » functions is now the place to download funcs.

UPDATE 3: Addon Tweakus Dilectus » "Func-on-demand" has been published intended to autoload funcs placed in snippets.

UPDATE 4: A proper dedicated documentation page at Midware Concepts » Reusable Functions has been published.


Complete snippet-as-a-function code in attachment:
sum.zip
Sum
(736 Bytes) Downloaded 2896 times


Code: Select all
// General and important concept of function is 

some_function( ->incoming data1, ->incoming data2, ... etc){

   ... operation over incoming datas

  outgoing result->
}


A great deal of calling functions is abstraction of its variables - somefunction('1','2') will perform the same as some_function( my_var1, some_other_var55 ) - no matter how the variables are named, it doesn't make any difference.


Sample for today is very simple, with didactic purpose: sum of numbers (1) and averaging a set of people's ages (2). Both operations share the same "cms:add" tag.


Let's take a regular code that sums values. It already has CouchCMS's tags (functions) that take data arguments and return values (cms:each, cms:add, cms:show). The problem: to apply the same logic to anything else besides summing numbers - as we need to average ages - we would have to copy-paste this code or write it again and change variables. It is not comfortable if code is more than 5 lines.

Code: Select all
<cms:set numbersToSum='10,20,30,40' />
<cms:set result = '0' scope='global'/>
<cms:each numbersToSum sep=',' >
    <cms:set result = "<cms:add result item />" scope='global'/>
</cms:each>
<cms:show result />


Let's build our own function , based only on the tags CouchCMS provides with the help of snippets.
Snippets are great reusable pieces of code, but today I am going to show again how make them truly independent, very much like functions.

(1)

Create a snippet 'add-many.html'. I will put it to some sub-folder that I prefer to call 'functions', so the call would look like:
Code: Select all
<cms:embed 'functions/add-many.html' />


Snippet's initial content consists of the core of the operation - summing. Our future function will accept any string of comma-separated numbers and return result.
Code: Select all
<cms:each numbersToSum sep=',' >
    <cms:set result = "<cms:add result item />" />
</cms:each>


(2)

Let's see our real-world tasks, that we need to perform with
Code: Select all
<h3>Sum a set of numbers</h3>
<cms:set numbersToSum='10,20,30,40' />
<cms:set totalSum = '0' scope='global'/>

<cms:embed 'functions/add-many.html' />
<cms:show totalSum />

<!-- // ----------------------------------------------- -->

<h3>Average age of humans</h3>
<cms:set peopleAgeData='16,23,55,82,30' />
<cms:set averageAge = '0' scope='global'/>

<cms:embed 'functions/add-many.html'  />
<cms:set averageAge = "<cms:div sumOfAges peopleCount />" />
<cms:show averageAge />

Incoming data has different names: numbersToSum, peopleAgeData, Outgoing: totalSum, sumOfAges, peopleCount.

(3)

With everything prepared, we must make sure our function accepts various names as incoming data and returns variable that we expect. In other words, complete independence of this snippet-function is required. Following approach helps us:

Code: Select all
<!-- "cms:embed" tag supports its own scope of variables, if written as a tag-pair: -->
<cms:embed 'functions/add-many.html'  ></cms:embed>

// -------------- IMPORTANT FEATURES ----------

<!-- "cms:embed" tag also supports passing variables in its own scope towards the content of the snippet -->
<cms:embed 'functions/add-many.html'  var=my_var var2='55' ></cms:embed>


So, let's rewrite front-end code with the help of arguments-variables set as incoming and outgoing data. We will have in this example 3 parameters that will be used by function: data, result, count (optional). Our snippet should read numbers from a variable which name is stored in parameter 'data', put results in a variable which name is stored in parameter 'result' and same with 'count'.
Final code on the front-end (aka function calls)
Code: Select all

<cms:set numbersToSum='10,20,30,40' />
<cms:embed 'functions/add-many.html' data='numbersToSum' result='totalSum' ></cms:embed>
<cms:show totalSum />

<!-- // ---------------------------------------- -->

<cms:set peopleAgeData='16,23,55,82,30' />
<cms:embed 'functions/add-many.html'  data='peopleAgeData' result='sumOfAges' count='peopleCount'></cms:embed>
<cms:set averageAge = "<cms:div sumOfAges peopleCount />" />
<cms:show averageAge />



(4)


Let's instruct the code in the snippet to use passed arguments and operate upon them. (If you place cms:dump inside the snippet to debug, you will see how these arguments are present there). Final look of the snippet:

Code: Select all
<cms:hide>

    // Receive passed values:
   
</cms:hide>
<cms:set fdata = "<cms:get data />"  scope='local' /><cms:ignore>// 'fdata' will have content of variable whose name is stored in argument 'data'. </cms:ignore>
<cms:set fresult = '0' scope='local' />
<cms:hide>

    // Perform calculations:
   
</cms:hide>
<cms:each fdata sep=',' >
    <cms:set fresult = "<cms:add fresult item />" scope='local' />
    <cms:if k_last_item ><cms:put var=result value=fresult scope='global' /><cms:ignore>// function doesn't know where to put results, but target variable's name is stored in 'result'</cms:ignore>
        <cms:if count ><cms:put var=count value=k_total_items scope='global' /></cms:if>
    </cms:if>
</cms:each>



See, how easier it will be to maintain your code and reuse parts of it in truly awesome independent manner. Much less code required in templates to do stuff and snippet can be reused independently (yes, you can save the code for future and maybe even share your functions as well :) )
Hopefully, this brilliant explanation positively influences your day-to-day coding.

Regards
Anton
Have reworked the "sum" function, now all variables get protected from outside scope and added a looooot of commentaries in code.
sum.zip
(1.21 KiB) Downloaded 2931 times


A new one: Creates random pages. Seriously worked on protecting variables, error handling etc.

Code: Select all
    Creates several random pages and returns number of successfully created pages 
   
    Samples to call this snippet:
    <cms:embed 'functions/pages/pages-add-random.html' count='33' result='1' redirect='0' ></cms:embed>
    <cms:embed 'functions/pages/pages-add-random.html' redirect="<cms:admin_link />" ></cms:embed>

        Arguments:
   
    masterpage      /optional     masterpage = k_template_name    masterpage = 'another-template.php'
    count           /optional     count = '30'
    result          /optional     result = '1'      result = 'my_var'
    redirect        /optional     redirect = '1'    redirect = 'my_link'
Some more examples of new functions.

N-depth JSON format for folders

Code: Select all
<cms:ignore>
/*
 
    It loops through dynamic folders and creates a json list with required depth
   
    Sample to call this snippet:
    <cms:embed 'functions/folders/folders-export-json.html' show_content_type='0'></cms:embed>
   
   
        Arguments:
   
    masterpage          /optional     masterpage = k_template_name    masterpage = 'another-template.php'
    depth               /optional     depth = '3'
    show_content_type   /optional     show_content_type = '0'
    level_names         /optional     level_names = 'countries, cities, suburbs, malls'
   
*/
</cms:ignore>



Export folders to static set. Useful for large lists.

Code: Select all
<cms:ignore>
/*
 
    It loops through dynamic folders and creates a list of static folders cms:folder... as in docs
    Code borrowed from docs. http://docs.couchcms.com/concepts/using-folders.html
   
    Sample of resulting export:
        <cms:folder name="north-america" title="North American News">
            <cms:folder name="united-states" title="United States News">
                <cms:folder name="ohio" title="Ohio News" />
                <cms:folder name="nevada" title="Nevada News" />
            </cms:folder>
        </cms:folder>   
   
    Sample to call this snippet:
    <cms:embed 'functions/folders/folders-export-static.html' ></cms:embed>
   
   
        Arguments:
   
    masterpage      /optional       masterpage = k_template_name    masterpage = 'template.php'
    depth           /optional       depth = '3'

*/
</cms:ignore>



Export folders to <UL><LI>


Code: Select all
<cms:ignore>
/*
 
    It loops through dynamic folders and creates an unordered list of folders.
    Code borrowed from docs. http://docs.couchcms.com/concepts/using-folders.html
   
    Sample to call this snippet:
    <cms:embed 'functions/folders/folders-export-ulli.html' ></cms:embed>
   
   
        Arguments:
   
    masterpage      /optional       masterpage = k_template_name    masterpage = 'template.php'
    html_encode     /optional       html_encode = '1'
    depth           /optional       depth = '3'
   
*/
</cms:ignore>
6. Output array as <UL>-<LI>

Code: Select all
<cms:ignore>
/*
 
    It loops and calls itself to build a multi-dimensional ul-li out of array.
   
   
    Sample to call this snippet:
    <cms:embed 'functions/arrays/arrays-export-ulli.html' array = logArray depth = fdepth ></cms:embed>
   
        Arguments:
   
    array       /required       array = logArray
    depth       /optional       depth = '3'
   
*/
</cms:ignore>
7. Return safe url, for example:
input: "users/index.php" -> output: "users-index-php"

Complete listing of the snippet
Code: Select all
<cms:ignore>
/*
 
    Converts "users/index.php" to "users-index-php".
   
    Sample to call this snippet:
    <cms:embed 'functions/string/get-clean-url.html' url='index.php' ></cms:embed>
    <cms:embed 'functions/string/get-clean-url.html' url=k_template_name ></cms:embed>
   
   
        Arguments:
   
    url     /required     url='data.php'
   
*/
</cms:ignore>
Hi Anton,

I love this tutorial .... just a quick question to help me understand the logic of reusable functions.

Isn't it easier to wrap this kind of stuff into a custom tag ?
I load frameworks and write bugs on top of them, after that I rearrange the code so that it looks like a cool product.
Tomarnst wrote: I love this tutorial ....

Isn't it easier to wrap this kind of stuff into a custom tag ?


Hi,

Thank you for sharing your love :)

Here is what I assume when dealing with snippets instead of tags:
  • Snippets have code and html, while tags should not generate html (not a rule, but general practice)
  • One can create multiple snippets that do a similar job with different html output (example: list folders)
  • Easy to create for anyone, following the samples. Custom tags require php and snippets are based on couch-tags.
  • Snippet is easy to share, while custom tag needs to be put in kfunctions.php
  • I always know what functions I have just by looking at the list of file names, while tags must be remembered and their possible options are not visible (need to have extra docs page for each tag)
  • ... maybe more

I agree that essential functions will look better in a tag, in case they are adopted by the core distribution. But I'll still keep them as snippets with reasons above. We already have a lot of tags that people do not even know exist..
Thanks for the info.

We already have a lot of tags that people do not even know exist..

Yeah tell me :oops: and even when I know them sometimes they seem to have "hidden" options. By reading this I just learned...

"cms:embed" tag also supports passing variables in its own scope towards the content of the snippet

I didn't know that..!?
I load frameworks and write bugs on top of them, after that I rearrange the code so that it looks like a cool product.
Exactly! Hidden options are available only for those who can read php sources. This community is meant to be on the opposite side - we flourish by *not knowing* php (or *not needing* to use php).

Please also see the potential in snippets to offer ready-made front-end solutions - charts, sliders, galleries, calendars.. you name it. If only we had samples of tasks like 'output blog archives' in a snippet and a huge collection of frontend/backend snippets...
Well you have some great ideas and solutions .... thanks for sharing those!

Exactly! Hidden options are available only for those who can read php sources.

mmm.... that should not be the case also those hidden ones should be clear for someone who doesn't read the source files.
I load frameworks and write bugs on top of them, after that I rearrange the code so that it looks like a cool product.
26 posts Page 1 of 3