2017 © Pedro Peláez
 

library freepbx-base

Helper to create module with the Symfony components like form validation, dependency injection...

image

telnowedge/freepbx-base

Helper to create module with the Symfony components like form validation, dependency injection...

  • Friday, July 20, 2018
  • by BorisMorel
  • Repository
  • 1 Watchers
  • 1 Stars
  • 34 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 6 Versions
  • 62 % Grown

The README.md

TelNowEdge/FreepbxBase bundle

Version

  • 2018/05/23 1.0: Stable release, (*1)

    • Container caching
    • Template caching
    • Form helper to append Destination block on form
    • Helper to send UserEvent
    • New Verb forn asterisk dialplan
  • 2017/11/28 0.1: First available working version, (*2)

Install

Dependencies requirements

Currently FreePBX® come with a symfony/property-access:3.4.19 on this version a major bug is known #29340. So, to install this module you must update your packages., (*3)

cd /var/www/admin/libraries/Composer
composer update

With composer require

cd /var/www/admin/libraries/Composer/composer.json
composer require telnowedge/freepbx-base

With git

git clone inside composer vendor dir, (*4)

cd /var/www/admin/libraries/Composer/vendor/telnowedge/
git clone freepbx-base

Update composer autoload by adding on composer.json, (*5)

"autoload": {
  "psr-4": {
  "TelNowEdge\\FreePBX\\Base\\": "vendor/telnowedge/freepbx-base"
  }
}

And finally run, (*6)

composer.phar dump-autoload

To known

  1. Cache system

All cached files was written on rootFreePBX/assets/cache/. Please take care with the rights., (*7)

Overview

This FreepbxBase bundle provide an easy way to write FreePBX® modules like an MVC project. He works alone without any modification of FreePBX® core files except composer.json., (*8)

FreepbxBase bundle use Symfony® components to improve security, accessibility and support., (*9)

It register its own namespace to give access on the different components through several helpers., (*10)

FreepbxBase bundle introduce in FreePBX® the Dependency Injection concept with the Symfony® component. This component is very useful to prevent any singleton and share easily your object through your own code., (*11)

FreepbxBase bundle provide too the Symfony® Form component to validate your form on the server side before to save it on your sql storage., (*12)

Before start using it, you need to understand namespace and the Symfony base development concepts., (*13)

Acme example module

Coding standard

To check the coding standard please include on your module GrumPHP., (*14)

  1. Require packages, (*15)

       $ composer require --dev "phpro/grumphp" "nikic/php-parser" "friendsofphp/php-cs-fixer" "jakub-onderka/php-parallel-lint" "phpmd/phpmd" "phpspec/phpspec"
    
  2. Create config file for php-cs-fixer ./php_cs, (*16)

       <?php
    
       return PhpCsFixer\Config::create()
           ->setRiskyAllowed(true)
           ->setRules([
               '@Symfony' => true,
               '@Symfony:risky' => true,
               'array_syntax' => true,
               'combine_consecutive_unsets' => true,
               'no_useless_else' => true,
               'no_useless_return' => true,
               'ordered_class_elements' => true,
               'ordered_imports' => true,
               'php_unit_strict' => true,
               'strict_comparison' => true,
               'strict_param' => true,
           ])
           ->setFinder(PhpCsFixer\Finder::create()
               ->exclude('vendor')
               ->in(__DIR__)
           )
       ;
    
  3. Create GrumPHP config file ./grumphp.yml, (*17)

       parameters:
         git_dir: .
         bin_dir: ./vendor/bin
         tasks:
           jsonlint: ~
           phpcsfixer2:
             config: "./.php_cs"
             allow_risky: true
             # rules:
             #   - "@@Symfony"
             #   - "@@Symfony:risky"
             #   - array_syntax
             #   - combine_consecutive_unsets
             #   - no_extra_consecutive_blank_lines
             #   - no_useless_else
             #   - no_useless_return
             #   - ordered_class_elements
             #   - ordered_imports
             #   - php_unit_strict
             #   - psr4
             #   - strict_comparison
             #   - strict_param
             using_cache: false
             config_contains_finder: false
           phplint: ~
           phpmd:
             ruleset: ['unusedcode', 'codesize']
           phpparser: ~
           phpspec: ~
           shell: ~
           xmllint: ~
           yamllint:
             parse_custom_tags: true
           xdebugparse: ~
    

Included components

  1. doctrine/annotations
  2. doctrine/cache
  3. guzzlehttp/guzzle
  4. monolog/monolog
  5. symfony/cache
  6. symfony/config
  7. symfony/dependency-injection
  8. symfony/event-dispatcher
  9. symfony/form
  10. symfony/http-foundation
  11. symfony/ldap
  12. symfony/property-access
  13. symfony/security-csrf
  14. symfony/serializer
  15. symfony/twig-bridge
  16. symfony/validator
  17. symfony/yaml

How to use

Start a new FreePBX® module

Start a new FreePBX® module like FreePBX® practices and change only the extends class to TelNowEdge\FreePBX\Base\Module\Module., (*18)

<?php

namespace FreePBX\modules;

use TelNowEdge\FreePBX\Base\Module\Module;

class Foo extends Module implements \BMO
{

}

This extends start and bridge all Symfony® components and register a new namespace. Now you can use a PSR4 namespace inside your module., (*19)

The new register namespace is \TelNowEdge\Module. He is registered with ./modules base directory. So now you can use \TelNowEdge\Module\foo namespace., (*20)

Note:, (*21)

Take care with the case of your module name. Your class can be Foo.class.php but the folder is ./modules/foo. So the namespace is \TelNowEdge\Module\foo., (*22)

Use FreePBX® class like an entry point

Your Foo.class.php is the first file for FreePBX®. Now use it to call your logic Controller., (*23)

<?php

namespace FreePBX\modules;

use TelNowEdge\FreePBX\Base\Module\Module;
use TelNowEdge\Module\foo\Controller\FooBarController;

class Foo extends Module implements \BMO
{
    public function install()
    {
        $this
            ->get('TelNowEdge\Module\foo\Resources\Migrations\TableMigration')
            ->migrate()
            ;
    }

    public static function myGuiHooks()
    {
        return array('core');
    }

    public function doGuiHook(&$cc)
    {
        $this
            ->processDeviceGui($cc)
            ;
    }

    private function processDeviceGui(&$cc)
    {
        $request = $this->get('request');

        if ('devices' === $request->query->get('display')) {
            if (true === $request->isMethod('POST')) {
                if ('edit' === $request->request->get('action')) {
                    $this->get(FooBarController::class)
                         ->updateAction($request, $cc)
                        ;
                }

                if ('add' === $request->request->get('action')) {
                    $this->get(FooBarController::class)
                         ->createAction($request, $cc)
                        ;
                }
            } else {
                $this->get(FooBarController::class)
                     ->showAction($request, $cc)
                    ;
            }
        }
    }
}

Your controller ./modules/foo/Controller/FooBarController.php, (*24)

<?php

namespace TelNowEdge\Module\foo\Controller;

use TelNowEdge\FreePBX\Base\Controller\AbstractController;

class FooBarController extends AbstractController
{
    [...]
}

Reference

Module

Entry point to start FreepbxBase bundle., (*25)

FreePBX® module must extends TelNowEdge\FreePBX\Base\Module\Module, (*26)

Controller

Your Controller must extends TelNowEdge\FreePBX\Base\Controller\AbstractController, (*27)

protected $container;

FormFactory function createForm(FormInterface $type, $data = null, array $options = array());

string function render(string $templatePath, array $data = array());

mixed function get(string $service);

  1. createForm(), (*28)

  2. render(), (*29)

    Render return the compile html from the template. Append on FreePBX® with the FreePBX® practices., (*30)

    $html = $this->render('foo.html.twig', array(
        'form' => $form->createView(),
    ));
    
    $cc->addguielem(_('Foo'), new \gui_html('Foo', $html), 1, null, _('TelNowEdge'));
    
  3. get(), (*31)

Model

Note:, (*32)

This bundle don't use Doctrine ORM. But the way is the same., (*33)

Model is the Database representation. This class must not extends anything., (*34)

On each properties, you can add a validator., (*35)

<?php

namespace TelNowEdge\Module\foo\Model;

use Symfony\Component\Validator\Constraints as Assert;

class Foo
{
    protected $id;

    /**
     * @Assert\NotBlank()
     */
    protected $name;

    public function getId()
    {
        return $this->id;
    }

    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }
}

Repository

Repository get informations from sql storage and map with Model. ORM like very lite., (*36)

Your Repository must extends TelNowEdge\FreePBX\Base\Repository\AbtractRepository, (*37)

array sqlToArray(array $sqlRes);

\Doctrine\DBAL\Statement fetch(\Doctrine\DBAL\Statement $stmt);

\Doctrine\DBAL\Statement fetchAll(\Doctrine\DBAL\Statement $stmt);

Model objectFromArray(string $modelClass, array $sqlToArrayRes);

  1. sqlToArray() Transform sql results set to an array for objectFromArray(), (*38)

    sqlToArray() need a formatted input., (*39)

    SELECT t.id t__id, t.name t__name, t.long_name t__long_name, t2.id t2__id
    FROM table t INNER JOIN table2 t2 ON (t2.id = t1.id)
    

    sqlToArray() return an associative array like:, (*40)

    array(
        't' => array('id' => '1', 'name' => 'foo', 'longName' => 'foobar'),
        't2' => array('id' => 1)
    )
    

    Note:, (*41)

    The __ was remove to create table key and _ was camel case., (*42)

  2. objectFromArray() Map the sqlToArray() to the model. On each properties, he try to call the setter., (*43)

    private function mapModel(array $res)
    {
        $foo = $this->objectFromArray(Foo::class, $res['t']);
        $fooBar = $this->objectFromArray(FooBar::class, $res['t2']);
    
        return $foo->setFooBar($fooBar);
    }
    

DbHandler

DbHandler save data from the Model to the sql., (*44)

Your Repository must extends TelNowEdge\FreePBX\Base\Handler\AbtractDbHandler, (*45)

<?php

namespace TelNowEdge\Module\foo\Handler\DbHandler;

use TelNowEdge\FreePBX\Base\Handler\AbstractDbHandler;
use TelNowEdge\Module\foo\Model\Foo;

class PhoneProvisionDbHandler extends AbstractDbHandler
{
    public function create(Foo $foo)
    {
        $sql = "INSERT INTO Foo (`id`, `name`, `value`) VALUES (:id, :name, :value)";
        $stmt = $this->connection->prepare($sql);
        $stmt->bindParam('id', $foo->getId());
        $stmt->bindParam('name', $foo->getName());
        $stmt->bindParam('value', $foo->getValue());

        $stmt->execute();
    }

Form

Form provide an easy way to build and validate your form., (*46)

This component is used exactly like Symfony does., (*47)

Validator

Validator works with Form to validate it on server side., (*48)

This component is used exactly like Symfony does., (*49)

Dependency Injection

Dependency Injection create a container of services to deal with on your code., (*50)

This component is used exactly like Symfony does., (*51)

Twig

Twig is a templating component. Cery useful to render the Symfony® forms, (*52)

This component is used exactly like Symfony does., (*53)

Todo

  1. Increase security in service.yml with public / private service

The Versions