Bonjour à tous,

Je suis sur un projet et je butte dès le début : j'ai une table Users, une table Towns et une troisième TownsUsers permerttant de donner la gestion d'une/plusieurs ville(s) à un/plusieurs utilisateur(s).

J'ai donc Users belongsToMany Towns et Towns belongsToMany Users.

Mon but est d'ajouter des villes depuis un utilsateur.

Voici le code :

PS : pour l'ajout d'une Town pour un User je passe par du javascript qui me rajoute les données des villes via du ajax

// UsersController
    public function editTowns($id = null)
    {
        $user = $this->Users->get($id, [
            'contain' => ['Towns']
        ]);
        if ($this->request->is(['post', 'put']))
        {
            $this->Users->patchEntity($user, $this->request->data);
            if ($this->Users->save($user))
            {
                $this->Flash->success("Les villes de l'utilisateur ont bien été enregistrées.");
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error("Impossible de modifier les villes d'un utilisateur");
        }
        $this->set(compact('user'));
    }

la vue :

<?= $this->Form->create($user, ['controller' => 'users', 'action' => 'editTowns', 'id' => 'form-town_search', 'name' => 'form-town_search']); ?>

        <div id="towns-planner">
            <?php foreach($user->towns as $town): ?>
                <div class="alert alert-info alert-dismissable" data-id="<?= $town->id; ?>" data-type="town-planner">
                    <?= $town->name; ?> <small><?= $town->code; ?></small>
                    <input type="text" name="towns[]" value="<?= $town->id; ?>" style="display:none">
                    <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span></button>
                </div>
            <?php endforeach; ?>
        </div>

        <div class="typeahead-container">
            <div class="typeahead-field">
                <span class="typeahead-query">
                    <?= $this->Form->input('town_search', ['label' => '', 'id' => 'town_search-query', 'name' => 'town_search[query]',
                                                    'type' => 'search', 'placeholder' => "Rechercher", 'autocomplete' => 'off']); ?>
                </span>
                <span class="typeahead-button">
                    <button type="submit">
                        <span class="typeahead-search-icon"></span>
                    </button>
                </span>

            </div>
        </div>

        <?= $this->Form->submit("Enregistrer les villes sélectionnées", ['class' => 'btn btn-success']); ?>

        <?= $this->Form->end(); ?>

Et le javascript:


        $('#town_search-query').typeahead({
            oder: 'desc',
            minLength: 1,
            dynamic: true,
            maxItem: 8,
            delay: 500,
            template: '<span data-id="{{id}}">' +
                        '<span class="town">{{name}} ({{code}}) - <small>{{department.name}} ({{department.code}}) </small></span>' +
                    '</span>',
            source: {
                towns: {
                    display: 'name',
                    url: [{
                        type: "POST",
                        url: "/soferias/admin/towns/ajaxSearch",
                        data: {q: "{{query}}"}
                    }, "towns"]
                }
            },
            callback: {
                onClickAfter: function (node, a, item, event)
                {
                    $tmp = $('#towns-planner').find('div[data-id="'+item.id+'"]');
                    if ($tmp.length == 0)
                    {
                        var $town = '<div class="alert alert-info alert-dismissable" data-id="'+item.id+'" data-type="town-planner">' +
                            item.name + ' <small>' + item.code + '</small>' +
                            '<input type="text" name="towns[]" value="' + item.id + '" style="display:none">' +
                            '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span></button>' +
                            '</div>';
                        $($town).hide().appendTo('#towns-planner').fadeIn();
                    }
                    else
                    {
                        $tmp.fadeToggle(100).fadeToggle(100);
                    }
                    $('#town_search-query').val('');
                }
            }
        });

Quand je debuggue $this->request->data dans l'action du controlleur je trouve bien un tableau towns avec les identifiants des villes ajoutées en javascript.

Faut il rajouter quelque chose dans le controller pour que la table de liaison TownsUsers enregistre bien les données ?
Sinon comment faire ?

Petite question supplémentaire pas vraiment propre à CakePhp : dans la vue et le code javascript j'ai 2 fois le même code avec les données d'une vile :

// vue
<div class="alert alert-info alert-dismissable" data-id="<?= $town->id; ?>" data-type="town-planner">
    <?= $town->name; ?> <small><?= $town->code; ?></small>
    <input type="text" name="towns[]" value="<?= $town->id; ?>" style="display:none">
    <button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span></button>
</div>

// javascript
var $town = '<div class="alert alert-info alert-dismissable" data-id="'+item.id+'" data-type="town-planner">' +
                item.name + ' <small>' + item.code + '</small>' +
                '<input type="text" name="towns[]" value="' + item.id + '" style="display:none">' +
                '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span></button>' +
'</div>';

Y aurait il une méthode pour n'avoir qu'une seule fois le code ?

Merci
Cordialement

1 réponse


Ferias Quarante
Auteur
Réponse acceptée

j'ai trouvé la solution :

// Action du controlleur
public function editTowns($id = null)
    {
        $user = $this->Users->get($id, [
            'contain' => ['Towns']
        ]);
        if ($this->request->is(['post', 'put']))
        {
            if (sizeof($this->request->data['towns']) == 0)
                $user->towns = [];

            $this->Users->patchEntity($user, $this->request->data);

            if ($this->Users->save($user))
            {
                $this->Flash->success("Les villes de l'utilisateur ont bien été enregistrées.");
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error("Impossible de modifier les villes d'un utilisateur");
        }

        return $this->redirect(['action' => 'edit']);
    }

et dans la vue, c'était la principale erreur, le "name" de l'inuput : change

// bug
<input type="text" name="towns[]" value="<?= $town->id; ?>" class="hide">
// correctif
<input type="text" name="towns[][id]" value="<?= $town->id; ?>" class="hide">

Pour moir cela marche en espérant que ca en aidera d'autres