搜尋
首頁後端開發php教程使用 PHP 設計新創公司的資料庫並概述功能需求

使用 PHP 设计初创公司的数据库并概述功能需求

這是「使用 PHP 建立您的新創公司」系列的第二部分,我將引導您完成我的新創公司 Meeting Planner 從概念到啟動的整個開發過程。在這一部分中,我將概述功能目標和要求,然後引導您完成初始資料庫設計和遷移。

因為我們不會看到很多功能立即生效,所以這一集可能看起來有點枯燥,但為接下來的所有內容奠定基礎至關重要。如果您還沒有設計過 Active Record 資料庫遷移並使用過 Yii 的鷹架應用程式 Gii,那麼您可能會學到很多東西。

功能要求

在描述 Meeting Planner 資料庫的具體資訊之前,我將引導您了解 Meeting Planner 將提供的進階功能。

規劃會議

  • 允許使用者建立會議請求並邀請其他人(我們的最低可行產品僅邀請一個人)。
  • 允許使用者建議和選擇地點。
  • 允許使用者建議和選擇日期和時間。
  • 允許使用者在會議規劃過程中互相傳送註解。
  • 建議適合在使用者附近舉行會議的地點。
  • 記錄所有會議新增和變更的日誌(或歷史記錄)。

支援地點

  • 允許用戶添加他們喜歡定期聚會的最喜歡的地點。
  • 允許使用者新增自己的會議地點,例如家庭和辦公室。
  • 部分根據受歡迎程度建議距離每位參與者較近或等距的地點。

支援用戶

  • 維護所有正在進行的、已確認的和過去的使用者會議的清單。
  • 允許使用者提供聯絡資訊,例如線上會議的電話號碼和 Skype 地址。
  • 允許使用者關閉不需要的電子郵件,即取消訂閱。
  • 要求使用者在發送邀請之前驗證其電子郵件的身份。
  • 輕鬆封鎖與不需要的邀請相關的電子郵件,例如垃圾郵件。

讓事情變得更簡單、更快

  • 允許用戶建立模板,以便更輕鬆地安排常見會議,並提供建議的日期和時間以及最喜歡的地點,例如我想安排在我最喜歡的地點、星期幾和開始時間與某人一起喝早晨咖啡
  • 發送包含會議更改的電子郵件,並附上用於進行更改的命令的 URL 鏈接,例如取消或要求更改地點、日期或時間;透過這些連結中的驗證碼對使用者進行身份驗證。
  • 提前一天發送會議提醒,其中包含聯絡資訊和路線。

賺取收入

  • 允許廣告商,例如餐廳、咖啡店和租賃辦公空間來宣傳他們的場所。

雖然上面並不是詳盡的功能列表,但它使您清楚地了解我們需要資料庫架構支援什麼。

#安裝會議規劃器儲存庫

要開始為 Meeting Planner 設定開發環境,您可以使用我的指南《使用 Yii2 程式設計:入門》;依照指示安裝 Composer。

所有會議策劃者教學都將在我們的免費開源 Github 儲存庫中進行標記。因此,對於本教學系列的這一部分,您可以從此處安裝基本的會議規劃器框架。

對於Meeting Planner,我安裝了Yii2 的高級應用程式模板,它為複雜的應用程式提供了稍微更強大的架構,例如用於前端(最終用戶)和後端(管理)訪問的不同應用程式。

要開始使用程式碼,您需要複製儲存庫,查看本部分教學的標記版本,執行初始化,並要求 Composer 更新檔案:

cd ~/Sites
git clone git@github.com:newscloud/mp.git
cd ~/Sites/mp
git checkout p2 
sudo -s php init
sudo composer update

我在本機開發環境中使用 MAMP。因此,我需要將我首選的前端本機主機 URL 指向 ~/Sites/mp/frontend/web:

cd /Applications/MAMP/htdocs
ln -s ~/Sites/mp/frontend/web/ /Applications/MAMP/htdocs/mp

如果您將瀏覽器導航到 http://localhost:8888/mp,您應該會看到以下內容:

使用 PHP 设计初创公司的数据库并概述功能需求

然後,您需要在 MySQL 中建立資料庫並在 \環境\dev\common\main-local.php:

<?php
return [
    'components' => [
        'db' => [
            'class' => 'yii\db\Connection',
            'dsn' => 'mysql:host=localhost;dbname=your-db',
            'username' => 'your-username',
            'password' => 'your-pwd',
            'charset' => 'utf8',
        ],

在我們進一步深入運行遷移之前,我想引導您完成初步的資料庫設計。

#設計資料庫架構

因為我正處於建立程式碼的早期階段,所以我試圖徹底完成資料庫的佈局;然而,隨著我的前進,設計可能需要改變或發展。

Yii 的 Active Record 遷移使得在不同環境中以程式設計方式建立資料庫變得相對容易,例如:本地和生產,並逐步發展它們。您可以在此處了解有關 Yii Active Record 的更多資訊。

用户表

第一次迁移构建了用户表,它包含在 Yii 的高级应用程序模板中 - 请参阅 /mp/console/migrations/m130524_201442_init.php

此迁移告诉 Yii 创建一个新的 SQL 表,其中包含用户表所需的字段,如下所示:

<?php

use yii\db\Schema;
use yii\db\Migration;

class m130524_201442_init extends Migration
{
    public function up()
    {
        $tableOptions = null;
        if ($this->db->driverName === 'mysql') {
            // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
            $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
        }

        $this->createTable('{{%user}}', [
            'id' => Schema::TYPE_BIGPK,
            'friendly_name' => Schema::TYPE_STRING . ' NOT NULL',
            'username' => Schema::TYPE_STRING . ' NOT NULL',
            'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL',
            'password_hash' => Schema::TYPE_STRING . ' NOT NULL',
            'password_reset_token' => Schema::TYPE_STRING,
            'email' => Schema::TYPE_STRING . ' NOT NULL',
            'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',

            'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',
            'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
            'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
        ], $tableOptions);
    }

    public function down()
    {
        $this->dropTable('{{%user}}');
    }
}

您可以运行第一次迁移,如下所示:

cd ~/Sites/mp
./yii migrate/up 1

您应该看到类似这样的内容:

Jeffs-Mac-mini:mp Jeff$ ./yii migrate/up 1
Yii Migration Tool (based on Yii v2.0.0)

Creating migration history table "migration"...done.
Total 1 out of 15 new migrations to be applied:
    m130524_201442_init

Apply the above migration? (yes|no) [no]:yes
*** applying m130524_201442_init
    > create table {{%user}} ... done (time: 0.068s)
*** applied m130524_201442_init (time: 0.071s)


Migrated up successfully.

Yii 为注册、登录、注销等常见操作提供内置 Web 支持。此功能和此表将为我们的初始身份验证功能提供支持基础。我们稍后可能会以各种方式对其进行扩展,例如支持 Twitter 或 Google OAuth 进行身份验证。

通过 Active Record 迁移,您还可以向后迁移。这在开发过程中特别有帮助。例如向下迁移会删除User表:

Jeffs-Mac-mini:mp Jeff$ ./yii migrate/down 1
Yii Migration Tool (based on Yii v2.0.0)

Total 1 migration to be reverted:
    m130524_201442_init

Revert the above migration? (yes|no) [no]:yes
*** reverting m130524_201442_init
    > drop table {{%user}} ... done (time: 0.001s)
*** reverted m130524_201442_init (time: 0.070s)


Migrated down successfully.

如果您需要调整表格设计,可以先进行调整,然后再迁移回来。

会议桌

会议架构以及与会议相关的所有表格对于我们应用程序的功能非常重要。

这是会议的基本架构:

 $this->createTable('{{%meeting}}', [
            'id' => Schema::TYPE_PK,
            'owner_id' => Schema::TYPE_BIGINT.' NOT NULL',
            'meeting_type' => Schema::TYPE_SMALLINT.' NOT NULL DEFAULT 0',
            'message' => Schema::TYPE_TEXT.' NOT NULL DEFAULT ""',
            'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
            'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
            'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
        ], $tableOptions);

会议的基础由所有者、会议指示符类型、邀请消息、状态字段以及标准创建和更新时间字段组成。

通过 Active Record,Yii 可以帮助我们自动创建表之间的关系。在会议表中,我们将创建一个关系,即每个会议在用户表中都有一个所有者。我们在迁移中通过创建一个外键将会议 -> Owner_ID 连接到用户 -> ID 来完成此操作。

$this->addForeignKey('fk_meeting_owner', '{{%meeting}}', 'owner_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');        

我们还需要在向下迁移中删除外键:

    public function down()
    {
       	$this->dropForeignKey('fk_meeting_owner', '{{%meeting}}');
        $this->dropTable('{{%meeting}}');
    }

在我们进入 Yii 的自动化脚手架系统 Gii 之前,请耐心等待我概述更多架构。

您可以在 /mp/console/migrations 文件夹 中看到所有迁移:

使用 PHP 设计初创公司的数据库并概述功能需求

我们将在下面回顾其中的大部分内容。

餐位表

地点也是 Meeting Planner 中的一个重要组成部分,因为它们是每个人都会见面的地点。它们按地理位置编入索引,并在 Google 地方信息中引用。

这是地点的架构:

$tableOptions = null;
      if ($this->db->driverName === 'mysql') {
          $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
      }

      $this->createTable('{{%place}}', [
          'id' => Schema::TYPE_PK,
          'name' => Schema::TYPE_STRING.' NOT NULL',          
          'place_type' => Schema::TYPE_SMALLINT.' NOT NULL DEFAULT 0',
          'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
          'google_place_id' => Schema::TYPE_STRING.' NOT NULL', // e.g. google places id
          'created_by' => Schema::TYPE_BIGINT.' NOT NULL',
          'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
          'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
      ], $tableOptions);
      $this->addForeignKey('fk_place_created_by', '{{%place}}', 'created_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');

地点由 nameplace_typestatuscreated_at更新_at。但它们还包含 google_place_id 将它们与 Google Places 目录关联起来。

请注意,没有任何与此表中的地点关联的地理位置。这是因为 MySQL InnoDB 引擎不支持空间索引。因此,我使用 MyISAM 表创建了一个辅助表来存储地点的地理位置坐标。这是 Place_GPS 表:

class m141025_213611_create_place_gps_table extends Migration
{
  public function up()
  {
      $tableOptions = null;
      if ($this->db->driverName === 'mysql') {
          $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=MyISAM';
      }

      $this->createTable('{{%place_gps}}', [
          'id' => Schema::TYPE_PK,
          'place_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'gps'=>'POINT NOT NULL',
      ], $tableOptions);
      $this->execute('create spatial index place_gps_gps on '.'{{%place_gps}}(gps);');
      $this->addForeignKey('fk_place_gps','{{%place_gps}}' , 'place_id', '{{%place}}', 'id', 'CASCADE', 'CASCADE');
  }

请注意,它通过 place_id 与 Place 表相关。地点的位置只是 GPS 坐标,或 MySQL POINT。

参与者表

会议参与者存储在名为“参与者”的连接表中。他们通过 meeting_id 加入会议表,并通过 participant_id 加入用户表。如果我们希望每次会议有多个会议参与者,此表将在将来实现这一点。

class m141025_215701_create_participant_table extends Migration
{
  public function up()
  {
      $tableOptions = null;
      if ($this->db->driverName === 'mysql') {
          $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
      }

      $this->createTable('{{%participant}}', [
          'id' => Schema::TYPE_PK,
          'meeting_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'participant_id' => Schema::TYPE_BIGINT.' NOT NULL',
          'invited_by' => 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_participant_meeting', '{{%participant}}', 'meeting_id', '{{%meeting}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_participant_participant', '{{%participant}}', 'participant_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_participant_invited_by', '{{%participant}}', 'invited_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');      
  }

其他相关会议桌

还有其他几个表格可以帮助定义我们的会议计划选项。

会议时间表

此表包含按开始时间(时间戳)列出的所有建议会议时间(和日期)。 Suggested_by 显示谁建议的时间。而status决定是否选择会议时间。

      $this->createTable('{{%meeting_time}}', [
          'id' => Schema::TYPE_PK,
          'meeting_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'start' => Schema::TYPE_INTEGER.' NOT NULL',
          'suggested_by' => 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_meeting_time_meeting', '{{%meeting_time}}', 'meeting_id', '{{%meeting}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_participant_suggested_by', '{{%meeting_time}}', 'suggested_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');      

集合地点表

此表显示了为会议建议的地点:

$this->createTable('{{%meeting_place}}', [
          'id' => Schema::TYPE_PK,
          'meeting_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'place_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'suggested_by' => 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_meeting_place_meeting', '{{%meeting_place}}', 'meeting_id', '{{%meeting}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_meeting_place_place', '{{%meeting_place}}', 'place_id', '{{%place}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_meeting_suggested_by', '{{%meeting_place}}', 'suggested_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     

会议日志表

此表记录特定会议的所有添加和更改的历史记录。会议安排期间采取的每个操作都会被记录下来,以提供与会议相关的事件的时间历史记录。它将帮助用户查看一段时间内会议的所有更改的记录,并且还可能帮助我们进行开发调试。

$this->createTable('{{%meeting_log}}', [
          'id' => Schema::TYPE_PK,
          'meeting_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'action' => Schema::TYPE_INTEGER.' NOT NULL',
          'actor_id' => Schema::TYPE_BIGINT.' NOT NULL',
          'item_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'extra_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',
          'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',
      ], $tableOptions);
      $this->addForeignKey('fk_meeting_log_meeting', '{{%meeting_log}}', 'meeting_id', '{{%meeting}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_meeting_log_actor', '{{%meeting_log}}', 'actor_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');

会议记录表

用户在对会议进行更改时可以来回发送简短的注释。该表记录了这些注释。

$this->createTable('{{%meeting_note}}', [
          'id' => Schema::TYPE_PK,
          'meeting_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'posted_by' => Schema::TYPE_BIGINT.' NOT NULL DEFAULT 0',
          'note' => Schema::TYPE_TEXT.' NOT NULL DEFAULT ""',
          '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_meeting_note_meeting', '{{%meeting_note}}', 'meeting_id', '{{%meeting}}', 'id', 'CASCADE', 'CASCADE');
      $this->addForeignKey('fk_meeting_note_posted_by', '{{%meeting_note}}', 'posted_by', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     

其他相关用户表

有几个表可以扩展用户定义。

好友表

这是一个索引表,列出了每个用户的好友。它还跟踪他们是否是最喜欢的朋友以及他们举行的会议数量。这可能有助于简化调度体验,例如首先显示最喜欢的或经常的朋友。

$this->createTable('{{%friend}}', [
          'id' => Schema::TYPE_PK,
          'user_id' => Schema::TYPE_BIGINT.' NOT NULL',
          'friend_id' => Schema::TYPE_BIGINT.' NOT NULL',
          'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
          'number_meetings' => Schema::TYPE_INTEGER . ' NOT NULL DEFAULT 0',
          'is_favorite' => 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_friend_user_id', '{{%friend}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     
      $this->addForeignKey('fk_friend_friend_id', '{{%friend}}', 'friend_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     

用户位置表

这是用户喜欢见面或过去见过的地点的索引表。我们将在此处跟踪该用户最喜欢的地点和举行的会议数量。 is_special 字段将指示某个地点是用户自己的家、办公室或会议地点。

$this->createTable('{{%user_place}}', [
          'id' => Schema::TYPE_PK,
          'user_id' => Schema::TYPE_BIGINT.' NOT NULL',
          'place_id' => Schema::TYPE_INTEGER.' NOT NULL',
          'is_favorite' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
          'number_meetings' => Schema::TYPE_INTEGER . ' NOT NULL DEFAULT 0',
          'is_special' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
          'note' => Schema::TYPE_STRING . ' 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_user_place_user', '{{%user_place}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     
      $this->addForeignKey('fk_user_place_place', '{{%user_place}}', 'place_id', '{{%place}}', 'id', 'CASCADE', 'CASCADE');     

用户联系表

此表提供特定用户的联系信息,例如电话号码、Skype 地址以及与在这些地方联系用户相关的任何注释。

 $this->createTable('{{%user_contact}}', [
          'id' => Schema::TYPE_PK,
          'user_id' => Schema::TYPE_BIGINT.' NOT NULL',
          'contact_type' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0',
          'info' => Schema::TYPE_STRING . ' NOT NULL',
          'details' => Schema::TYPE_TEXT . ' 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_user_contact_user', '{{%user_contact}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');     

为了简单起见,我现在将跳过会议模板架构。而且我还没有设计与收入相关的功能。这样做的主要原因是,我目前有很多工作要做,以运行核心功能集并完成本教程系列的前几集。然而,这是一个值得教育的时刻。这是一个很好的例子,说明企业家的资源有限,专注于核心功能,但没有“意识到”创收也是一个核心功能。因为我相信我最初可以在没有收入的情况下启动 Meeting Planner,所以这是我目前能够做出的妥协。

运行数据库迁移

既然您对我们的数据库架构和 Active Record 迁移有了更多的背景知识,那么让我们运行其余部分:

cd ~/Sites/mp
./yii migrate/up all

您应该看到类似这样的内容:

Yii Migration Tool (based on Yii v2.0.0)

Total 14 new migrations to be applied:
    m141025_212656_create_meeting_table
    m141025_213610_create_place_table
    m141025_213611_create_place_gps_table
    m141025_215701_create_participant_table
    m141025_215833_create_meeting_time_table
    m141025_220016_create_meeting_place_table
    m141025_220133_create_meeting_log_table
    m141025_220524_create_friend_table
    m141025_220923_create_user_place_table
    m141025_221627_create_meeting_note_table
    m141025_221902_create_user_contact_table
    m141025_222213_create_template_table
    m141025_222431_create_template_time_table
    m141025_222531_create_template_place_table

Apply the above migrations? (yes|no) [no]:yes
*** applying m141025_212656_create_meeting_table
    > create table {{%meeting}} ... done (time: 0.124s)
    > add foreign key fk_meeting_owner: {{%meeting}} (owner_id) references {{%user}} (id) ... done (time: 0.307s)
*** applied m141025_212656_create_meeting_table (time: 0.434s)

*** applying m141025_213610_create_place_table
    > create table {{%place}} ... done (time: 0.091s)
    > add foreign key fk_place_created_by: {{%place}} (created_by) references {{%user}} (id) ... done (time: 0.114s)
*** applied m141025_213610_create_place_table (time: 0.206s)

*** applying m141025_213611_create_place_gps_table
    > create table {{%place_gps}} ... done (time: 0.120s)
    > execute SQL: create spatial index place_gps_gps on {{%place_gps}}(gps); ... done (time: 0.114s)
    > add foreign key fk_place_gps: {{%place_gps}} (place_id) references {{%place}} (id) ... done (time: 0.112s)
*** applied m141025_213611_create_place_gps_table (time: 0.347s)

*** applying m141025_215701_create_participant_table
    > create table {{%participant}} ... done (time: 0.100s)
    > add foreign key fk_participant_meeting: {{%participant}} (meeting_id) references {{%meeting}} (id) ... done (time: 0.138s)
    > add foreign key fk_participant_participant: {{%participant}} (participant_id) references {{%user}} (id) ... done (time: 0.112s)
    > add foreign key fk_participant_invited_by: {{%participant}} (invited_by) references {{%user}} (id) ... done (time: 0.149s)
*** applied m141025_215701_create_participant_table (time: 0.500s)

*** applying m141025_215833_create_meeting_time_table
    > create table {{%meeting_time}} ... done (time: 0.142s)
    > add foreign key fk_meeting_time_meeting: {{%meeting_time}} (meeting_id) references {{%meeting}} (id) ... done (time: 0.148s)
    > add foreign key fk_participant_suggested_by: {{%meeting_time}} (suggested_by) references {{%user}} (id) ... done (time: 0.122s)
*** applied m141025_215833_create_meeting_time_table (time: 0.413s)

*** applying m141025_220016_create_meeting_place_table
    > create table {{%meeting_place}} ... done (time: 0.120s)
    > add foreign key fk_meeting_place_meeting: {{%meeting_place}} (meeting_id) references {{%meeting}} (id) ... done (time: 0.125s)
    > add foreign key fk_meeting_place_place: {{%meeting_place}} (place_id) references {{%place}} (id) ... done (time: 0.135s)
    > add foreign key fk_meeting_suggested_by: {{%meeting_place}} (suggested_by) references {{%user}} (id) ... done (time: 0.137s)
*** applied m141025_220016_create_meeting_place_table (time: 0.518s)

*** applying m141025_220133_create_meeting_log_table
    > create table {{%meeting_log}} ... done (time: 0.109s)
    > add foreign key fk_meeting_log_meeting: {{%meeting_log}} (meeting_id) references {{%meeting}} (id) ... done (time: 0.126s)
    > add foreign key fk_meeting_log_actor: {{%meeting_log}} (actor_id) references {{%user}} (id) ... done (time: 0.113s)
*** applied m141025_220133_create_meeting_log_table (time: 0.348s)

*** applying m141025_220524_create_friend_table
    > create table {{%friend}} ... done (time: 0.109s)
    > add foreign key fk_friend_user_id: {{%friend}} (user_id) references {{%user}} (id) ... done (time: 0.125s)
    > add foreign key fk_friend_friend_id: {{%friend}} (friend_id) references {{%user}} (id) ... done (time: 0.102s)
*** applied m141025_220524_create_friend_table (time: 0.337s)

*** applying m141025_220923_create_user_place_table
    > create table {{%user_place}} ... done (time: 0.109s)
    > add foreign key fk_user_place_user: {{%user_place}} (user_id) references {{%user}} (id) ... done (time: 0.137s)
    > add foreign key fk_user_place_place: {{%user_place}} (place_id) references {{%place}} (id) ... done (time: 0.114s)
*** applied m141025_220923_create_user_place_table (time: 0.360s)

*** applying m141025_221627_create_meeting_note_table
    > create table {{%meeting_note}} ... done (time: 0.109s)
    > add foreign key fk_meeting_note_meeting: {{%meeting_note}} (meeting_id) references {{%meeting}} (id) ... done (time: 0.125s)
    > add foreign key fk_meeting_note_posted_by: {{%meeting_note}} (posted_by) references {{%user}} (id) ... done (time: 0.101s)
*** applied m141025_221627_create_meeting_note_table (time: 0.337s)

*** applying m141025_221902_create_user_contact_table
    > create table {{%user_contact}} ... done (time: 0.098s)
    > add foreign key fk_user_contact_user: {{%user_contact}} (user_id) references {{%user}} (id) ... done (time: 0.125s)
*** applied m141025_221902_create_user_contact_table (time: 0.225s)

*** applying m141025_222213_create_template_table
    > create table {{%template}} ... done (time: 0.108s)
    > add foreign key fk_template_owner: {{%template}} (owner_id) references {{%user}} (id) ... done (time: 0.171s)
*** applied m141025_222213_create_template_table (time: 0.281s)

*** applying m141025_222431_create_template_time_table
    > create table {{%template_time}} ... done (time: 0.111s)
    > add foreign key fk_template_time_template: {{%template_time}} (template_id) references {{%template}} (id) ... done (time: 0.114s)
*** applied m141025_222431_create_template_time_table (time: 0.226s)

*** applying m141025_222531_create_template_place_table
    > create table {{%template_place}} ... done (time: 0.099s)
    > add foreign key fk_template_place_template: {{%template_place}} (template_id) references {{%template}} (id) ... done (time: 0.103s)
    > add foreign key fk_template_place_place: {{%template_place}} (place_id) references {{%place}} (id) ... done (time: 0.101s)
*** applied m141025_222531_create_template_place_table (time: 0.304s)

Migrated up successfully.

同样,当我们在生产中安装 Meeting Planner 时,我们也将使用迁移来构建初始数据库。无需导出和导入 SQL 文件,这些文件可能会因我们跨环境使用的版本不同而损坏。

注册管理用户

在我们继续之前,您需要将自己注册为管理用户。单击工具栏中的注册链接,只需注册该应用程序即可。

使用 PHP 设计初创公司的数据库并概述功能需求

如果成功,当您返回主页时,您将看到工具栏指示您的登录状态.

使用 PHP 设计初创公司的数据库并概述功能需求

这些表单和应用逻辑都包含在 Yii 的高级应用模板中。

使用 Yii 的 Gii 构建脚手架

现在我们可以构建脚手架来支持常见的创建、读取、更新和删除操作 (CRUD) 的模型视图控制器代码。

我们将使用 Gii(Yii 令人惊叹的自动代码生成器)来构建许多基本框架代码。这个名字可能很愚蠢,但它非常强大并且是 Yii 开发的核​​心。我们将从会议和地点开始。

使用 Gii

将浏览器指向 http://localhost:8888/mp/gii。你应该看到这个:

使用 PHP 设计初创公司的数据库并概述功能需求

生成模型

使用 Gii 构建时,通常从每个表的模型生成器开始。在使用模型生成器之前,您必须先运行迁移以在数据库中创建表,就像我们上面所做的那样。 Gii 使用 SQL 表定义为您的模型生成代码。

使用 PHP 设计初创公司的数据库并概述功能需求

让我们使用模型生成器为会议桌生成模型代码。代码已在您的 Github 存储库中生成,但您可以随意再次运行这些练习。 Gii 将为您预览并可选择覆盖代码。

按如下所示为会议模型填写模型生成器:

使用 PHP 设计初创公司的数据库并概述功能需求

然后,生成 Place 模型:

使用 PHP 设计初创公司的数据库并概述功能需求

Gii 非常令人惊奇——基于我们的表定义,它生成了大量的逻辑。

/mp/frontend/models/Meeting.php 模型中,您将看到自动生成的属性标签:

    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'owner_id' => 'Owner ID',
            'meeting_type' => 'Meeting Type',
            'message' => 'Message',
            'status' => 'Status',
            'created_at' => 'Created At',
            'updated_at' => 'Updated At',
        ];
    }

它为表单生成字段验证规则:

    public function rules()
    {
        return [
            [['owner_id', 'message', 'created_at', 'updated_at'], 'required'],
            [['owner_id', 'meeting_type', 'status', 'created_at', 'updated_at'], 'integer'],
            [['message'], 'string']
        ];
    }

它会生成数据库关系 - 以下是一些示例:

/* @property User $owner
 * @property MeetingLog[] $meetingLogs
 * @property MeetingNote[] $meetingNotes
 * @property MeetingPlace[] $meetingPlaces
 * @property MeetingTime[] $meetingTimes
 * @property Participant[] $participants
*/
/**
     * @return \yii\db\ActiveQuery
     */
    public function getMeetingLogs()
    {
        return $this->hasMany(MeetingLog::className(), ['meeting_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getMeetingNotes()
    {
        return $this->hasMany(MeetingNote::className(), ['meeting_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getMeetingPlaces()
    {
        return $this->hasMany(MeetingPlace::className(), ['meeting_id' => 'id']);
    }

生成CRUD

现在,我们可以使用 CRUD 生成器来构建用于创建、读取、更新和删除操作的代码。

访问 CRUD 生成器并为会议创建它。请注意,前端是用户将看到的 Yii 应用程序。

使用 PHP 设计初创公司的数据库并概述功能需求

当您点击预览时,您应该会看到如下内容:

使用 PHP 设计初创公司的数据库并概述功能需求

当您点击生成时,您应该会看到以下结果:

使用 PHP 设计初创公司的数据库并概述功能需求

接下来,对地点重复上述过程。

現在,您實際上可以瀏覽我們網站上的會議和地點,以查看實際產生的程式碼。將瀏覽器指向 http://localhost:8888/mp/meeting。它應該看起來像這樣:

使用 PHP 设计初创公司的数据库并概述功能需求

如果您註冊了帳戶,則應該能夠建立會議。請注意,Gii 不知道我們的程式碼應管理的欄位和使用者要提供的欄位之間的差異。我們將在接下來的教程中清理這些內容。目前,您需要為owner_id 輸入整數(使用1 - 這是第一個登入的使用者)、meeting_typestatuscreated_atupdated_at:

使用 PHP 设计初创公司的数据库并概述功能需求

建立幾次會議後,會議索引頁面將如下所示:

p>

使用 PHP 设计初创公司的数据库并概述功能需求

#結合 Gii 和 Yii 的強大功能,可以比其他方式更快地建立 Web 應用程式。令人驚訝的是,只需一個資料庫表格結構和一段遷移程式碼,我們就可以輕鬆使用 Bootstrap 響應式建構的工作控制器和表單。

下一步是什麼?

我希望您對資料庫和 Gii 演練感興趣。本系列的下一篇文章將重點放在圍繞地點建立功能。它將介紹如何使用 Google 地方資訊、Google 地圖和 HTML5 地理定位來建立 Meeting Planner 所需的功能。如果您想先了解這些主題,我寫了一個相關教學:如何使用 Zillow Neighborhood Maps 和 HTML5 Geolocation。

請隨時在下面添加您的問題和評論;我通常會參與討論。您也可以透過 Twitter @reifman 聯繫我或直接給我發送電子郵件。

相關連結

  • 使用 Yii2 程式設計:入門
  • Yii 框架簡介

以上是使用 PHP 設計新創公司的資料庫並概述功能需求的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
簡單地說明PHP會話的概念。簡單地說明PHP會話的概念。Apr 26, 2025 am 12:09 AM

phpsessionstrackuserdataacrossmultiplepagerequestsusingauniqueIdStoredInAcookie.here'showtomanageThemeffectionaly:1)startAsessionWithSessionWwithSession_start()和stordoredAtain $ _session.2)

您如何循環中存儲在PHP會話中的所有值?您如何循環中存儲在PHP會話中的所有值?Apr 26, 2025 am 12:06 AM

在PHP中,遍歷會話數據可以通過以下步驟實現:1.使用session_start()啟動會話。 2.通過foreach循環遍歷$_SESSION數組中的所有鍵值對。 3.處理複雜數據結構時,使用is_array()或is_object()函數,並用print_r()輸出詳細信息。 4.優化遍歷時,可採用分頁處理,避免一次性處理大量數據。這將幫助你在實際項目中更有效地管理和使用PHP會話數據。

說明如何使用會話進行用戶身份驗證。說明如何使用會話進行用戶身份驗證。Apr 26, 2025 am 12:04 AM

會話通過服務器端的狀態管理機制實現用戶認證。 1)會話創建並生成唯一ID,2)ID通過cookies傳遞,3)服務器存儲並通過ID訪問會話數據,4)實現用戶認證和狀態管理,提升應用安全性和用戶體驗。

舉一個如何在PHP會話中存儲用戶名的示例。舉一個如何在PHP會話中存儲用戶名的示例。Apr 26, 2025 am 12:03 AM

Tostoreauser'snameinaPHPsession,startthesessionwithsession_start(),thenassignthenameto$_SESSION['username'].1)Usesession_start()toinitializethesession.2)Assigntheuser'snameto$_SESSION['username'].Thisallowsyoutoaccessthenameacrossmultiplepages,enhanc

哪些常見問題會導致PHP會話失敗?哪些常見問題會導致PHP會話失敗?Apr 25, 2025 am 12:16 AM

PHPSession失效的原因包括配置錯誤、Cookie問題和Session過期。 1.配置錯誤:檢查並設置正確的session.save_path。 2.Cookie問題:確保Cookie設置正確。 3.Session過期:調整session.gc_maxlifetime值以延長會話時間。

您如何在PHP中調試與會話相關的問題?您如何在PHP中調試與會話相關的問題?Apr 25, 2025 am 12:12 AM

在PHP中調試會話問題的方法包括:1.檢查會話是否正確啟動;2.驗證會話ID的傳遞;3.檢查會話數據的存儲和讀取;4.查看服務器配置。通過輸出會話ID和數據、查看會話文件內容等方法,可以有效診斷和解決會話相關的問題。

如果session_start()被多次調用會發生什麼?如果session_start()被多次調用會發生什麼?Apr 25, 2025 am 12:06 AM

多次調用session_start()會導致警告信息和可能的數據覆蓋。 1)PHP會發出警告,提示session已啟動。 2)可能導致session數據意外覆蓋。 3)使用session_status()檢查session狀態,避免重複調用。

您如何在PHP中配置會話壽命?您如何在PHP中配置會話壽命?Apr 25, 2025 am 12:05 AM

在PHP中配置會話生命週期可以通過設置session.gc_maxlifetime和session.cookie_lifetime來實現。 1)session.gc_maxlifetime控制服務器端會話數據的存活時間,2)session.cookie_lifetime控制客戶端cookie的生命週期,設置為0時cookie在瀏覽器關閉時過期。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器