jQuery Semantic-UI

Par défaut, Ubiquity utilise la bibliothèque phpMv-UI pour la partie UI.
PhpMv-UI permet de créer des composants basés sur Semantic-UI ou Bootstrap et de générer des scripts jQuery en PHP.

Cette bibliothèque est utilisée pour l’interface d’administration webtools.

Intégration

Par défaut, une variable $jquery est injectée dans les contrôleurs au moment de l’exécution.

Cette opération se fait par injection de dépendance, dans app/config.php :

app/config.php
...
"di"=>array(
             "@exec"=>array(
                             "jquery"=>function ($controller){
                                     return \Ajax\php\ubiquity\JsUtils::diSemantic($controller);
                                     }
                             )
             )
...

Il n’y a donc rien à faire,
mais pour faciliter son utilisation et permettre la complétion de code dans un contrôleur, il est recommandé d’ajouter la documentation de code suivante :

app/controllers/FooController.php
 /**
 * Controller FooController
 * @property \Ajax\php\ubiquity\JsUtils $jquery
 **/
class FooController extends ControllerBase{

     public function index(){}
}

jQuery

Href en requêtes ajax

Créez un nouveau contrôleur et sa vue associée, puis définissez les routes suivantes :

app/controllers/FooController.php
 1namespace controllers;
 2
 3class FooController extends ControllerBase {
 4
 5     public function index() {
 6             $this->loadview("FooController/index.html");
 7     }
 8
 9     /**
10      *
11      *@get("a","name"=>"action.a")
12      */
13     public function aAction() {
14             echo "a";
15     }
16
17     /**
18      *
19      *@get("b","name"=>"action.b")
20      */
21     public function bAction() {
22             echo "b";
23     }
24}

La vue associée :

app/views/FooController/index.html
     <a href="{{path('action.a')}}">Action a</a>
     <a href="{{path('action.b')}}">Action b</a>

Initialiser le cache du routeur :

Ubiquity init:cache -t=controllers

Testez cette page dans votre navigateur à l’adresse http://127.0.0.1:8090/FooController.

Transformation des requêtes en requêtes Ajax

Le résultat de chaque requête ajax doit être affiché dans une zone de la page définie par son sélecteur jQuery (.result span).

app/controllers/FooController.php
namespace controllers;

/**
 * @property \Ajax\php\ubiquity\JsUtils $jquery
 */
class FooController extends ControllerBase {

     public function index() {
             $this->jquery->getHref('a','.result span');
             $this->jquery->renderView("FooController/index.html");
     }
     ...
}
app/views/FooController/index.html
     <a href="{{path('action.a')}}">Action a</a>
     <a href="{{path('action.b')}}">Action b</a>
<div class='result'>
     Selected action:
     <span>No One</span>
</div>
{{ script_foot | raw }}

Note

La variable script_foot contient le script jquery généré par la méthode renderView. Le filtre raw marque la valeur comme étant « sûre », ce qui signifie que dans un environnement où l’échappement automatique est activé, cette variable ne sera pas échappée.

Ajoutons un peu de css pour le rendre plus professionnel :

app/views/FooController/index.html
<div class="ui buttons">
     <a class="ui button" href="{{path('action.a')}}">Action a</a>
     <a class="ui button" href="{{path('action.b')}}">Action b</a>
</div>
<div class='ui segment result'>
     Selected action:
     <span class="ui label">No One</span>
</div>
{{ script_foot | raw }}

Si nous voulons ajouter un nouveau lien dont le résultat doit être affiché dans une autre zone, il est possible de le spécifier via l’attribut data-target.

La nouvelle action

app/controllers/FooController.php
namespace controllers;

class FooController extends ControllerBase {
     ...
     /**
      *@get("c","name"=>"action.c")
      */
     public function cAction() {
             echo \rand(0, 1000);
     }
}

La vue associée :

app/views/FooController/index.html
<div class="ui buttons">
     <a class="ui button" href="{{path('action.a')}}">Action a</a>
     <a class="ui button" href="{{path('action.b')}}">Action b</a>
     <a class="ui button" href="{{path('action.c')}}" data-target=".result p">Action c</a>
</div>
<div class='ui segment result'>
     Selected action:
     <span class="ui label">No One</span>
     <p></p>
</div>
{{ script_foot | raw }}
../_images/fooController.png

Définition des attributs de la requête ajax :

Dans l’exemple suivant, les paramètres passés à la variable attributs de la méthode getHref :

  • supprimer l’historique de la navigation,

  • rendre le loader ajax interne au bouton cliqué.

app/controllers/FooController.php
 1namespace controllers;
 2
 3/**
 4 * @property \Ajax\php\ubiquity\JsUtils $jquery
 5 */
 6class FooController extends ControllerBase {
 7
 8     public function index() {
 9             $this->jquery->getHref('a','.result span', [
10                     'hasLoader' => 'internal',
11                     'historize' => false
12             ]);
13             $this->jquery->renderView("FooController/index.html");
14     }
15     ...
16}

Note

Il est possible d’utiliser la méthode postHref pour utiliser le POST http.

Requêtes ajax classiques

Pour cet exemple, créez la base de données suivante :

CREATE DATABASE `uguide` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `uguide`;

CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `firstname` varchar(30) NOT NULL,
  `lastname` varchar(30) NOT NULL,
  `password` varchar(30) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `user` (`id`, `firstname`, `lastname`) VALUES
(1, 'You', 'Evan'),
(2, 'Potencier', 'Fabien'),
(3, 'Otwell', 'Taylor');

ALTER TABLE `user` ADD PRIMARY KEY (`id`);
ALTER TABLE `user`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;

Connectez l’application à la base de données, et générez la classe User :

Avec les devtools :

Ubiquity config:set --database.dbName=uguide
Ubiquity all-models

Créer un nouveau contrôleur UsersJqueryController.

Ubiquity controller UsersJqueryController -v

Créez les actions suivantes dans UsersJqueryController :

../_images/UsersJqueryControllerStructure.png

Action index

L’action index doit afficher un bouton pour obtenir la liste des utilisateurs, chargée via une requête ajax :

app/controllers/UsersJqueryController.php
 1namespace controllers;
 2
 3/**
 4 * Controller UsersJqueryController
 5 *
 6 * @property \Ajax\php\ubiquity\JsUtils $jquery
 7 * @route("users")
 8 */
 9class UsersJqueryController extends ControllerBase {
10
11     /**
12      *
13      * {@inheritdoc}
14      * @see \Ubiquity\controllers\Controller::index()
15      * @get
16      */
17     public function index() {
18             $this->jquery->getOnClick('#users-bt', Router::path('display.users'), '#users', [
19                     'hasLoader' => 'internal'
20             ]);
21             $this->jquery->renderDefaultView();
22     }
23}

La vue par défaut associée à l’action index :

app/views/UsersJqueryController/index.html
<div class="ui container">
     <div id="users-bt" class="ui button">
             <i class="ui users icon"></i>
             Display <b>users</b>
     </div>
     <p></p>
     <div id="users">
     </div>
</div>
{{ script_foot | raw }}

Action displayUsers

Tous les utilisateurs sont affichés, et un clic sur un utilisateur doit afficher les détails de l’utilisateur via une requête ajax postée :

app/controllers/UsersJqueryController.php
 1namespace controllers;
 2
 3/**
 4 * Controller UsersJqueryController
 5 *
 6 * @property \Ajax\php\ubiquity\JsUtils $jquery
 7 * @route("users")
 8 */
 9class UsersJqueryController extends ControllerBase {
10...
11     /**
12      *
13      * @get("all","name"=>"display.users","cache"=>true)
14      */
15     public function displayUsers() {
16             $users = DAO::getAll(User::class);
17             $this->jquery->click('#close-bt', '$("#users").html("");');
18             $this->jquery->postOnClick('li[data-ajax]', Router::path('display.one.user', [
19                     ""
20             ]), '{}', '#user-detail', [
21                     'attr' => 'data-ajax',
22                     'hasLoader' => false
23             ]);
24             $this->jquery->renderDefaultView([
25                     'users' => $users
26             ]);
27     }

La vue associée à l’action displayUsers :

app/views/UsersJqueryController/displayUsers.html
<div class="ui top attached header">
     <i class="users circular icon"></i>
     <div class="content">Users</div>
</div>
<div class="ui attached segment">
     <ul id='users-content'>
     {% for user in users %}
             <li data-ajax="{{user.id}}">{{user.firstname }} {{user.lastname}}</li>
     {% endfor %}
     </ul>
     <div id='user-detail'></div>
</div>
<div class="ui bottom attached inverted segment">
<div id="close-bt" class="ui inverted button">Close</div>
</div>
{{ script_foot | raw }}

Action displayOneUser

app/controllers/UsersJqueryController.php
 1namespace controllers;
 2
 3/**
 4 * Controller UsersJqueryController
 5 *
 6 * @property \Ajax\php\ubiquity\JsUtils $jquery
 7 * @route("users")
 8 */
 9class UsersJqueryController extends ControllerBase {
10...
11     /**
12      *
13      * @post("{userId}","name"=>"display.one.user","cache"=>true,"duration"=>3600)
14      */
15     public function displayOneUser($userId) {
16             $user = DAO::getById(User::class, $userId);
17             $this->jquery->hide('#users-content', '', '', true);
18             $this->jquery->click('#close-user-bt', '$("#user-detail").html("");$("#users-content").show();');
19             $this->jquery->renderDefaultView([
20                     'user' => $user
21             ]);
22     }

La vue associée à l’action displayOneUser :

app/views/UsersJqueryController/displayUsers.html
<div class="ui label">
     <i class="ui user icon"></i>
     Id
     <div class="detail">{{user.id}}</div>
</div>
<div class="ui label">
     Firstname
     <div class="detail">{{user.firstname}}</div>
</div>
<div class="ui label">
     Lastname
     <div class="detail">{{user.lastname}}</div>
</div>
<p></p>
<div id="close-user-bt" class="ui black button">
     <i class="ui users icon"></i>
     Return to users
</div>
{{ script_foot | raw }}

Composants Semantic

Nous allons ensuite réaliser un contrôleur implémentant les mêmes fonctionnalités que précédemment, mais en utilisant des composants PhpMv-UI (partie sémantique).

Exemple HtmlButton

Créer un nouveau contrôleur UsersJqueryController.

Ubiquity controller UsersCompoController -v
app/controllers/UsersJqueryController.php
 1namespace controllers;
 2
 3use Ubiquity\controllers\Router;
 4
 5/**
 6 * Controller UsersCompoController
 7 *
 8 * @property \Ajax\php\ubiquity\JsUtils $jquery
 9 * @route("users-compo")
10 */
11class UsersCompoController extends ControllerBase {
12
13     private function semantic() {
14             return $this->jquery->semantic();
15     }
16
17     /**
18      *
19      * @get
20      */
21     public function index() {
22             $bt = $this->semantic()->htmlButton('users-bt', 'Display users');
23             $bt->addIcon('users');
24             $bt->getOnClick(Router::path('display.compo.users'), '#users', [
25                     'hasLoader' => 'internal'
26             ]);
27             $this->jquery->renderDefaultView();
28     }

Note

L’appel à renderView ou renderDefaultView sur l’objet JQuery effectue la compilation du composant et génère le HTML et le JS correspondants.

La vue associée intègre le composant bouton avec le tableau q disponible dans la vue :

app/views/UsersCompoController/index.html
<div class="ui container">
     {{ q['users-bt'] | raw }}
     <p></p>
     <div id="users">
     </div>
</div>
{{ script_foot | raw }}

//todo DataTable sample +++++++++++++++++