What's Included

File Structure

  • CacheHere are all cache files stored.
  • ExtensionAll Fraym extensions PHP files are here.
  • FraymHere are all Fraym core PHP files.
  • PublicThis is the document root folder where the index.php is stored an all public files.
  • Template This folder contains all template files.
    • DefaultHere are all default templates that comes with the Fraym core or the extension you have installed. This folder ist also set as the default site template dir. It is not recommended to change any template in here, because on an update this templates will be overwritten.
      • ExtensionHere are all default extension templates.
      • FraymHere are all default Fraym core templates.
    • DynamicThis is the default folder for dynamic templates, you can change the default folder for dynamic templates in the configuration of the data manager.
  • TestHere you find all PHP unit tests.
  • HookHere are all hooked php files.
  • VendorAll 3rd party classes are here. Fraym used some 3rd party libraries.
  • Bootstrap.phpThe index.php will include this file.
  • Config.phpThis is the main configuration file with the database connection and the some minimal options of the environment.
Database, dependency injection and more

3rd party libraries

Fraym used some vendor libraries

Database

Fraym is using the Doctrine ORM for the database connection, more information about the Doctrine ORM you will find here. Fraym also takes advantages from some Doctrine extensions.

Dependency injection

Fraym is using PHP-DI for dependency injection. More information about dependency injection you also find on the PHP-DI website.

Image manipulation

For image processing Fraym is using the PHP Imagine library.

Mailing

For mailing we use the swiftmailer

How routing in Fraym works

Routing

All about Url's, Ajax and more

Annotations

Fraym specific php annotations

LifecycleCallback

Namespace / Class: @Fraym\Annotation\LifecycleCallback

Description: This annotation is only for doctrine entites. You can add this annotation on top of a doctrine entity class.

Example:
@LifecycleCallback(postPersist={"\Fraym\Block\Block"="clearCache"}, onFlush={"\Fraym\Block\Block"="clearCache"})

This will call the method clearCache in the class Fraym\Block\Block on postPersist and onFlush. More about postPersist,onFlush you will find in the doctrine documentation.

Allowed paremeters: preRemove,postRemove,prePersist,postPersist,preUpdate,postUpdate,postLoad,onFlush

 

FormField

Namespace / Class: @Fraym\Annotation\FormField

Description: This annotation is only for doctrine entites. You can use this annotation to create editable input fields for the Data Manager.

FormField Parameter

Paramater Description
label Type: String - The title of the field in the Data Manager
type Type: String - Possible values: text,password,textarea,rte,select,radio,checkbox,multiselect,date,datetime,filepath,description - The type of the input field.
sort Type: Array - If you add an FormField annotation to a OneToMany relation and you have a multiselect you can define the sorting with this paramater. Just enter the name of the field from the relation.
validation Type: Array - Add field validation. The validation use Fraym\Validation\Validation class.
readOnly Type: Bool - If the value is true the field is not editable.
createNew Type: Bool - If true you can create a new OneToMany entry for the current entry. A new overlay appears where you can set multiple field from the new item.
createNewInline Type: String - Set the entity property name as value. For example: You want so store News Tags on an entity.
rteConfig Type: String - Add CKEditor configuration.
rteConfigFile Type: String - Add the file path where the CKEditor config are stored. Example: rteConfigFile="Template/Default/Extension/News/RteConfig.tpl"
fileFilter Type: String - Add file filter Example: "*.jpg,*.png". Only works with type filepath.
absolutePath Type: Bool - Returns the absolute path of the selected file. Only works with type filepath.
singleFileSelect Type: Bool - If true you can select only one file. Only works with type filepath.
Templating

Template Engine

Templating is one of the easiest thing with Fraym.

The templating language is very easy it is just PHP. You can run all PHP code just add curly braces. It is something like the smarty template engine.

{if 1 === 1}
    {date('Y')} <!-- Output the current date -->
{/if}

{foreach $data as $key => $value}
...
{/foreach}

{while $a !== NULL}
...
{/while}

{for $i = 10; $i<=10; $i++}
...
{/for}

{switch $var}
...
{case 1:}
...
{/switch}

{function myFunc($param)}
...
{/function}

All template vars will be converted to objects. So you can access all arrays like this:

{$foo.bar}

It’s the same like this:

{$foo->bar}

Custom Template Functions

Function Description
{menuItem($menuItemId)} Returns a menuItem object with the specified id
{i('NAMESPACE\ClassName')} Returns a instance of the specified class
{css($file, $group = 'default', $key = null)} Adds a css file to the block css output: <block type="css" sequence="outputFilter" group="default" consolidate="false"></block>
{js($file, $group = 'default', $key = null)} Adds a javascript file to the block js output: <block type="js" sequence="outputFilter" group="default" consolidate="false"></block>
{include($file, $vars = array(), $cacheKey = null, $showError = true)} Includes a template file. If $vars are a empty array all variables from the parent template will be assigned to the included template. Add a cacheKey if you want to cache the included template. $showError will show an error message if the template file will not found
{shorten($text, $length = 200, $append = '...')} Shorten a text with the specified length
{age($dateTime)} Return the age in years
{isLast($array, $arrayProperty)} Checks if the array property is the last item of a array
{formatCurrency($number, $symbol = '')} Use the PHP NumberFormatter and the current locale to format the currency
{formatDate($dateTime)} Format the date to the current locale defined format. To define the format check the configuration in the Data Manager
{formatDateTime($dateTime)} Format the date and time to the current locale defined format. To define the format check the configuration in the Data Manager
{_($defaultText, $key, $defaultLocale = 'en_US', $placeholder = array())} This function is used for translating text in templates. $defaultText is your default locale template text. If you use the default locale en_US as your primary language you don't need to change the $defaultLocale. Use $key for a unique translation assignment. To change the translation of a text use the Data Manager. With $placeholder you can replace parts of your string. Example: {_('Default :placeholder text', 'UNIQUE_KEY', 'en_US', array(':placeholder' => 'translated'))}
{et($entity, $propertyName, $locale, $defaultValue = '')} This function get the translated value of a property from your doctrine entity with the given locale string

Image blocks

When ever you use a image on your website it is recommended to use the block image element, because all images are resized and optimized. The image block has the same attributes llike a html img tag. Additionally the block image has this definition:
 

<block type="image" src="Public/images/file.jpg" width="100" height="100" maxWidth="200" maxHeight="200" method="resize" mode="outbound" crop="0,0,50,50" quality="80" format="jpg" override="false" srcOnly="false"></block>

Note: The image source is always loaded from the application root not from the document root.

Attribute Default value Allowed values Description
src [string] File path from application root: Public/images/myimage.jpg
width [integer] Size in pixel how the image width will be resized.
height [integer] Size in pixel how the image height will be resized.
maxWidth [integer] The maximal image width a image can have for resizing. The image will keep aspect ratio.
maxHeight [integer] The maximal image height a image can have for resizing. The image will keep aspect ratio.
method resize resize,crop,thumbnail resize: resizing the image to the specified size. crop: Crop the image. Use the crop attribute to define x,y,height,width for cropping. thumbnail: Create a image in a box, use the mode attribute for the thumbnail style.
crop x,y,width,height [string] Set the parameters for cropping.
mode outbound outbound,inbound Defines the thumbnail style. If the image will be inner or outer the box width and height.
quality 80 1-100 [integer] Indicates how the jpg quality should be in percent
format jpg jpg,png,gif,tiff,svg The output format. If src is for example png you can convert/output the image as jpg.
override false false,true If true, the image will not be cached and always overwritten.
srcOnly false false,true If true, no html image tag will be outputted, only the src/filepath to the image.

Creating Container Elements

First checkout the default theme "Template/Default/Extension/Theme/DefaultTheme/Index.tpl" there you will see the block elements. The block elements of type "content" are the containers where you can drag & drop the block extensions. So you only need to create those type of block elements to add editable elements to your website.
 

<block style="" type="content">
     <view actionBarStyle="" add="afterContent" class="mycssclass" description="" editable="true" editStyle="min-height:300px;" element="div" hideEmpty="true" id="ELEMENT-ID" renderElement="true" unique="false">
     </view>
     <view actionBarStyle="" add="afterContent" class="mycssclass" description="" editable="true" editStyle="min-height:300px;" element="div" hideEmpty="true" id="ELEMENT-ID-2" renderElement="true" unique="false">
         <view element="span" id="ELEMENT-ID-2-1">
         </view>
     </view>
</block>

All view elements will be replaced with the given “element” attribute. If the attribute “renderElement” is false only the content of the element will be rendered.

Attribute Default value Allowed values Description
id Required. Must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens (“-“), underscores (“_”), colons (“:”), and periods (“.”) The id of the html element
editable true true / false If this element is editable
unique true true / false If you add multiple custom view’s with the same id to a page you can add dynamic unique ids
hideEmpty true true / false If the content of the view is empty the wrapper will not be rendered
add afterContent afterContent / beforeContent If you have a view in view you can decide where the content will be rendered
class CSS classes Add css classes for the html element
editStyle Inline css Add inline style for the admin editing view
renderElement true true / false If false the wrapper will not be rendered
element div All html elements The wrapper element type
description Custom string Adds a description tooltip text for the container element
actionBarStyle CSS inline style Add a custom style for the editing action bar, if you are in editing mode
More blocks

Creating Extensions

Create your first extension in 10 minutes.

We want to create a simple extension that outputs simple entries from the database.

Create a folder named "Test in the "Extension" folder. Create two files in the "Test" folder: "Test.php" and "TestController.php"

In both files you have to create the php namespace in this format: "Folder\SubFolder\SubSubFolder"
So for the "Test" extension we define the namespace "namespace Extension\Test;"

Here is the complete code of Test.php:

 

namespace Extension\Test;

use Fraym\Annotation\Registry;

/**
 * @Registry(
 * name="My first extension",
 * repositoryKey="fraym-test-extension",
 * composerPackage=false,
 * entity={
 *      "\Fraym\Block\Entity\Extension"={
 *          {
 *           "name"="My items",
 *           "description"="Reading string from the database.",
 *           "class"="\Extension\Test\Test",
 *           "execMethod"="execBlock"
 *           },
 *      },
 *      "\Fraym\EntityManager\Entity\Entity"={
 *          {
 *           "className"="\Extension\Test\Entity\Item",
 *           "name"="Test item entry",
 *           "group"={
 *                      "\Fraym\EntityManager\Entity\Group"={
 *                          "name"="My test items"
 *                      }
 *                   },
 *           }
 *       }
 * }
 * )
 * @Injectable(lazy=true)
 */
class Test
{
    /**
     * @Inject
     * @var \Extension\Test\TestController
     */
    protected $testController;

    /**
     * @Inject
     * @var \Fraym\Database\Database
     */
    protected $db;

    /**
     * @param $xml
     */
    public function execBlock($xml)
    {
        $items = $this->db->getRepository('\Extension\Test\Entity\Item')->findAll();
        $this->testController->render($items);
    }
}

Look at the code. The important thing here is the @Registry annotation, this defines the install options for your extension. For more about Fraym annotations look at the annotation section. The execBlock method is definded in the @Registry annotation. This will be called when the block will be rendered. The $xml parameter of the method is unused here because our block element has no additional configurations.
In the method of execBlock we read our items from the database and assign them to our controller for the rendering. Important is here that we set composerPackage=false, because otherwise we are not able to install the extension without a existing composer package.

Here is the code for the TestController.php:

namespace Extension\Test;

/**
 * @package Extension\Test
 * @Injectable(lazy=true)
 */
class TestController extends \Fraym\Core
{
    /**
     * @param $items
     */
    public function render($items)
    {
        $this->view->assign('items', $items);
        $this->view->setTemplate('MyItems');
    }
}

The render method assign the variable to our template, after that we set our template file name to MyItems.
Now we need to create the template file MyItems here: Template/Default/Extension/Test/MyItems.tpl.
This will be the default template for this extension. Now we want to output our items in MyItems.tpl:


{foreach $items as $item}
    <div>
        <h3>{$item.title}</h3>
        {{$item.description}}
    </div>
{/foreach}
    

With the curly braces we disable the html entity encoding because the item description input field is a RTE Input. 

But wait where we store or create our dataset items. For that we have to create a doctrine entity object. We have to create a file here Extension/Test/Entity/Item.php:


namespace Extension\Test\Entity;
use \Doctrine\ORM\Mapping as ORM;
use \Fraym\Annotation\FormField;
use \Gedmo\Mapping\Annotation as Gedmo;

/**
 * Class Item
 * @package Extension\Test\Entity
 * @ORM\Table(name="test_items")
 * @ORM\Entity
 */
class Item extends \Fraym\Entity\BaseEntity
{
    /**
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * @ORM\Column(name="title", type="string", nullable=false)
     * @FormField(label="Title", validation={"notEmpty"})
     * @Gedmo\Translatable
     */
    protected $title;

    /**
     * @ORM\Column(name="description", type="text", nullable=true)
     * @FormField(label="Description", type="rte")
     * @Gedmo\Translatable
     */
    protected $description;

    /**
     * @return string
     */
    public function __toString()
    {
        return $this->title;
    }
}

The @FormField annotation is a custom Fraym annotation to create editable entity objects. So you can add & edit datasets with the Fraym Data Manager which you will find in the sidebar.

Now we install our extension with the Extension Manager in the left sidebar. If you have done all right you will find My first extension there. Click on the install icon to install the extension. We want to create some items now, open the Data Manager, in the dropdown choose "Test item entry" under your extension name.

You see now the 2 Fields (title and description) you have added in the Entity/Item.php. Fill out the field with test data and click save. We now have to create a block for the output on our side. Enable the edit mode to editing the website. Add a extension by clicking on the plus icon. Choose your extension "Data storeage reader" in the extension dropdown and click save & close in the upper right. Now you will the your item you have added.

Congrats, you have build your first extension!

Note: If you want to make your extension available to the world, create a github repository with your extension, add a composer.json (with type fraym-extension) the to your project and add the extension to packagist.org then you will can find and install the extension over the Fraym Extension Manager.