* Code for task #41775.
This commit is contained in:
@@ -67,6 +67,12 @@ class program extends control
|
||||
$this->display();
|
||||
}
|
||||
|
||||
public function kanban()
|
||||
{
|
||||
$this->view->kanbanGroup = $this->program->getKanbanGroup();
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Program products list.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
.main-table .table {cursor: default;}
|
||||
.main-table .table td {background: #f5f5f5;}
|
||||
|
||||
.board-item {border: 1px solid #EBEBEB; padding: 5px 10px; cursor: default; border-radius: 2px; background-color: #fff;}
|
||||
.board-item:hover {border-color: #ccc;}
|
||||
.board-item + .board-item {margin-top: 10px;}
|
||||
|
||||
#kanban {overflow-y: auto;}
|
||||
#kanban tbody > tr > td {line-height: 24px;}
|
||||
#kanban tbody > tr > td{border-right: 3px solid #fff; border-bottom: 3px solid #fff;}
|
||||
#kanban thead > tr:first-child > th:not(:first-child) {border-right: 3px solid #fff; border-bottom: 3px solid #fff;}
|
||||
#kanban thead > tr:last-child > th {border: 3px solid #fff;}
|
||||
|
||||
.table-grouped tbody > tr > td:first-child, .table-grouped thead > tr > th:first-child {padding-left: 3px;}
|
||||
@@ -62,6 +62,9 @@ $lang->program->readjustTime = 'Change the program begin&end date.';
|
||||
$lang->program->stakeholderTypeList['inside'] = 'Inside';
|
||||
$lang->program->stakeholderTypeList['outside'] = 'Outside';
|
||||
|
||||
$lang->program->typeList['my'] = 'My Programs';
|
||||
$lang->program->typeList['others'] = 'Others';
|
||||
|
||||
$lang->program->noProgram = 'No program.';
|
||||
$lang->program->showClosed = 'Closed programs.';
|
||||
$lang->program->tips = 'If a parent item set is selected, products under that parent item set can be associated. If no item set is selected, a product with the same name as the item is created by default and associated with that item.';
|
||||
|
||||
@@ -74,6 +74,9 @@ $lang->program->isStakeholderKey = 'Key stakeholder';
|
||||
$lang->program->stakeholderTypeList['inside'] = 'Inside';
|
||||
$lang->program->stakeholderTypeList['outside'] = 'Outside';
|
||||
|
||||
$lang->program->typeList['my'] = 'My Programs';
|
||||
$lang->program->typeList['others'] = 'Others';
|
||||
|
||||
$lang->program->noProgram = 'No program.';
|
||||
$lang->program->showClosed = 'Closed programs.';
|
||||
$lang->program->tips = 'If a parent item set is selected, products under that parent item set can be associated. If no item set is selected, a product with the same name as the item is created by default and associated with that item.';
|
||||
|
||||
@@ -62,6 +62,9 @@ $lang->program->readjustTime = 'Change the program begin&end date.';
|
||||
$lang->program->stakeholderTypeList['inside'] = 'Inside';
|
||||
$lang->program->stakeholderTypeList['outside'] = 'Outside';
|
||||
|
||||
$lang->program->typeList['my'] = 'My Programs';
|
||||
$lang->program->typeList['others'] = 'Others';
|
||||
|
||||
$lang->program->noProgram = 'No program.';
|
||||
$lang->program->showClosed = 'Closed programs.';
|
||||
$lang->program->tips = 'If a parent item set is selected, products under that parent item set can be associated. If no item set is selected, a product with the same name as the item is created by default and associated with that item.';
|
||||
|
||||
@@ -62,6 +62,9 @@ $lang->program->readjustTime = 'Change the program begin&end date.';
|
||||
$lang->program->stakeholderTypeList['inside'] = 'Inside';
|
||||
$lang->program->stakeholderTypeList['outside'] = 'Outside';
|
||||
|
||||
$lang->program->typeList['my'] = 'My Programs';
|
||||
$lang->program->typeList['others'] = 'Others';
|
||||
|
||||
$lang->program->noProgram = 'No program.';
|
||||
$lang->program->showClosed = 'Closed programs.';
|
||||
$lang->program->tips = 'If a parent item set is selected, products under that parent item set can be associated. If no item set is selected, a product with the same name as the item is created by default and associated with that item.';
|
||||
|
||||
@@ -115,3 +115,16 @@ $lang->program->statusList['suspended'] = '已挂起';
|
||||
$lang->program->statusList['closed'] = '已关闭';
|
||||
|
||||
$lang->program->featureBar['all'] = '所有';
|
||||
|
||||
$lang->program->kanban = new stdclass();
|
||||
$lang->program->kanban->typeList['my'] = '我参与的项目集';
|
||||
$lang->program->kanban->typeList['others'] = '其他项目集';
|
||||
|
||||
$lang->program->kanban->activeProducts = '未关闭的产品';
|
||||
$lang->program->kanban->activePlans = '未过期的计划';
|
||||
$lang->program->kanban->waitProjects = '未开始的项目';
|
||||
$lang->program->kanban->doingProjects = '进行中的项目';
|
||||
$lang->program->kanban->doingExecutions = '进行中的执行';
|
||||
$lang->program->kanban->normalReleases = '正常的发布';
|
||||
|
||||
$lang->program->kanban->laneColorList = array('#32C5FF', '#006AF1', '#9D28B2', '#FF8F26', '#FFC20E', '#00A78E', '#7FBB00', '#424BAC', '#C0E9FF', '#EC2761');
|
||||
|
||||
+266
-2
@@ -96,7 +96,7 @@ class programModel extends model
|
||||
*/
|
||||
public function getByID($programID = 0)
|
||||
{
|
||||
$program = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($programID)->andWhere('`type`')->eq('program')->fetch();
|
||||
$program = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($programID)->fetch();
|
||||
$program = $this->loadModel('file')->replaceImgURL($program, 'desc');
|
||||
return $program;
|
||||
}
|
||||
@@ -143,7 +143,271 @@ class programModel extends model
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get kanban group data.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getKanbanGroup()
|
||||
{
|
||||
$kanbanGroup = array();
|
||||
$kanbanGroup['my'] = array();
|
||||
$kanbanGroup['others'] = array();
|
||||
|
||||
/* Get all prived programs. */
|
||||
$programs = $this->dao->select('id, name')->from(TABLE_PROGRAM)
|
||||
->where('type')->eq('program')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('grade')->eq(1)
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->programs)->fi()
|
||||
->andWhere('status')->ne('closed')
|
||||
->fetchAll('id');
|
||||
|
||||
$involvedPrograms = $this->getInvolvedPrograms($this->app->user->account);
|
||||
|
||||
/* Get all products under programs. */
|
||||
$productGroup = $this->dao->select('id, program, name')->from(TABLE_PRODUCT)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('program')->in(array_keys($programs))
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->products)->fi()
|
||||
->andWhere('status')->ne('closed')
|
||||
->fetchGroup('program', 'id');
|
||||
|
||||
$productPairs = array();
|
||||
foreach($productGroup as $programID => $products)
|
||||
{
|
||||
foreach($products as $productID => $product) $productPairs[$productID] = $productID;
|
||||
}
|
||||
|
||||
/* Get all plans under products. */
|
||||
$plans = $this->dao->select('id, product, title')->from(TABLE_PRODUCTPLAN)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('product')->in($productPairs)
|
||||
->andWhere('end')->gt(helper::today())
|
||||
->fetchGroup('product');
|
||||
|
||||
/* Get all products linked projects and executions. */
|
||||
$projectGroup = $this->dao->select('t1.product, t2.id, t2.name, t2.status')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')
|
||||
->on('t1.project = t2.id')
|
||||
->where('t2.deleted')->eq(0)
|
||||
->andWhere('t1.product')->in($productPairs)
|
||||
->andWhere('t2.status')->ne('closed')
|
||||
->andWhere('t2.type')->eq('project')
|
||||
->fetchGroup('product');
|
||||
|
||||
$projectPairs = array();
|
||||
foreach($projectGroup as $projects)
|
||||
{
|
||||
foreach($projects as $project) $projectPairs[$project->id] = $project->id;
|
||||
}
|
||||
|
||||
$tasks = $this->dao->select('id, project, estimate, consumed, `left`, status, closedReason, execution')
|
||||
->from(TABLE_TASK)
|
||||
->where('project')->in($projectPairs)
|
||||
->andWhere('parent')->lt(1)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchGroup('project', 'id');
|
||||
|
||||
$projectHours = $this->computeProgress($tasks);
|
||||
|
||||
$releases = $this->dao->select('product, id, name')->from(TABLE_RELEASE)
|
||||
->where('product')->in($productPairs)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('status')->eq('normal')
|
||||
->fetchGroup('product');
|
||||
|
||||
$doingExecutions = $this->dao->select('id, project, name')->from(TABLE_EXECUTION)
|
||||
->where('type')->in('sprint,stage')
|
||||
->andWhere('status')->eq('doing')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('id_asc')
|
||||
->fetchAll('project');
|
||||
|
||||
$executionPairs = array();
|
||||
foreach($doingExecutions as $execution) $executionPairs[$execution->id] = $execution->id;
|
||||
|
||||
$tasks = $this->dao->select('id, project, estimate, consumed, `left`, status, closedReason, execution')
|
||||
->from(TABLE_TASK)
|
||||
->where('execution')->in($executionPairs)
|
||||
->andWhere('parent')->lt(1)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchGroup('execution', 'id');
|
||||
|
||||
$executionHours = $this->computeProgress($tasks);
|
||||
|
||||
foreach($productGroup as $programID => $products)
|
||||
{
|
||||
foreach($products as $productID => $product)
|
||||
{
|
||||
$product->plans = zget($plans, $productID, array());
|
||||
$product->releases = zget($releases, $productID, array());
|
||||
$projects = zget($projectGroup, $productID, array());
|
||||
foreach($projects as $project)
|
||||
{
|
||||
$status = $project->status == 'wait' ? 'wait' : 'doing';
|
||||
$execution = zget($doingExecutions, $project->id, array());
|
||||
if(!empty($execution)) $execution->hours = zget($executionHours, $execution->id, array());
|
||||
|
||||
$project->execution = $execution;
|
||||
$project->hours = zget($projectHours, $project->id, array());
|
||||
$product->projects[$status][] = $project;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//区分出其他项目集
|
||||
foreach($programs as $programID => $program)
|
||||
{
|
||||
$program->products = zget($productGroup, $programID, array());
|
||||
|
||||
if(in_array($programID, $involvedPrograms))
|
||||
{
|
||||
$kanbanGroup['my'][$programID] = $program;
|
||||
}
|
||||
else
|
||||
{
|
||||
$kanbanGroup['others'][$programID] = $program;
|
||||
}
|
||||
}
|
||||
|
||||
return $kanbanGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get involved programs by user.
|
||||
*
|
||||
* @param string $account
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getInvolvedPrograms($account)
|
||||
{
|
||||
$involvedPrograms = array();
|
||||
|
||||
/* All involves in program table. */
|
||||
$objects = $this->dao->select('id, type, project')->from(TABLE_PROGRAM)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere("(openedBy = '$account' or PM = '$account')")
|
||||
->fetchAll('id');
|
||||
|
||||
foreach($objects as $id => $object)
|
||||
{
|
||||
if($object->type == 'program') $involvedPrograms[$id] = $id;
|
||||
if($object->type == 'project')
|
||||
{
|
||||
$programID = $this->getTopByID($id);
|
||||
$involvedPrograms[$programID] = $programID;
|
||||
}
|
||||
if($object->type == 'sprint' || $object->type == 'stage')
|
||||
{
|
||||
$programID = $this->getTopByID($object->project);
|
||||
$involvedPrograms[$programID] = $programID;
|
||||
}
|
||||
}
|
||||
|
||||
/* All involves in stakeholder table. */
|
||||
$stakeholders = $this->dao->select('t1.objectID, t2.type')->from(TABLE_STAKEHOLDER)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')
|
||||
->on('t1.objectID = t2.id')
|
||||
->where('t1.objectType')->in("program,project")
|
||||
->andWhere('t1.user')->eq($account)
|
||||
->fetchAll('objectID');
|
||||
|
||||
foreach($stakeholders as $objectID => $object)
|
||||
{
|
||||
if($object->type == 'program')
|
||||
{
|
||||
$involvedPrograms[$objectID] = $objectID;
|
||||
}
|
||||
if($object->type == 'project')
|
||||
{
|
||||
$programID = $this->getTopByID($objectID);
|
||||
$involvedPrograms[$programID] = $programID;
|
||||
}
|
||||
}
|
||||
|
||||
/* All involves in team table. */
|
||||
$teams = $this->dao->select('t1.root, t2.project, t2.type')->from(TABLE_TEAM)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')
|
||||
->on('t1.root = t2.id')
|
||||
->where('t1.account')->eq($account)
|
||||
->andWhere('t1.type')->in('project,execution')
|
||||
->fetchAll('root');
|
||||
|
||||
foreach($teams as $objectID => $object)
|
||||
{
|
||||
if($object->type == 'project')
|
||||
{
|
||||
$programID = $this->getTopByID($objectID);
|
||||
$involvedPrograms[$programID] = $programID;
|
||||
}
|
||||
if($object->type == 'execution')
|
||||
{
|
||||
$programID = $this->getTopByID($object->project);
|
||||
$involvedPrograms[$programID] = $programID;
|
||||
}
|
||||
}
|
||||
|
||||
/* All involves in products table. */
|
||||
$products = $this->dao->select('id, program, createdBy, PO, QD, RD')->from(TABLE_PRODUCT)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere("(createdBy = '$account' or PO = '$account' or QD = '$account' or RD = '$account')")
|
||||
->fetchAll('id');
|
||||
|
||||
foreach($products as $id => $product) $involvedPrograms[$product->program] = $product->program;
|
||||
|
||||
/* Check priv. */
|
||||
$involvedPrograms = $this->dao->select('id')->from(TABLE_PROGRAM)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->programs)->fi()
|
||||
->andWhere('id')->in($involvedPrograms)
|
||||
->andWhere('grade')->eq(1)
|
||||
->fetchPairs();
|
||||
|
||||
return $involvedPrograms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute progress for project or execution.
|
||||
*
|
||||
* @param array $tasks
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function computeProgress($tasks)
|
||||
{
|
||||
$hours = array();
|
||||
foreach($tasks as $projectID => $projectTasks)
|
||||
{
|
||||
$hour = new stdclass();
|
||||
$hour->totalConsumed = 0;
|
||||
$hour->totalEstimate = 0;
|
||||
$hour->totalLeft = 0;
|
||||
|
||||
foreach($projectTasks as $task)
|
||||
{
|
||||
$hour->totalConsumed += $task->consumed;
|
||||
$hour->totalEstimate += $task->estimate;
|
||||
if($task->status != 'cancel' and $task->status != 'closed') $hour->totalLeft += $task->left;
|
||||
}
|
||||
$hours[$projectID] = $hour;
|
||||
}
|
||||
|
||||
foreach($hours as $hour)
|
||||
{
|
||||
$hour->totalEstimate = round($hour->totalEstimate, 1) ;
|
||||
$hour->totalConsumed = round($hour->totalConsumed, 1);
|
||||
$hour->totalLeft = round($hour->totalLeft, 1);
|
||||
$hour->totalReal = $hour->totalConsumed + $hour->totalLeft;
|
||||
$hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 2) * 100 : 0;
|
||||
}
|
||||
|
||||
return $hours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project list data.
|
||||
*
|
||||
* @param int $programID
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* The html template file of kanban method of program module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
|
||||
* @license ZPL (http://zpl.pub/page/zplv12.html)
|
||||
* @author Guangming Sun<sunguangming@cnezsoft.com>
|
||||
* @package ZenTaoPMS
|
||||
* @version $Id
|
||||
*/
|
||||
?>
|
||||
<?php include '../../common/view/header.html.php';?>
|
||||
<div id="kanban" class="main-table fade auto-fade-in" data-ride="table" data-checkable="false" data-group="true">
|
||||
<?php foreach($kanbanGroup as $type => $programGroup):?>
|
||||
<?php $colorIndex = 0;?>
|
||||
<div class="cell">
|
||||
<div class='detail'>
|
||||
<div class='detail-title'><?php echo $lang->program->kanban->typeList[$type];?></div>
|
||||
<div class='detail-content'>
|
||||
<table class="table no-margin table-grouped text-center" style='background: #f5f5f5;'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan='2' class='w-20px' style='background: #32C5FF; border-bottom: none'></th>
|
||||
<th rowspan='2'><?php echo $lang->program->kanban->activeProducts;?></th>
|
||||
<th rowspan='2'><?php echo $lang->program->kanban->activePlans;?></th>
|
||||
<th rowspan='2'><?php echo $lang->program->kanban->waitProjects;?></th>
|
||||
<th colspan='2'><?php echo $lang->program->statusList['doing'];?></th>
|
||||
<th rowspan='2'><?php echo $lang->program->kanban->normalReleases;?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->program->kanban->doingProjects;?></th>
|
||||
<th><?php echo $lang->program->kanban->doingExecutions;?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($programGroup as $programID => $program):?>
|
||||
<tr>
|
||||
<td style='background: <?php echo $lang->program->kanban->laneColorList[$colorIndex];?>; color: #fff; border-right: none;' rowspan='<?php echo count($program->products);?>'><?php echo $program->name;?></td>
|
||||
<?php $i = 0;?>
|
||||
<?php if(!empty($program->products)):?>
|
||||
<?php foreach($program->products as $productID => $product):?>
|
||||
<?php if($i != 0) echo '<tr>';?>
|
||||
<td><?php echo $product->name;?></td>
|
||||
<td>
|
||||
<?php foreach($product->plans as $planID => $plan):?>
|
||||
<div class='board-item'>
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<?php echo html::a($this->createLink('productplan', 'view', "planID=$plan->id"), $plan->title);?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if(isset($product->projects['wait'])):?>
|
||||
<?php foreach($product->projects['wait'] as $projectID => $project):?>
|
||||
<div class='board-item'>
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<?php echo html::a($this->createLink('project', 'view', "projectID=$projectID"), $project->name);?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class='doing-project'>
|
||||
<?php if(isset($product->projects['doing'])):?>
|
||||
<?php foreach($product->projects['doing'] as $projectID => $project):?>
|
||||
<div class='board-item'>
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<?php echo html::a($this->createLink('project', 'view', "projectID=$projectID"), $project->name);?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td class='doing-execution'>
|
||||
<?php if(isset($product->projects['doing'])):?>
|
||||
<?php foreach($product->projects['doing'] as $projectID => $project):?>
|
||||
<div class='board-item'>
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<?php if(!empty($project->execution)):?>
|
||||
<?php echo html::a($this->createLink('execution', 'view', "executionID={$project->execution->id}"), $project->execution->name);?>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
<td>
|
||||
<?php foreach($product->releases as $releaseID => $release):?>
|
||||
<div class='board-item'>
|
||||
<div class='table-row'>
|
||||
<div class='table-col'>
|
||||
<?php echo html::a($this->createLink('release', 'view', "releaseID=$release->id"), $release->name);?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</td>
|
||||
<?php if($i != 0) echo '</tr>';?>
|
||||
<?php $i ++;?>
|
||||
<?php endforeach;?>
|
||||
<?php else:?>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<?php endif;?>
|
||||
</tr>
|
||||
<?php $colorIndex ++;?>
|
||||
<?php if($colorIndex > 9) $colorIndex = 0;?>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
<?php include '../../common/view/footer.html.php';?>
|
||||
@@ -760,7 +760,7 @@ class projectModel extends model
|
||||
$this->dao->insert(TABLE_PROJECT)->data($project)
|
||||
->autoCheck()
|
||||
->batchcheck($requiredFields, 'notempty')
|
||||
->check('name', 'unique', "type='project'")
|
||||
->check('name', 'unique', "type='project' AND deleted='0'")
|
||||
->exec();
|
||||
|
||||
/* Add the creater to the team. */
|
||||
@@ -951,7 +951,7 @@ class projectModel extends model
|
||||
->checkIF($project->begin != '', 'begin', 'date')
|
||||
->checkIF($project->end != '', 'end', 'date')
|
||||
->checkIF($project->end != '', 'end', 'gt', $project->begin)
|
||||
->check('name', 'unique', "id != $projectID AND type='project'")
|
||||
->check('name', 'unique', "id != $projectID AND type='project' AND deleted='0'")
|
||||
->where('id')->eq($projectID)
|
||||
->exec();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user