当前位置:

首页 > 编程开发 > 使用 PHP 构建您的初创公司:安排会议

使用 PHP 构建您的初创公司:安排会议

本教程是Tuts+上“使用PHP构建您的初创公司”系列的一部分。在本系列中,我将使用我的MeetingPlanner应用程序作为现实生活中的示例,指导您启动从概念到现实的初创公司。在此过程中的每一步,我们都会将MeetingPlanner代码作为开源示例发布,您可以从中学习。我们还将解决出现的与初创企业相关的业务问题。MeetingPlanner的所有代码都是用PHP的Yii2框架编写的。如果您想了解有关Yii2的更多信息,请查看Tuts+上的并行系列“使用Yii2编程”。您可能还想查看我的知识库网站,了

使用 PHP 构建您的初创公司:安排会议

本教程是 Tuts+ 上“使用 PHP 构建您的初创公司”系列的一部分。在本系列中,我将使用我的 Meeting Planner 应用程序作为现实生活中的示例,指导您启动从概念到现实的初创公司。在此过程中的每一步,我们都会将 Meeting Planner 代码作为开源示例发布,您可以从中学习。我们还将解决出现的与初创企业相关的业务问题。

Meeting Planner 的所有代码都是用 PHP 的 Yii2 框架编写的。如果您想了解有关 Yii2 的更多信息,请查看 Tuts+ 上的并行系列“使用 Yii2 编程”。您可能还想查看我的知识库网站,了解 Yii2 问题,Yii2 开发者交流中心。

在过去的六个教程中,我们通过多种方式奠定了应用程序支持的基础:用户、地点、联系人、设置和本地化。我打赌您会和我一样兴奋,因为我们终于准备好开始构建安排会议功能了。感谢您的耐心等待,我已经为这个应用程序的有趣且不可或缺的部分构建了基础架构。

但是,支持安排会议功能的编码教程将至少持续四集。接下来的两集将主要关注为基本用户体验建立支持,选择会议的参与者、地点、日期和时间,并将其存储在数据库中。之后,我们将介绍如何通过电子邮件发送会议请求。我们将在本系列稍后返回来优化和完善用户界面,因为它对于该产品的成功至关重要;后续更新的主要任务是消除会议安排过程中的页面刷新。

构建本教程的功能需要大量代码 - 一些由 Yii 的 Gii 自动生成,还有很多是手动生成的。由于交付此功能的初始部分非常复杂,因此我专注于相当基本的用户界面,我将对其进行迭代完善。

构建此功能涉及 Yii2 框架中编程的许多方面:Active Record 迁移、关系和验证、Gii 代码生成、Bootstrap、Yii2 JQuery UI 扩展和小部件、AJAX、渲染部分视图、DRY 编码实践等。很难选择这里要涵盖的内容。您会注意到早期教程中的存储库发生了很多更改。

如果您有任何疑问或意见,请在下面发布。我确实参与了讨论。

会议页面

引导选项卡

我需要做的第一件事就是为未来、过去和取消的会议构建不同的选项卡。

使用 PHP 构建您的初创公司:安排会议

实现这一点只是 Bootstrap 的伟大之处以及 Yii2 与 Bootstrap 3.x 集成的牢固性的另一个例子。 Bootstrap 有预构建的选项卡。

MeetingController 中,我们预加载每种会议类型的查询并呈现索引视图:

public function actionIndex()
{
  // add filter for upcoming or past
    $upcomingProvider = new ActiveDataProvider([
        'query' => Meeting::find()->joinWith('participants')->where(['owner_id'=>Yii::$app->user->getId()])->orWhere(['participant_id'=>Yii::$app->user->getId()])->andWhere(['Meeting.status'=>[Meeting::STATUS_PLANNING,Meeting::STATUS_CONFIRMED]]),
    ]);
    $pastProvider = new ActiveDataProvider([
        'query' => Meeting::find()->joinWith('participants')->where(['owner_id'=>Yii::$app->user->getId()])->orWhere(['participant_id'=>Yii::$app->user->getId()])->andWhere(['Meeting.status'=>Meeting::STATUS_COMPLETED]),
    ]);
    $canceledProvider = new ActiveDataProvider([
        'query' => Meeting::find()->joinWith('participants')->where(['owner_id'=>Yii::$app->user->getId()])->orWhere(['participant_id'=>Yii::$app->user->getId()])->andWhere(['Meeting.status'=>Meeting::STATUS_CANCELED]),
    ]);

    return $this->render('index', [
        'upcomingProvider' => $upcomingProvider,
        'pastProvider' => $pastProvider,
        'canceledProvider' => $canceledProvider,
    ]);
}

然后,在索引视图中,我们使用选项卡窗格实现引导代码:

title ?>

render('_grid', [ 'dataProvider' => $upcomingProvider, ]) ?>
render('_grid', [ 'dataProvider' => $pastProvider, ]) ?>
render('_grid', [ 'dataProvider' => $canceledProvider, ]) ?>

随着我们深入了解本系列,我将留下许多占位符工作要做。其中之一是通过 AJAX 实现这些选项卡窗格,这样我们就不会预先加载三个查询。

工单追踪

我还将开始在问题跟踪应用 Lighthouse 中为我未来的工作创建票证,以使其更易于跟踪。我将在以后的教程中讨论 Lighthouse。

使用 PHP 构建您的初创公司:安排会议

安排会议的背后是什么?

创建一个安排会议的框架这个简单的任务在幕后却是相当复杂和详细的。我将在整个系列中分阶段完善这一点。

我的第一个目标是构建基本框架,以便我可以开始测试会议安排的功能。

会议由一些 ActiveRecord 数据模型组成,例如Participant、MeetingTime、MeetingPlace、MeetingNote 等。最初,我只是想使用 Yii 代码生成为每个模型构建 CRUD,然后将其集成到单个调度页面中。

这个想法是使用 MVC 来构建所有这些操作,并尽可能坚持 DRY 方法。最初,该界面将通过页面刷新来工作,但稍后我们将返回并使用相同的 MVC 代码通过 AJAX 集成所有这些模型。

创建会议表单

对于许多模型,我首先经历了早期教程中概述的使用 Yii 代码生成器 Gii 构建 CRUD 的过程。然后我根据需要定制它们。目前,我坚持使用非常基本的创建会议表单 - 它甚至还不包括参与者的电子邮件地址。这使我能够快速创建基本的会议记录并在安排页面上工作。

使用 PHP 构建您的初创公司:安排会议

表单提交后,您可以查看会议页面。显然,我会及时修改这个表格和最初的流程。

会议页面

记住我的本系列第一篇教程的模型:

使用 PHP 构建您的初创公司:安排会议

这是我正在处理的表单的早期版本:

使用 PHP 构建您的初创公司:安排会议

实现这一目标涉及大量基础设施、代码(自动生成、手动生成)和第三方小部件。我将逐步引导您完成它。

引导面板和表格

虽然不太可能是最终设计,但我选择使用 Bootstrap 面板来组织属性、地点、日期、时间和注释之间的页面。页面本身由会议控制器的 View 操作呈现,并调用每个视图的特定模型的部分视图。

我不必以这种方式构建它,但我有目的地想要利用 Yii 的所有内置 MVC 框架并尽可能多地集成事物。我的希望是,将来能够更轻松地对整个页面进行 AJAX 化,减少页面刷新并提高源代码的简单性和可维护性。

以下是会议控制器 View 操作的工作原理。它为每个模型加载 ActiveDataProviders,然后呈现会议视图文件:

/**
     * Displays a single Meeting model.
     * @param integer $id
     * @return mixed
     */
    public function actionView($id)
    {
      $timeProvider = new ActiveDataProvider([
          'query' => MeetingTime::find()->where(['meeting_id'=>$id]),
      ]);

      $noteProvider = new ActiveDataProvider([
          'query' => MeetingNote::find()->where(['meeting_id'=>$id]),
      ]);

      $placeProvider = new ActiveDataProvider([
          'query' => MeetingPlace::find()->where(['meeting_id'=>$id]),
      ]);

      $participantProvider = new ActiveDataProvider([
          'query' => Participant::find()->where(['meeting_id'=>$id]),
      ]);
      $model = $this->findModel($id);
      $model->prepareView();
        return $this->render('view', [
            'model' => $model,
            'participantProvider' => $participantProvider,
            'timeProvider' => $timeProvider,
            'noteProvider' => $noteProvider,
            'placeProvider' => $placeProvider,
        ]);
    }

部分视图

通过使用每个关联模型中的所有视图,可以非常轻松地使用 MVC 部分视图显示整个计划页面。会议视图呈现其他模型的所有 _panel 视图。您可以在此处查看 Yii2 渲染方法的文档。

        render('../participant/_panel', [
            'model'=>$model,
            'participantProvider' => $participantProvider,
        ]) ?>

        render('../meeting-place/_panel', [
            'model'=>$model,
            'placeProvider' => $placeProvider,
        ]) ?>       
                
        render('../meeting-time/_panel', [
            'model'=>$model,
            'timeProvider' => $timeProvider,
        ]) ?>

        render('../meeting-note/_panel', [
            'model'=>$model,
            'noteProvider' => $noteProvider,
        ]) ?>

缺少模型

在构建此功能时,我意识到我忽略了几个必要的模型:MeetingPlaceChoiceMeetingTimeChoice。需要这些来存储特定 MeetingPlacesMeetingTimes 的组织者和参与者的可用性。

以下是 MeetingPlaceChoice 的迁移:

$this->createTable('{{%meeting_place_choice}}', [
          'id' => Schema::TYPE_PK,
          'meeting_place_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'user_id' => Schema::TYPE_BIGINT.' NOT NULL',
          'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
          'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
          'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
      ], $tableOptions);
      $this->addForeignKey('fk_mpc_meeting_place', '{{%meeting_place_choice}}', 'meeting_place_id', '{{%meeting_place}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_mpc_user_id', '{{%meeting_place_choice}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');   

以下是 MeetingTimeChoice 的迁移:

$this->createTable('{{%meeting_time_choice}}', [
          'id' => Schema::TYPE_PK,
          'meeting_time_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'user_id' => Schema::TYPE_BIGINT.' NOT NULL',
          'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
          'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
          'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
      ], $tableOptions);
      $this->addForeignKey('fk_mtc_meeting_time', '{{%meeting_time_choice}}', 'meeting_time_id', '{{%meeting_time}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_mtc_user_id', '{{%meeting_time_choice}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');  

随着产品的进步,Yii 的 ActiveRecord 迁移可以轻松地以编程方式扩展数据库架构。

这些模型确定您在上面的每个地点和日期时间的行中看到的开关小部件的状态(反映用户可用性)。在下面的教程中,我将引导您了解如何初始化这些小部件并在 Yii 中使用 AJAX 来更新它们的状态而无需刷新页面。

安排提醒

PrepareView 确定会议的状态,并在必要时警告用户邀请尚未发送:

public function prepareView() {
        $this->setViewer();
        $this->canSend();
        $this->canFinalize();
        // has invitation been sent
         if ($this->canSend()) {
           Yii::$app->session->setFlash('warning', Yii::t('frontend','This invitation has not yet been sent.'));
      }
        // to do - if sent, has invitation been opened
        // to do - if not finalized, is it within 72 hrs, 48 hrs        
      }

Yii 具有显示 Bootstrap Alerts 的内置支持,称为 flashes:

使用 PHP 构建您的初创公司:安排会议

命令按钮

以下是示例会议视图容器的代码,其中包含上面所示的命令按钮:

title) ?>

message ?>

每个按钮都是使用 Yii 的 HTML 帮助器和 Bootstrap 按钮样式创建的:

 $model->id], ['class' => 'btn btn-primary '.(!$model->isReadyToSend?'disabled':'')]) ?>

对于取消和编辑属性按钮,我使用了 Glyphicons。 Glyphicons 非常漂亮,并且免费包含在 Bootstrap 中并与 Yii2 集成。

这些命令有什么作用?

用户添加一名参与者以及至少一个地点、日期和时间后,他或她就可以发送邀请。此功能将通过电子邮件向用户发送会议邀请,我将在即将发布的教程中对此进行描述。

最终确定按钮允许组织者(或参与者)将会议状态从计划更改为即将举行。这个想法是,一旦选择了地点和日期时间,会议就可以“最终确定”。在此之前,参与者将有机会选择建议其他地点和日期时间,组织者(或双方)将可以选择最终地点和日期时间。

取消按钮将取消会议并将其移至会议页面上已取消的选项卡。

参与者

接下来,用户将添加人员。

使用 PHP 构建您的初创公司:安排会议

注意:在我的最小可行产品中,只允许一名参与者,但我们稍后可能会添加更多参与者。

em>

如果您还记得我们在之前的教程中创建的“好友”表,我将允许用户输入新的电子邮件地址,或者通过从现有好友和过去的会议中加载自动完成功能来加快输入速度。

使用 PHP 构建您的初创公司:安排会议

将来,我们将在此处提供更多用户界面选项,包括频繁参与者。

在 Participant 控制器的顶部,我们将朋友加载到一个数组中,以供 JQuery 自动完成小部件使用 - Yii2 中再次内置了对此的支持:

/**
     * Creates a new Participant model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate($meeting_id)
    {
      $mtg = new Meeting();
      $title = $mtg->getMeetingTitle($meeting_id);
        $model = new Participant();
        $model->meeting_id= $meeting_id;
        $model->invited_by= Yii::$app->user->getId();
        // load friends for auto complete field
        $friends = Friend::getFriendList(Yii::$app->user->getId());

这是_form.php,位于\frontend\views\participant

errorSummary($model); ?>

Email address:

$model, 'attribute' => 'email', 'clientOptions' => [ 'source' => $friends, ], ]); ?>

我做出了将所有参与者存储在用户表中的设计决策。我可能会后悔——还不确定。但它极大地简化了流程,让人们能够快速开始使用网站,并简化了整体数据模型。

当用户邀请系统未知的人(新电子邮件地址)时,我们会在用户表中被动注册他们。

if ($model->load(Yii::$app->request->post())) {
          if (!User::find()->where( [ 'email' => $model->email ] )->exists()) {
            // if email not already registered
            //  create new user with temporary username & password
            $temp_email_arr[] = $model->email;
            $model->username = Inflector::slug(implode('-', $temp_email_arr));
            $model->password = Yii::$app->security->generateRandomString(12);
            $model->participant_id = $model->addUser();
          } else {
            // add participant from user record
            $usr = User::find()->where( [ 'email' => $model->email ] )->one();
            $model->participant_id = $usr->id;
          }
          // validate the form against model rules
          if ($model->validate()) {
              // all inputs are valid
              $model->save();              
              return $this->redirect(['/meeting/view', 'id' => $meeting_id]);
          } 

我们根据他们的电子邮件地址创建用户名。我在 Inflector 助手中使用 Yii 的 slug 生成器。我们现在使用 Yii 的安全助手创建一个随机密码。如果我使用普通 PHP,我可能必须集成其他函数才能实现这些功能。相反,它是内置的。

让我们继续添加地点。

地点

对每个控制器和模型使用 Yii 的 MVC 比将所有这些功能编码到会议控制器中具有很大的优势。它使理解和管理代码变得更加简单和更有条理。

但是,我很快注意到,我必须自定义默认面包屑以链接回当前会议页面,而不是特定模型的索引或视图。

使用 PHP 构建您的初创公司:安排会议

我们实际上使用 MeetingPlace 模型来添加会议地点。在 \frontend\views\meeting-place\create.php 中,我只需自定义 breadcrumbs 区域中的链接:

title = Yii::t('frontend', 'Add a {modelClass}', [
    'modelClass' => 'Meeting Place',
]);
$this->params['breadcrumbs'][] = ['label' => Yii::t('frontend', 'Meetings'), 'url' => ['/meeting/index']];

$this->params['breadcrumbs'][] = ['label'=>$title,'url' => ['/meeting/view', 'id' => $model->meeting_id]];
$this->params['breadcrumbs'][] = $this->title;

?>

添加对直接添加 Google 地点的支持

使用 PHP 构建您的初创公司:安排会议

我不仅想自定义地点创建表单,以便用户添加以前使用过的地点,还希望他们添加新的 Google 地方信息正在运行。

我基本上必须在 MeetingPlace 创建中复制我们在 Google 地方信息教程中构建的支持:



errorSummary($model); ?>

Choose one of your places

all(), 'place.id', 'place.name'),['prompt'=>Yii::t('frontend','-- select one of your places below --')] ) ?>

- or -

Choose from Google Places

Type in a place or business known to Google Places:

field($model, 'searchbox')->textInput(['maxlength' => 255])->label('Place') ?>
isNewRecord ? Yii::t('frontend', 'Add Place') : Yii::t('frontend', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

我还需要更多地利用 Yii2 复杂的验证支持。在下面的 MeetingPlace 模型中,如果有人尝试前往已建议的会议地点,我们会使用 Yii2 的独特验证来报告错误:

    public function rules()
    {
        return [
            [['meeting_id', 'place_id', 'suggested_by'], 'required'],
            [['meeting_id', 'place_id', 'suggested_by', 'status', 'created_at', 'updated_at'], 'integer'],
            [['place_id'], 'unique', 'targetAttribute' => ['place_id','meeting_id'], 'message'=>Yii::t('frontend','This place has already been suggested.')],

我还在 MeetingPlaceController 创建操作中添加了一个自定义错误条件(如果用户从其列表以及 Google Place 中选择地点),尽管这可能是一个需要保留的可选功能(有意见吗?请在下面的评论中发表):

     public function actionCreate($meeting_id)
     {
       $mtg = new Meeting();
       $title = $mtg->getMeetingTitle($meeting_id);
         $model = new MeetingPlace();
         $model->meeting_id= $meeting_id;
         $model->suggested_by= Yii::$app->user->getId();
         $model->status = MeetingPlace::STATUS_SUGGESTED;
         $posted_form = Yii::$app->request->post(); 
         if ($model->load($posted_form)) {
          // check if both are chosen and return an error
           if ($model->place_id<>'' and $posted_form['MeetingPlace']['google_place_id']<>'') {    
             $model->addErrors(['place_id'=>Yii::t('frontend','Please choose one or the other')]);
             return $this->render('create', [
                  'model' => $model,
                   'title' => $title,
              ]);             
           }

我使用了 Yii2 的 addErrors 方法。

我还修复了第三集中的一个错误,即每当有人更改 Google 地点选择时就会创建多个地图框。检查 article 选择器中现有的子级数量修复了此问题:

function loadMap(gps,name) {
  if (document.querySelector('article').children.length==0) {
    var mapcanvas = document.createElement('div');
    mapcanvas.id = 'mapcanvas';
    mapcanvas.style.height = '300px';
    mapcanvas.style.width = '300px';
    mapcanvas.style.border = '1px solid black';    
    document.querySelector('article').appendChild(mapcanvas);  
  }

未来,这种创作形式将包含一些重要的功能:

  • 允许用户添加他们当前的地理位置。
  • 推荐用户推荐的常去地点。
  • 提供对用户最喜爱的地点的快速访问。
  • 建议用户和参与者附近(等距离)的地点。
  • 建议付费广告商赞助的地点。
  • 允许组织者删除地点和日期时间 - 可能是在参与者未看到或回复的情况下。

允许用户记录特定地点和日期时间也可能很有用。例如,我可能会指定“这个地方适合我周四早上但周五下午不适合”或“如果您选择这个时间,我们可以在国会山的 Caffe Vita 进行吗”。如果您对此功能有意见(这会增加复杂性),请在下面发表评论。

显示面板

对于每个模型,我们使用类似的视图层次结构和 Yii2 组件。会议控制器在 \frontend\views\meeting-place 中呈现 _panel.php 的视图:


$model->id], ['class' => 'btn btn-primary glyphicon glyphicon-plus']) ?>
count>0): ?> $placeProvider, 'itemOptions' => ['class' => 'item'], 'layout' => '{items}', 'itemView' => '_list', 'viewParams' => ['placeCount'=>$placeProvider->count], ]) ?>
count>1) echo Yii::t('frontend','Choose'); ?>

Bootstrap 兼容表的概要位于 _panel.php 中。然后我们使用 Yii2 Listview 小部件以表格形式显示每一行数据。 itemView 部分位于 _list.php 中。

请注意,我们通过 viewParams 传递了一个名为 placeCount 的自定义变量。这对于配置表格中的按钮非常方便。

这是 _list.php 视图,我将在下一个教程中更详细地介绍该视图,包括切换输入小部件和 AJAX 实现。



 
  
        place->name,BaseUrl::home().'/place/'.$model->place->slug) ?>
  
  
      meetingPlaceChoices as $mpc) {
        if ($mpc->user_id == $model->meeting->owner_id) {
            if ($mpc->status == $mpc::STATUS_YES)
              $value = 1;
            else
              $value =0;
              echo SwitchInput::widget([
              'type'=>SwitchInput::CHECKBOX,
              'name' => 'meeting-place-choice',
              'id'=>'mpc-'.$mpc->id,          
              'value' => $value,
              'pluginOptions' => ['size' => 'mini','onText' => '','offText'=>'','onColor' => 'success','offColor' => 'danger',],
              ]);          
        }
      }      
      ?>
  
  
    meetingPlaceChoices as $mpc) {
    if (count($model->meeting->participants)==0) break;    
    if ($mpc->user_id == $model->meeting->participants[0]->participant_id) {
        if ($mpc->status == $mpc::STATUS_YES)
          $value = 1;
        else if ($mpc->status == $mpc::STATUS_NO)
          $value =0;
        else if ($mpc->status == $mpc::STATUS_UNKNOWN)
          $value =-1;
            echo SwitchInput::widget([
          'type'=>SwitchInput::CHECKBOX,         
          'name' => 'meeting-place-choice',
          'id'=>'mpc-'.$mpc->id,          
          'tristate'=>true,
          'indeterminateValue'=>-1,
          'indeterminateToggle'=>false,
          'disabled'=>true,
          'value' => $value,
          'pluginOptions' => ['size' => 'mini','onText' => '','offText'=>'','onColor' => 'success','offColor' => 'danger'],
      ]);          
    }
  }
    ?>
  
  
      
      1) {
        if ($model->status == $model::STATUS_SELECTED) {
            $value = $model->id;
        }    else {
          $value = 0;        
        } 
        echo SwitchInput::widget([
          'type' => SwitchInput::RADIO,
          'name' => 'place-chooser',
            'items' => [
                [ 'value' => $model->id],
            ],
            'value' => $value,
            'pluginOptions' => [  'size' => 'mini','handleWidth'=>60,'onText' => '','offText'=>''],
            'labelOptions' => ['style' => 'font-size: 12px'],
        ]);              
      }
      ?>
  

日期和时间

为了添加日期和时间,我们通过 2Amigos Yii2 日期时间扩展集成了 Bootstrap JQuery 日期时间选择器

使用 PHP 构建您的初创公司:安排会议



$model, 'attribute' => 'start', 'language' => 'en', 'size' => 'ms', 'clientOptions' => [ 'autoclose' => true, 'format' => 'MM dd, yyyy HH:ii P', 'todayBtn' => true, 'minuteStep'=> 15, 'pickerPosition' => 'bottom-left', ] ]);?>

isNewRecord ? Yii::t('frontend', 'Add') : Yii::t('frontend', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>

我希望将来对这个小部件进行一些增强。我想让它在加载时自动打开,但目前似乎没有相应的设置。

我们再次使用唯一的验证器来确保特定日期和时间尚未添加到会议中:

public function rules()
    {
        return [
            [['meeting_id', 'start', 'suggested_by'], 'required'],
            [['meeting_id', 'start', 'suggested_by', 'status', 'created_at', 'updated_at'], 'integer'],
            [['start'], 'unique', 'targetAttribute' => ['start','meeting_id'], 'message'=>Yii::t('frontend','This date and time has already been suggested.')],
            
        ];
    }

在会议视图页面上,“日期和时间”面板的构建方式与“地点”类似:


$model->id], ['class' => 'btn btn-primary glyphicon glyphicon-plus']) ?>
count>0): ?> $timeProvider, 'itemOptions' => ['class' => 'item'], 'layout' => '{items}', 'itemView' => '_list', 'viewParams' => ['timeCount'=>$timeProvider->count], ]) ?>
count>1) echo Yii::t('frontend','Choose'); ?>

这是_list.php 视图:



 
  
        start) ?>
  
  
      meetingTimeChoices as $mtc) {
        if ($mtc->user_id == $model->meeting->owner_id) {
            if ($mtc->status == $mtc::STATUS_YES)
              $value = 1;
            else
              $value =0;
              echo SwitchInput::widget([
              'type' => SwitchInput::CHECKBOX,              
              'name' => 'meeting-time-choice',
              'id'=>'mtc-'.$mtc->id,
              'value' => $value,
              'pluginOptions' => ['size' => 'mini','onText' => '','offText'=>'','onColor' => 'success','offColor' => 'danger',],
              ]);          
        }
      }
      ?>
  
  
    meetingTimeChoices as $mtc) {
      if (count($model->meeting->participants)==0) break;
      if ($mtc->user_id == $model->meeting->participants[0]->participant_id) {
          if ($mtc->status == $mtc::STATUS_YES)
            $value = 1;
          else if ($mtc->status == $mtc::STATUS_NO)
            $value =0;
          else if ($mtc->status == $mtc::STATUS_UNKNOWN)
            $value =-1;
          echo SwitchInput::widget([
            'type' => SwitchInput::CHECKBOX,          
            'name' => 'meeting-time-choice',
            'id'=>'mtc-'.$mtc->id,
            'tristate'=>true,
            'indeterminateValue'=>-1,
            'indeterminateToggle'=>false,
            'disabled'=>true,
            'value' => $value,
            'pluginOptions' => ['size' => 'mini','onText' => '','offText'=>'','onColor' => 'success','offColor' => 'danger',],
        ]);          
      }
    }
    ?>
  
  
      1) {
        if ($model->status == $model::STATUS_SELECTED) {
            $value = $model->id;
        }    else {
          $value = 0;        
        } 
        echo SwitchInput::widget([
            'type' => SwitchInput::RADIO,
            'name' => 'time-chooser',
            'items' => [
                [ 'value' => $model->id],
            ],
            'value' => $value,
            'pluginOptions' => [  'size' => 'mini','handleWidth'=>60,'onText' => '','offText'=>''],
            'labelOptions' => ['style' => 'font-size: 12px'],
        ]);            
      }
      ?>
  


注释

会议笔记允许用户根据他们的建议来回沟通并选择地点和日期时间,而无需实际分别向彼此发送电子邮件。

使用 PHP 构建您的初创公司:安排会议

会议页面上的注释如下所示:

使用 PHP 构建您的初创公司:安排会议

注释的实现与上述地点和日期时间的实现几乎相同。您可以查看 MeetingNote 控制器和 \frontend\views\meeting-note 视图文件以获取更多信息。

下一步是什么?

我希望您通过本教程学到了一些新东西。请观看我的“使用 PHP 构建您的初创公司”系列中即将推出的教程 - 即将推出许多有趣的功能。

在下一个教程中,我将深入探讨如何使用 AJAX 实现地点和日期时间选择。之后,我们将开始构建电子邮件以发送消息邀请、在日程安排页面上收集参与者的回复,并最终确定现实世界的会议。

请随时在下面添加您的问题和评论;我一般都会参与讨论。您还可以通过 Twitter @reifman 联系我或直接给我发送电子邮件。

相关链接

  • 使用 Yii2 编程:入门
  • Yii 开发者交流中心

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
C++动态数组初始化怎么写?常用语句与代码示例
C++动态数组初始化怎么写?常用语句与代码示例

深入解析C++中动态数组的初始化机制,涵盖new操作符的不同用法、基本类型与类对象的初始化差异,以及为何在现代C++开发中应优先使用std::vector。

using namespace 使用中遇到的问题怎么解决
using namespace 使用中遇到的问题怎么解决

命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,

c语言函数递归 实操经验总结:这些技巧很实用
c语言函数递归 实操经验总结:这些技巧很实用

理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接

c语言函数递归 怎么选?常见方案对比分析
c语言函数递归 怎么选?常见方案对比分析

递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的

Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解

理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的

如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏

理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de

深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制
深入理解 Objective-C 中的 dealloc 方法:内存管理核心机制

内存管理的基石在Objective-C的世界里,内存管理是开发者必须掌握的核心技能之一。作为一门在手动引用计数(MRC)时代诞生的语言,Objective-C要求程序员对对象的生命周期有清晰的认识。dealloc方法正是这一生命周期中至关重要的终点站。它是一个实例方法,当对象的引用计数降为零时,系统

理解 native2ascii:Java 国际化开发中的字符编码工具
理解 native2ascii:Java 国际化开发中的字符编码工具

native2ascii 工具的基本定位在Ja va应用程序的国际化与本地化开发过程中,处理非拉丁字符集是一个常见且关键的环节。Ja va内部使用Unicode字符集来统一表示全球各种语言的文字,但其属性文件(.properties)在历史上要求使用ASCII编码,或者更准确地说,要求非ASCII字

如何使用 native2ascii 转换中文字符为 Unicode 转义序列
如何使用 native2ascii 转换中文字符为 Unicode 转义序列

理解 native2ascii 工具的基本用途在软件开发,特别是涉及国际化处理的场景中,开发者常常需要处理不同编码的文本资源。native2ascii 是 Ja va 开发工具包(JDK)中提供的一个命令行实用程序,其主要功能是将包含本地字符编码(非ASCII字符)的文件,转换为包含 Unicode

Java native2ascii 命令详解:解决属性文件乱码问题
Java native2ascii 命令详解:解决属性文件乱码问题

native2ascii 命令的由来与作用在Ja va开发中,处理国际化资源文件是一个常见需求。资源文件通常以.properties格式存储,用于支持多语言界面。然而,Ja va属性文件默认采用ISO-8859-1字符集编码,这导致了一个直接的问题:当文件中包含非拉丁字符(如中文、日文、韩文等)时,

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

网站备案号:苏ICP备2026018738号-1 联系邮箱:bd@zhengruan.com 网站地图

Copyright ©2018-2026