day by day

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

  1. 协议(Protocol)http:// 表示这是一个使用HTTP协议的请求。HTTP(超文本传输协议)是用于从万维网(WWW)服务器传输超媒体文档(如HTML)的协议。

  2. 主机名(Hostname)127.0.0.1 是一个特殊的IP地址,称为回环地址(Loopback Address)。它指向本机(即你的计算机)。这意味着当你尝试访问这个地址时,请求实际上是在你的计算机内部处理的,而不是发送到网络上的另一台计算机。

  3. 端口号(Port Number):8081 指定了服务器监听的端口号。HTTP协议默认使用端口80,但在这个例子中,服务器被配置为监听端口8081。这意味着,为了访问这个服务,客户端(如浏览器)需要指定端口8081。

  4. 路径(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

做出匹配后修正错误了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值