PHP,SQL,MVC架构
2024/8/27
Controller里函数怎莫调试
Controllers里面写了一个方法,不知道怎莫调试,很烦。
/** * 根据会员等级计算并刷新会员等级 * 查会员的实收款字段,在会员等级表里查询是否要升级 */ public function actionUpdateMemberLevels() { // 开启事务以确保数据一致性 $transaction = Yii::$app->db->beginTransaction(); try { // 获取所有会员及其相关信息 $members = Yii::$app->db->createCommand(" SELECT id, net_receipts, level_id, level_name FROM tt_member ")->queryAll(); // 获取所有等级及其升级要求 $levels = Yii::$app->db->createCommand(" SELECT level AS level_id, name AS level_name, upgradation FROM tt_client_level ORDER BY level ASC ")->queryAll(); // 如果没有找到任何等级信息,抛出异常 if (empty($levels)) { throw new \Exception("未找到任何等级信息。"); } // 将等级要求存储在数组中以便快速查找 $levelRequirements = []; foreach ($levels as $level) { $levelRequirements[$level['level_id']] = [ 'upgradation' => $level['upgradation'], 'level_name' => $level['level_name'] ]; } $updateNeeded = false; // 标记是否需要更新 // 遍历会员数据并逐级更新等级 foreach ($members as $member) { $currentLevelId = $member['level_id']; // 当前等级ID $currentNetReceipts = $member['net_receipts'] ?? 0; // 如果为 NULL,默认赋值为 0 // 检查当前会员是否可以升级 while (isset($levelRequirements[$currentLevelId + 1]) && $currentNetReceipts >= $levelRequirements[$currentLevelId]['upgradation']) { $currentLevelId++; // 升级到下一个等级 } $newLevelId = $currentLevelId; $newLevelName = $levelRequirements[$newLevelId]['level_name']; // 仅在新等级与当前等级不同时才进行更新 if ($newLevelId !== $member['level_id'] || $newLevelName !== $member['level_name']) { $updateResult = Yii::$app->db->createCommand(" UPDATE tt_member SET level_id = :newLevelId, level_name = :newLevelName WHERE id = :id ")->bindValues([ ':newLevelId' => $newLevelId, ':newLevelName' => $newLevelName, ':id' => $member['id'] ])->execute(); // 如果更新失败,抛出异常 if (!$updateResult) { throw new \Exception("更新会员ID {$member['id']} 从等级 {$member['level_id']} 到等级 {$newLevelId} 失败。"); } echo "会员ID {$member['id']} 的等级从 {$member['level_id']} 更新为 {$newLevelId}。\n"; $updateNeeded = true; } } // 仅在需要更新时提交事务 if ($updateNeeded) { $transaction->commit(); echo "会员等级更新成功。\n"; } else { echo "没有会员需要升级。\n"; } } catch (\Exception $e) { // 在发生错误时回滚事务 $transaction->rollBack(); echo "更新失败: " . $e->getMessage() . "\n"; } }
解决了,比如我这个函数UpdateMemberLevels,它怎莫能在浏览器输出内容呢?按照文件的路径和命名方法(驼峰命名法,单词间转成网址则是小写加连字符),结构就像:
http://127.0.0.1:8081/member/update-member-levels
-
协议(Protocol):
http://
表示这是一个使用HTTP协议的请求。HTTP(超文本传输协议)是用于从万维网(WWW)服务器传输超媒体文档(如HTML)的协议。 -
主机名(Hostname):
127.0.0.1
是一个特殊的IP地址,称为回环地址(Loopback Address)。它指向本机(即你的计算机)。这意味着当你尝试访问这个地址时,请求实际上是在你的计算机内部处理的,而不是发送到网络上的另一台计算机。 -
端口号(Port Number):
:8081
指定了服务器监听的端口号。HTTP协议默认使用端口80,但在这个例子中,服务器被配置为监听端口8081。这意味着,为了访问这个服务,客户端(如浏览器)需要指定端口8081。 -
路径(Path):
/member/update-member-levels
是URL的路径部分,它指定了服务器上资源的具体位置(我的方法的具体地址)。在这个例子中,它可能指向一个处理会员等级更新请求的服务或页面。
刷新index页面数据不更新
在做了以上调整后,我发现每次我在刷新页面(index)时,数据不更新,当我http://127.0.0.1:8081/member/update-member-levels刷新这个网址对应函数时,回头再刷新index页面,数据才更新。错误如下:
请求异常,错误提示:parsererror。 // 先调用更新会员等级的方法 $this->actionUpdateMemberLevels();加了这句后报出错误显示
解析:出现 parsererror
错误通常意味着你的 AJAX 请求期望的是 JSON 格式的响应,但服务器返回的却不是有效的 JSON。这可能是因为在 actionList
中调用了 actionUpdateMemberLevels
后,输出了一些非 JSON 格式的内容,导致解析失败。
解决方法
我们可以做以下几件事来解决这个问题:
1. 确保 actionUpdateMemberLevels
不输出内容
- 在
actionUpdateMemberLevels
中删除或注释掉所有的echo
语句,确保这个方法只更新数据,而不输出任何内容。
2. 调整 actionUpdateMemberLevels
方法
- 删除所有的
echo
语句,并用日志记录替代。
在删掉echo语句后一切如常。
Model里面设置字段规则
public function rules() { return [ [['id', 'point', 'created_by', 'updated_by', 'level_id'], 'integer'], [['phone', 'email', 'address'], 'string', 'max' => 255], [['remark','name'], 'string', 'max' => 100], [['net_receipts'], 'number'], [['expiry', 'birthday'], 'date', 'format'=>'yyyy-MM-dd'], [['level_name'], 'string', 'max' => 40], [['phone', 'level_id', 'level_name'], 'required'], [['mobile','backup_mobile'], 'unique'], ]; }
[['phone', 'level_id', 'level_name'], 'required'],required要求字段内容非空。
定时任务(console/controller)
<?php
namespace console\controllers;
use Yii;
use yii\console\Controller;
use yii\db\Exception;
class UpdateController extends Controller
{
/**
* 每日更新会员累计消费
* @param string $startDate 开始日期,例如 "2024-03-01"
* @throws Exception
*/
public function actionUpdateNetReceipts($startDate = null)
{
if ($startDate === null) {
$startDate = $this->getLastProcessedDate();
}
if ($startDate === null) {
echo "没有找到有效的开始日期。\n";
return;
}
// 验证日期格式
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDate)) {
echo "日期格式不正确。请使用 YYYY-MM-DD 格式。\n";
return;
}
// 获取目标日期(将开始日期推迟一天)
$targetDate = date('Y-m-d', strtotime($startDate . ' +1 day'));
// 开始事务
$transaction = Yii::$app->db->beginTransaction();
try {
// 更新累计实收款到会员表
Yii::$app->db->createCommand("
UPDATE tt_member m
JOIN (
SELECT phone,
SUM(net_receipts) AS total_net_receipts
FROM tt_member_point
WHERE DATE(finished_at) = :startDate
GROUP BY phone
) mp ON m.mobile = mp.phone
SET m.net_receipts = COALESCE(m.net_receipts, 0) + mp.total_net_receipts
", [':startDate' => $startDate])->execute();
// 提交事务
$transaction->commit();
echo "会员累计消费更新成功。\n";
// 更新处理后的开始日期
$this->updateNextDate($targetDate);
echo "下一次处理的日期为: $targetDate\n";
} catch (Exception $e) {
// 发生错误时回滚事务
$transaction->rollBack();
echo "更新失败: " . $e->getMessage() . "\n";
}
}
/**
* 获取上次处理的日期
* @return string|null
*/
protected function getLastProcessedDate()
{
// 从数据库中读取上次处理的日期
$date = (new \yii\db\Query())
->select(['last_execution_date'])
->from('script_execution_log')
->where(['id' => 1])
->scalar();
return $date ?: null;
}
/**
* 更新下次处理日期
* @param string $nextDate
*/
protected function updateNextDate($nextDate)
{
// 更新数据库中的日期
Yii::$app->db->createCommand()
->update('script_execution_log', ['last_execution_date' => $nextDate], ['id' => 1])
->execute();
}
}
在处理这段代码时,刚开始总有问题,后面发现是标红的语段 完成日期 使用的是datetime但程序里的开始日期只是用date数据类型,不匹配。
WHERE DATE(finished_at) = :startDate
做出匹配后修正错误了。