Router.php выполняется трижды

Всем привет! Пишу таск менеджер с использованием модальных окон. На данном этапе перечень задач выводится в виде кнопок, в которых установлен data-id аттрибут, вмещающий в себя id задачи в БД. Пытаюсь вывести форму редактирования задачи в модальном окне. Для этого с помощью AJAX обращаюсь к url: 'task/edit/XXX' (айди вместо ХХХ). В routes.php этот url описан. Router.php свою работу так же делает. Но на выходе (из AJAX, в модальном окне) я вижу, что Router->run(); был запущен аж три раза. В последний раз ещё и uri он получил некорректный. Далее код. Отрывок index.php:

<?php foreach($tasksList as $task) : ?>
     <button class="btn btn_task" data-shot="editTaskMenu" data-id="<?=$task['id'] ?>">
         <?= $task['title'] ?>
     </button>
<?php endforeach; ?>

routes.php:

<?php 
return [
    // Задачи
    'task/create' => 'task/create',
    'task/edit' => 'task/edit',
    'task/edit/([0-9]+)' => 'task/edit/$1',

    // Пользователи
    'user/register' => 'user/register',
    'user/login' => 'user/login',
    'user/logout' => 'user/logout',

    // Главная страница
    '' => 'site/index', // actionIndex в SiteController
];

Router->run():

public function run()
    {
        // Получаем строку запроса
        $uri = $this->getURI();
        echo "<hr>".$uri;

        // Проверяем наличие такого запроса в массиве маршрутов (routes.php)
        foreach ($this->routes as $uriPattern => $path) {

            // Сравниваем $uriPattern и $uri, т.е. "если путь, по которому мы перешли находится в массиве маршрутов, то"
            if (preg_match("~$uriPattern~", $uri)) {

                // Получаем внутренний путь из внешнего согласно правилу
                $internalRoute = preg_replace("~$uriPattern~", $path, $uri);

                // Определяем название контроллера, экшена, параметры. Для этого разбиваем внутр. путь на составные части.
                $segments = explode('/', $internalRoute);

                // Название контроллера будет начинаться в заглавной буквы и состоять из 1ой части внутр. пути и слова Controller
                $controllerName = ucfirst(array_shift($segments) . 'Controller');

                // Название экшена будет начинаться со слова action и 2ой части внутр. пути
                $actionName = 'action' . ucfirst(array_shift($segments));
                echo "<hr>" .$actionName. "<hr>";
                // Оставшееся в сегментах назовём параметрами
                $parameters = $segments;

                // Подключаем файл класса-контроллера
                $controllerFile = ROOT . '/controllers/' . $controllerName . '.php';
                if (file_exists($controllerFile)) include_once($controllerFile);

                // Создаём объект
                $controllerObject = new $controllerName;

                /* Вызываем необходимый метод ($actionName) класса определенного 
                объекта ($controllerObject) с заданными параметрами ($parameters) */
                $result = call_user_func_array(array($controllerObject, $actionName), $parameters);
            }
        }
    }

modal.js:

const btns = document.querySelectorAll('.btn');
const modalOverlay = document.querySelector('.modal-overlay ');
const modals = document.querySelectorAll('.modal');

btns.forEach((el) => {
    el.addEventListener('click', (e) => {
        if (el.classList.contains('btn_task')) {
            console.log(event.target.dataset.id);
            console.log('da');
            $.ajax({
                type: 'POST',
                url: 'task/edit/' + event.target.dataset.id,
                // data: {},
                // dataType: "application/json",
            })        
            .done(function(data) {
                console.log('done');
                $("div[data-target=\"editTaskMenu\"]").html(data);
            })
            .fail(function() {
                alert('error');
            })
        }

        let shot = e.currentTarget.getAttribute('data-shot');

        modals.forEach((el) => {
            el.classList.remove('modal--visible');
        });

        document.querySelector(`[data-target="${shot}"]`).classList.add('modal--visible');
        modalOverlay.classList.add('modal-overlay--visible');
    });
});

modalOverlay.addEventListener('click', (e) => {

    if (e.target == modalOverlay) {
        modalOverlay.classList.remove('modal-overlay--visible');
        modals.forEach((el) => {
            el.classList.remove('modal--visible');
        });
    }
});

Есть какие-нибудь идеи у вас?

Модальное окно


Ответы (0 шт):