* code for product create page.

This commit is contained in:
wangyidong
2023-04-28 08:23:49 +08:00
parent 1776e5c681
commit 89f5120652
9 changed files with 392 additions and 139 deletions
+5 -20
View File
@@ -394,8 +394,8 @@ class product extends control
}
/**
* 创建产品。可以是顶级产品,也可以是项目集下的产品。
* Create a product.
* 创建产品。可以是顶级产品,也可以是项目集下的产品。
*
* @param int $programID
* @param string $extra
@@ -410,26 +410,11 @@ class product extends control
{
$data = form::data($this->config->product->form->create);
$data = $this->productZen->prepareCreateExtras($data);
if(!$data) return $this->productZen->errorBeforeEdit();
if(!$data) return $this->productZen->sendError4Create();
$result = $this->product->create($data);
if(!$result) return $this->productZen->errorAfterEdit();
return $this->productZen->responseAfterEdit($result);
$productID = $this->product->create();
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->loadModel('action')->create('product', $productID, 'opened');
$message = $this->executeHooks($productID);
if($message) $this->lang->saveSuccess = $message;
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $productID));
$tab = $this->app->tab;
$moduleName = $tab == 'program'? 'program' : $this->moduleName;
$methodName = $tab == 'program'? 'product' : 'browse';
$param = $tab == 'program' ? "programID=$programID" : "productID=$productID";
$locate = isonlybody() ? 'parent' : $this->createLink($moduleName, $methodName, $param);
if($tab == 'doc') $locate = $this->createLink('doc', 'productSpace', "objectID=$productID");
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locate));
$productID = $this->product->create($data);
if(!$productID) return $this->productZen->sendError4Create();
return $this->productZen->responseAfterCreate($productID, $data);
}
$this->productZen->setMenu4Create($programID);
+73 -88
View File
@@ -678,103 +678,22 @@ class productModel extends model
/**
* Create a product.
* 直接用对象数据创建产品
*
* @param object $product
* @access public
* @return int
* @return int|false
*/
public function create()
public function create(object $product): int|false
{
$product = fixer::input('post')
->callFunc('name', 'trim')
->setDefault('status', 'normal')
->setDefault('line', 0)
->setDefault('createdBy', $this->app->user->account)
->setDefault('createdDate', helper::now())
->setDefault('createdVersion', $this->config->version)
->setIF($this->post->acl == 'open', 'whitelist', '')
->setIF(!isset($_POST['whitelist']), 'whitelist', '')
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
->join('whitelist', ',')
->join('reviewer', ',')
->remove('uid,newLine,lineName,contactListMenu')
->get();
$this->lang->error->unique = $this->lang->error->repeat;
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
/* Lean mode relation defaultProgram. */
$programID = isset($product->program) ? $product->program : 0;
if($this->config->systemMode == 'light')
{
$programID = $this->config->global->defaultProgram;
$product->program = $this->config->global->defaultProgram;
}
$this->dao->insert(TABLE_PRODUCT)->data($product)->autoCheck()
->batchCheck($this->config->product->create->requiredFields, 'notempty')
->checkIF(!empty($product->name), 'name', 'unique', "`program` = $programID and `deleted` = '0'")
->checkIF(!empty($product->name), 'name', 'unique', "`program` = {$product->program} and `deleted` = '0'")
->checkIF(!empty($product->code), 'code', 'unique', "`deleted` = '0'")
->checkFlow()
->exec();
if(!dao::isError())
{
$productID = $this->dao->lastInsertID();
if(!empty($_POST['lineName']))
{
/* Create product line. */
$maxOrder = $this->dao->select("max(`order`) as maxOrder")->from(TABLE_MODULE)->where('type')->eq('line')->fetch('maxOrder');
$maxOrder = $maxOrder ? $maxOrder + 10 : 0;
$line = new stdClass();
$line->type = 'line';
$line->parent = 0;
$line->grade = 1;
$line->name = $this->post->lineName;
$line->root = $this->config->systemMode == 'ALM' ? $product->program : 0;
$line->order = $maxOrder;
$lines = $this->dao->select('name')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq($line->root)->andWhere('name')->eq($line->name)->fetch();
if(!empty($lines))
{
dao::$errors['lineName'] = sprintf($this->lang->product->nameIsDuplicated, $line->name);
return false;
}
$this->dao->insert(TABLE_MODULE)->data($line)->exec();
if(!dao::isError())
{
$lineID = $this->dao->lastInsertID();
$path = ",$lineID,";
$this->dao->update(TABLE_MODULE)->set('path')->eq($path)->where('id')->eq($lineID)->exec();
$this->dao->update(TABLE_PRODUCT)->set('line')->eq($lineID)->where('id')->eq($productID)->exec();
}
}
$this->file->updateObjectID($this->post->uid, $productID, 'product');
$this->dao->update(TABLE_PRODUCT)->set('`order`')->eq($productID * 5)->where('id')->eq($productID)->exec();
$whitelist = explode(',', $product->whitelist);
$this->loadModel('personnel')->updateWhitelist($whitelist, 'product', $productID);
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
/* Create doc lib. */
$this->app->loadLang('doc');
$lib = new stdclass();
$lib->product = $productID;
$lib->name = $this->lang->doclib->main['product'];
$lib->type = 'product';
$lib->main = '1';
$lib->acl = 'default';
$lib->addedBy = $this->app->user->account;
$lib->addedDate = helper::now();
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
return $productID;
}
if(dao::isError()) return false;
return $this->dao->lastInsertID();
}
/**
@@ -1025,6 +944,72 @@ class productModel extends model
}
}
/**
* Create product line.
* 创建产品线。
*
* @param int programID
* @access public
* @return int|false
*/
public function createLine(int $programID): int|false
{
if($programID <= 0) return false;
if(empty($_POST['lineName'])) return false;
$line = new stdClass();
$line->type = 'line';
$line->parent = 0;
$line->grade = 1;
$line->name = htmlSpecialString($this->post->lineName);
$line->root = $programID;
$existedLineID = $this->dao->select('id')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq($line->root)->andWhere('name')->eq($line->name)->fetch('id');
if($existedLineID) return $existedLineID;
$this->dao->insert(TABLE_MODULE)->data($line)->exec();
if(dao::isError()) return false;
$lineID = $this->dao->lastInsertID();
$path = ",$lineID,";
$this->dao->update(TABLE_MODULE)->set('path')->eq($path)->set('`order`')->eq($lineID)->where('id')->eq($lineID)->exec();
return $lineID;
}
/**
* Create main lib for product
* 关联创建产品主库
*
* @param int productID
* @access public
* @return int|false
*/
public function createMainLib(int $productID): int|false
{
if($productID <= 0) return false;
$existedLibID = $this->dao->select('id')->from(TABLE_DOCLIB)->where('product')->eq($productID)
->andWhere('type')->eq('product')
->andWhere('main')->eq('1')
->fetch('id');
if($existedLibID) return $existedLibID;
$this->app->loadLang('doc');
$lib = new stdclass();
$lib->product = $productID;
$lib->name = $this->lang->doclib->main['product'];
$lib->type = 'product';
$lib->main = '1';
$lib->acl = 'default';
$lib->addedBy = $this->app->user->account;
$lib->addedDate = helper::now();
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
if(dao::isError())return false;
return $this->dao->lastInsertID();
}
/**
* Get stories.
*
-1
View File
@@ -235,5 +235,4 @@ class productTao extends productModel
return $closedBugs;
}
}
@@ -47,7 +47,3 @@ $stories2 = array($story4, $story5, $story6);
$stories3 = array($story7, $story8, $story9);
$product = new productTest('admin');
r($product->batchGetStoryStageTest($stories1)) && p('1;2;3') && e('wait;planned;projected'); // 测试获取需求1 2 3的阶段
r($product->batchGetStoryStageTest($stories2)) && p('4;5;6') && e('developing;developed;testing'); // 测试获取需求4 5 6的阶段
r($product->batchGetStoryStageTest($stories3)) && p('7;8;9') && e('tested;verified;released'); // 测试获取需求7 8 9的阶段
+11 -16
View File
@@ -4,6 +4,7 @@ include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/product.class.php';
#su('admin');
zdTable('product')->gen(0);
/**
@@ -24,20 +25,14 @@ pid=1
$product = new productTest('admin');
$t_create = array('name' => 'case1', 'code' => 'testcase1');
$t_noid = array('name' => 'case2');
$t_repeat = array('name' => 'case1', 'code' => 'testcase1');
$t_noname = array('code' => 'testcase1');
$t_namecode = array('name' => 'case3', 'code' => 'testcase3');
$t_pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
$t_intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
$t_noacl = array('name' => 'case12', 'code' => 'testcase1', 'acl' => '');
$create = array('name' => 'case1', 'code' => 'testcase1');
$repeat = array('name' => 'case1', 'code' => 'testcase1');
$namecode = array('name' => 'case3', 'code' => 'testcase3');
$pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
$intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
r($product->createObject($t_create)) && p('name') && e('case1'); // 测试正常的创建
r($product->createObject($t_noid)) && p('code:0') && e('『产品代号』不能为空。'); // 测试不填产品代号的情况
r($product->createObject($t_repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品
r($product->createObject($t_noname)) && p('name:0') && e('『产品名称』不能为空。'); // 测试不填产品名称的情况
r($product->createObject($t_namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
r($product->createObject($t_pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
r($product->createObject($t_intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
r($product->createObject($t_noacl)) && p('acl:0') && e('『访问控制』不符合格式,应当为:『/open|private|custom/』。'); // 测试不填权限控制的情况
r($product->createObject($create)) && p('name') && e('case1'); // 测试正常的创建
r($product->createObject($repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品
r($product->createObject($namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
r($product->createObject($pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
r($product->createObject($intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/product.class.php';
zdTable('module')->gen(0);
/**
title=productModel->createLine();
cid=1
pid=1
*/
$product = new productTest('admin');
r($product->createLineTest('1', 'test line1')) && p('root,name') && e('1,test line1');
r($product->createLineTest('0', 'test line1')) && p() && e('0');
r($product->createLineTest('1', '')) && p() && e('0');
r($product->createLineTest('1', "<script>alert('test')</script>")) && p('root,name') && e('1,&lt;script&gt;alert(&#039;test&#039;)&lt;/script&gt;');
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/product.class.php';
zdTable('doclib')->gen(0);
/**
title=productModel->createmainlib();
cid=1
pid=1
*/
$product = new productTest('admin');
r($product->createMainLibTest('-1')) && p() && e('0');
r($product->createMainLibTest('0')) && p() && e('0');
r($product->createMainLibTest('1')) && p('product,name,type,main') && e('1,产品主库,product,1');
+69 -10
View File
@@ -22,19 +22,28 @@ class productTest
*
* @param array $param
* @access public
* @return object
* @return object|array
*/
public function createObject($param = array()): object
public function createObject(array $param = array()): object|array
{
global $createFields;
$whitelist = array();
$createFields = array('program' => 1, 'line' => 0, 'lineName' => '', 'newLine' => 0, 'name' => '', 'code' => '', 'PO' => 'admin', 'QD' => '', 'RD' => '',
'reviewer' => '', 'type' => 'normal', 'status' => 'normal', 'desc' => '', 'acl' => 'open', 'uid' => '');
foreach($createFields as $field => $defaultValue) $_POST[$field] = $defaultValue;
foreach($param as $key => $value) $_POST[$key] = $value;
$createFields = array();
$createFields['program'] = 1;
$createFields['line'] = 0;
$createFields['name'] = '';
$createFields['code'] = '';
$createFields['PO'] = 'admin';
$createFields['QD'] = '';
$createFields['RD'] = '';
$createFields['reviewer'] = '';
$createFields['type'] = 'normal';
$createFields['status'] = 'normal';
$createFields['desc'] = '';
$createFields['acl'] = 'open';
$objectID = $this->objectModel->create();
unset($_POST);
$data = new stdclass();
foreach($createFields as $field => $defaultValue) $data->$field = zget($param, $field, $defaultValue);
$objectID = $this->objectModel->create($data);
if(dao::isError())
{
@@ -1113,4 +1122,54 @@ class productTest
return $object;
}
}
/**
* 测试创建产品线
* Test for create line.
*
* @param int programID
* @param string lineName
* @access public
* @return object|array
*/
public function createLineTest(int $programID, string $lineName): object|array
{
$_POST['lineName'] = $lineName;
$lineID = $this->objectModel->createLine($programID);
if(dao::isError())
{
return dao::getError();
}
else
{
if(!$lineID) return array();
$object = $this->objectModel->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($lineID)->fetch();
return $object;
}
}
/**
* 测试创建产品主库
* Test for create main lib.
*
* @param int productID
* @access public
* @return object|array
*/
public function createMainLibTest(int $productID): object|array
{
$libID = $this->objectModel->createMainLib($productID);
if(dao::isError())
{
return dao::getError();
}
else
{
if(!$libID) return array();
$object = $this->objectModel->dao->select('*')->from(TABLE_DOCLIB)->where('id')->eq($libID)->fetch();
return $object;
}
}
}
+193
View File
@@ -32,6 +32,84 @@ class productZen extends product
}
}
/**
* Set menu for create product page.
* 为创建产品设置导航数据,主要是替换占位符。
*
* @param int $programID
* @access protected
* @return void
*/
protected function setMenu4Create(int $program): void
{
if($this->app->tab == 'program') $this->loadModel('program')->setMenu($programID);
if($this->app->tab == 'doc') unset($this->lang->doc->menu->product['subMenu']);
if($this->app->getViewType() != 'mhtml') return;
if($this->app->rawModule == 'projectstory' and $this->app->rawMethod == 'story')
{
$this->loadModel('project')->setMenu();
return;
}
$this->product->setMenu();
}
/**
* Get goback link for create by extra.
* 通过extra获取返回链接。
*
* @param string $extra
* @access private
* @return string
*/
private function getBackLink4Create(string $extra): string
{
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
parse_str($extra, $output);
$backLink = '';
$from = zget($output, 'from', '');
if($from == 'qa') $backLink = $this->createLink('qa', 'index');
if($from == 'global') $backLink = $this->createLink('product', 'all');
return $backLink;
}
/**
* Get form fields for create.
* 获取创建产品页面的表单配置。
*
* @param int $programID
* @access private
* @return array
*/
private function getFormFields4Create(int $programID = 0): array
{
$fields = $this->config->product->form->create;
$this->loadModel('user');
$poUsers = $this->user->getPairs('nodeleted|pofirst|noclosed');
$qdUsers = $this->user->getPairs('nodeleted|qdfirst|noclosed');
$rdUsers = $this->user->getPairs('nodeleted|devfirst|noclosed');
$users = $this->user->getPairs('nodeleted|noclosed');
foreach($fields as $field => $attr)
{
if(isset($attr['options']) and $attr['options'] == 'users') $fields[$field]['options'] = $users;
$fields[$field]['name'] = $field;
$fields[$field]['title'] = $this->lang->product->$field;
}
$fields['program']['options'] = array('') + $this->loadModel('program')->getTopPairs('', 'noclosed');
$fields['PO']['options'] = $poUsers;
$fields['QD']['options'] = $qdUsers;
$fields['RD']['options'] = $rdUsers;
if($programID) $fields['line']['options'] = array('') + $this->product->getLinePairs($programID);
if(empty($programID) or $this->config->systemMode != 'ALM') unset($fields['line']);
return $fields;
}
/**
* Get product lines and product lines of program.
*
@@ -54,4 +132,119 @@ class productZen extends product
return array($productLines, $programLines);
}
/**
* Build form fields for create.
* 构建创建产品页面数据。
*
* @param int $programID
* @param string $extra
* @access protected
* @return void
*/
protected function buildCreateForm(int $programID = 0, string $extra = ''): void
{
$this->view->title = $this->lang->product->create;
$this->view->gobackLink = $this->getBackLink4Create($extra);
$this->view->programID = $programID;
$this->view->fields = $this->getFormFields4Create($programID);
unset($this->lang->product->typeList['']);
$this->display();
}
/**
* Prepare data for create.
* 追加创建信息,处理白名单、评审者、项目集字段,还有富文本内容处理。
*
* @param int $programID
* @param string $extra
* @access protected
* @return object
*/
protected function prepareCreateExtras(object $data): object
{
$product = $data->setDefault('createdBy', $this->app->user->account)
->setDefault('createdDate', helper::now())
->setDefault('createdVersion', $this->config->version)
->setIF($this->config->systemMode == 'light', 'program', (int)zget($this->config->global, 'defaultProgram', 0))
->setIF($this->post->acl == 'open', 'whitelist', '')
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
->join('whitelist', ',')
->join('reviewer', ',')
->remove('uid,newLine,lineName,contactListMenu')
->get();
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
return $product;
}
/**
* Process after create product.
* 成功插入产品数据后,其他的额外操作。
*
* @param int $productID
* @param object $product
* @access protected
* @return void
*/
protected function responseAfterCreate(int $productID, object $product): void
{
$fixData = new stdclass();
$fixData->order = $productID * 5;
if(!empty($_POST['lineName']))
{
$lineID = $this->product->createLine((int)$product->program);
if($lineID) $fixData->line = $lineID;
}
$this->dao->update(TABLE_PRODUCT)->data($fixData)->where('id')->eq($productID)->exec();
$this->file->updateObjectID($this->post->uid, $productID, 'product');
$this->loadModel('personnel')->updateWhitelist(explode(',', $product->whitelist), 'product', $productID);
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
$this->product->createMainLib($productID);
$this->loadModel('action')->create('product', $productID, 'opened');
$message = $this->executeHooks($productID);
if($message) $this->lang->saveSuccess = $message;
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $productID));
$this->sendCreateLocate($productID, (int)$product->program);
}
/**
* Locate after create product.
* 创建完成后,做页面跳转。
*
* @param int $productID
* @param int $programID
* @access private
* @return void
*/
private function sendCreateLocate(int $productID, int $programID): void
{
$tab = $this->app->tab;
$moduleName = $tab == 'program'? 'program' : $this->moduleName;
$methodName = $tab == 'program'? 'product' : 'browse';
$param = $tab == 'program' ? "programID=$programID" : "productID=$productID";
$locate = isonlybody() ? 'true' : $this->createLink($moduleName, $methodName, $param);
if($tab == 'doc') $locate = $this->createLink('doc', 'productSpace', "objectID=$productID");
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $locate));
}
/**
* Send error for create.
* 输出创建产品产生的错误。
*
* @access protected
* @return void
*/
protected function sendError4Create(): void
{
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
}
}