Руководство по заполнению ямы Phalcon: проблемы и решения, возникшие при разработке (постоянно обновляется)

PHP

В этой статье будут описаны проблемы, с которыми я столкнулся при разработке Phalcon, и способы их решения.

1. Правильно получить параметры в контроллере

В общем, запросы GET/POST получают параметры:

$this->request->get(参数名);
$this->request->getPost("参数名")

В режиме маршрутизации маршрут получает параметры с помощью диспетчера->getParam();
Имя параметра определяется в маршруте и может быть получено непосредственно через имя параметра:

this->dispatcher->getParam("参数名");

Маршрут не имеет определенного имени, но в правилах написано :params для сопоставления, которое можно получить по порядку в контроллере:

class NewsController extends Controller {
    public function showAction($id, $testParam)
    {
        echo $id, '|' , $testParam;
    }
}

2. Настройте маршрутизацию для URL

Автоматически разрешать по умолчанию/:controller/:action/:paramsмодель:
При создании экземпляра не добавляйте параметр false:

$router = new Router();

URL будет сделан автоматически/:controller/:action/:paramsРазбор параметров, таких какhttps://www.goozp.com/loginБудет разрешено действие по умолчанию в контроллере входа в систему.

При использовании маршрутизации сохранение режима разбора по умолчанию иногда может привести к путанице при разборе.Полностью настраиваемый режим маршрутизации.
Полностью настройте маршрут, добавьте false, если он новый:

$router = new Router(false);

Не разрешается автоматически/:controller/:action/:paramsЭти правила, конкретные правила сопоставления маршрутов, написаны вами самостоятельно, например:

$router->add('/login',
    [
        'module'     => 'admin',
        'controller' => 'login',
        'action'     => 'index',
    ]
)->setName('login');

Это не вызовет путаницы с URL-адресами из-за автоматического синтаксического анализа, но все URL-адреса должны сами настраивать правила маршрутизации.

3. Неверный вывод приглашения flash после перезаписи (нерешено)

Выходной html-тег после перезаписи представляет собой строку с "" снаружи

4. Правильная установка baseURI в Config

Поскольку существуют правила перезаписи файлов Apache+.htaccess или правила перезаписи nginx, настроенные на public/index.php, нам не нужно, чтобы URL-адрес в проекте имел /publc/index.php.
Но по умолчанию он ссылается на /public/index.php (например, $_SERVER["PHP_SELF"] получает путь от корневого каталога до самой текущей страницы); поэтому, если есть правила перезаписи Apache или конфигурации nginx в публичный /index.php Для конфигурации перезаписи нам нужно указать URL без public/index.php, поэтому есть официальная настройка:
использовать $_SERVER["PHP_SELF"] и регулярное удаление /public/index.php

'baseUri'        => preg_replace('/public([\/\\\\])index.php$/', '', $_SERVER["PHP_SELF"]),

Это динамический метод записи. Проблема с этим методом записи заключается в неопределенности $_SERVER["PHP_SELF"]. Возвращаемое значение будет основано на корне, настроенном Apache или nginx, независимо от того, настроено ли имя хоста или домена, $ _SERVER["PHP_SELF"] будет иметь разные возвращаемые значения. В этом случае регулярные выражения перед описанным выше методом записи не все совместимы, поэтому писать и отлаживать таким образом немного хлопотно.

Просто, используйте статическую запись:
Установите хост или настройте доменное имя

'baseUri'        => '/',

Если вы хотите открыть его прямо под локальным хостом, вам нужно добавить имя внешнего каталога проекта, например:

'baseUri'        => '/zphal/',

В этом случае, когда мы определяем службу URL, нам нужно только передать определенную конфигурацию в:

$di->setShared('url', function () {
    $config = $this->getConfig();

    $url = new UrlResolver();
    $url->setBaseUri($config->application->baseUri); // baseUri

    return $url;
});

Конфигурация WebServer написана выше:

  • Апач:
    .hatccess может быть настроен в соответствии с официальной конфигурацией, при настройке хоста он также может быть настроен на корневой каталог проекта под общедоступным или на один уровень вне общедоступного:
    <VirtualHost *:80>
      DocumentRoot "D:\phpStudy\WWW\zPhal\public"
      ServerName goozp.com
      ServerAlias
    <Directory "D:\phpStudy\WWW\zPhal\public">
        Options FollowSymLinks ExecCGI
        AllowOverride All
        Order allow,deny
        Allow from all
        Require all granted
    </Directory>
    </VirtualHost>
    
  • Nginx
    Примерная конфигурация выглядит следующим образом, настройте ее под публичным доступом и определите правила перезаписи:

    server {
      listen        80;
      server_name www.goozp.com goozp.com;
    
      root /data/www/zPhal/public;
      index index.php index.html index.htm;
    
      charset utf-8;
      client_max_body_size 100M;
      fastcgi_read_timeout 1800;
    
      location / {
          # Matches URLS `$_GET['_url']`
          try_files $uri $uri/ /index.php?_url=$uri&$args;
      }
    
      location ~ \.php$ {
          try_files $uri =404;
    
          #fastcgi_pass  unix:/var/run/php/php7.0-fpm.sock;
          fastcgi_pass  php-fpm:9000;
    
          fastcgi_index /index.php;
    
          include fastcgi_params;
          fastcgi_split_path_info       ^(.+\.php)(/.+)$;
          fastcgi_param PATH_INFO       $fastcgi_path_info;
          fastcgi_param PATH_TRANSLATED /data/www/zPhal/public/$fastcgi_path_info;
          fastcgi_param SCRIPT_FILENAME /data/www/zPhal/public/$fastcgi_script_name;
      }
    
      location ~ /\.ht {
          deny all;
      }
    
      location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
          expires       max;
          log_not_found off;
          access_log    off;
      }
    }
    

5. Менеджер событий, метод записи огня не работает

Неправильно понял руководство и неправильно понял.

НижеОшибкаСпособ записи события слушателя определяется в диспетчере:

$di->set('dispatcher', function () {
    // 创建一个事件管理器
    $eventsManager = new EventsManager();

    $media = new Media();

    $media->setEventsManager($eventsManager);

    // 监听分发器中使用插件产生的事件
    $eventsManager->attach(
        "media",
        new AliYunOss()
    );

    $dispatcher = new Dispatcher();
    $dispatcher->setDefaultNamespace('ZPhal\Modules\Admin\Controllers\\');
    $dispatcher->setEventsManager($eventsManager); // 分配事件管理器到分发器

    return $dispatcher;
});

Однако то, что я хочу инкапсулировать, это функция загрузки файлов, которая не имеет ничего общего с диспетчером, поэтому она не работает и сообщает об ошибке; я должен зарегистрировать службу загрузки файлов, которая возвращает контейнер DI:

$di->set('mediaUpload',function (){
    // 创建一个事件管理器
    $eventsManager = new EventsManager();

    $media = new Media();

    $eventsManager->attach(
        "media",
        new AliYunOss()
    );

    $media->setEventsManager($eventsManager);

    return $media;
});

6. Использование ассоциаций моделей не работает

Вброшенный объект сообщает об ошибке, вам нужно определить псевдоним для связанного объекта и получить его через псевдоним.
если так:

$terms = new Terms();
$terms->name = $name;
$terms->slug = $slug;

$termTaxonomy = new TermTaxonomy();
$termTaxonomy->Terms  = $terms; // 这里
$termTaxonomy->taxonomy = $type;

$termTaxonomy->save();

В $termTaxonomy->Terms = $terms, здесь Термины — это псевдоним для отношения, определенного в модели TermTaxonomy;
Определение в модели выглядит следующим образом:

$this->belongsTo(
    "term_id",
    "ZPhal\\Models\\Terms",
    "term_id",
    [
        "alias" => "Terms",
    ]
);

Если вы не можете позволить себе псевдоним, будет сообщено об ошибке.

7. Вернуть идентификатор первичного ключа при вставке данных

пройти через$model -> getWriteConnection() -> lastInsertId();получить:

$model = new model();

if($model -> create($data)) {
    $insertId = $model -> getWriteConnection() -> lastInsertId($model -> getSource());
}

Или возьмите атрибут id сразу после выполнения:

<?php
$model = new model();

if($model -> create($data)) {
    $insertId = $model -> id;
}

8. модельное событие beforeCreate и проверка поля

Проверка данных и присвоение данных полям таблицы данных, определенным в событии beforeCreate, не вступают в силу.

BeforeCreate проверит, соответствует ли поле требованиям (валидации) перед выполнением, поэтому вставить его во время beforecreate не получится, он сообщит об ошибке, нужно передать значение перед выполнением create, либо установить значение по умолчанию.

Вы можете выполнять проверки назначения в beforeValidation.

9. Когда операционная модель сохранена, сохранение или обновление недействительны.

Проблема заключается в том, что сохранение или обновление не удается, и об ошибке не сообщается.
Ситуация: для первичного ключа установлено два поля, и одно из полей обновляется при обновлении.
Решение: первичный ключ не следует изменять.
Ссылаться на:stackoverflow.com/questions/3…

10. найти() и найтипервого()

  • Формат данных возвращаемого значения функций find() и findFirst() различается.
  • Когда добавляется параметр столбца, объект возвращаемого значения является неполным, поэтому нельзя использовать такие методы, как сохранение, а также нельзя использовать связь модели.
  • Когда данных нет, find() возвращает пустой массив, а findfrist() возвращает false

11. В queryKeys() Phalcon\Cache\Backend\Redis есть следующая ошибка:

Cached keys need to be enabled to use this function (options['statsKey'] == '_PHCR')!

Конфигурация Redis по умолчанию имеет параметр с префиксом «_PHCR», поэтому queryKeys() должен иметь префикс запроса.

12 Исходный скрипт продолжает выполняться после отправки dispatcher->forward()

Вы можете добавить блокировку возврата:

$this->dispatcher->forward([
    "controller" => "error",
    "action"    => "route404"
]);
return;

Код после распространения больше не будет выполняться.

13. Ошибка: ключ шифрования не может быть пустым

При использовании файлов cookie по умолчанию используется шифрование Crypt, и для использования шифрования Crypt необходимо определить глобальный ключ шифрования.
Шифрование файлов cookie можно отключить:

<?php
use Phalcon\Http\Response\Cookies;

$di->set(
    "cookies",
    function () {
        $cookies = new Cookies();

        $cookies->useEncryption(false);

        return $cookies;
    }
);

Или установить ключ:

<?php
use Phalcon\Crypt;

$di->set(
    "crypt",
    function () {
        $crypt = new Crypt();

        $crypt->setKey('#1dj8$=dp?.ak//j1V$'); // 使用你自己的key!

        return $crypt;
    }
);

14. Ошибка удаления кеша: удаление() цикла обхода foreach не удалось удалить после queryKeys()

При обычном удалении:

$this->cache->delete($key)

Если установлен префикс, он будет автоматически иметь префикс $key.

Список queryKeys имеет префикс, поэтому удалите так:

$keys = $this->cache->queryKeys();
    foreach($keys as $key) {
        $this->cache->delete($key)
    }

Переданный ключ такжеАвтоматически добавить префикс снова, кэш не может быть найден, что приводит к сбою удаления.

Решение:

  1. использовать$this->cache->flush()Очистите все кэши, но все кэши будут очищены, поэтому, если это кэш memcache или redis, вы можете установить statsKey, чтобы избежать очистки всех кэшей.
  2. Или без префикса вы можете использовать queryKeys() и delete() в обычном режиме.