<?php
namespace CorporateTrainingBundle\Biz\Org\Service\Impl;
use AppBundle\Common\ArrayToolkit;
use AppBundle\Common\Exception\AccessDeniedException;
use Biz\Org\Service\Impl\OrgServiceImpl as BaseOrgServiceImpl;
use Biz\System\Service\CacheService;
use Biz\System\Service\LogService;
use Codeages\Biz\Framework\Service\Exception\NotFoundException;
use CorporateTrainingBundle\Biz\ManagePermission\Service\ManagePermissionOrgService;
use CorporateTrainingBundle\Biz\Org\Service\OrgService;
use CorporateTrainingBundle\Common\Constant\CTConst;
use CorporateTrainingBundle\Common\OrgTreeToolkit;
class OrgServiceImpl extends BaseOrgServiceImpl implements OrgService
{
protected $visibleOrgTreeDataLocalCacheArray = [];
/**
* @param $id
* @param $num //正数或负数
*
* @return array
*
* @throws NotFoundException
*/
public function waveOrgChildrenNum($id, $num)
{
$org = $this->checkBeforeProccess($id);
$childrenNum = ($org['childrenNum'] + $num) < 1 ? 0 : $org['childrenNum'] + $num;
return $this->getOrgDao()->update($id, ['childrenNum' => $childrenNum]);
}
public function countOrgs(array $conditions)
{
return $this->getOrgDao()->count($conditions);
}
public function getOrgBySyncId($syncId)
{
return $this->getOrgDao()->getOrgBySyncId($syncId);
}
public function findOrgsBySyncIds($syncIds)
{
return $this->getOrgDao()->findOrgsBySyncIds($syncIds);
}
public function findOrgsByOrgCodes(array $orgCodes)
{
return $this->getOrgDao()->findByOrgCodes($orgCodes);
}
public function findOrgsByCodes(array $codes)
{
return $this->getOrgDao()->findByCodes($codes);
}
public function findSelfAndParentOrgsByOrgCode($orgCode)
{
$preOrgIdArray = explode('.', $orgCode);
return $this->findOrgsByIds($preOrgIdArray);
}
public function findOrgsByPrefixOrgCodes(array $orgCodes = ['1.'], $columns = [])
{
$cacheName = md5(json_encode($orgCodes).'|'.json_encode($columns));
$cacheOrgs = $this->getCacheService()->get($cacheName);
if (!empty($cacheOrgs)) {
return $cacheOrgs;
}
$result = $this->getOrgDao()->findByPrefixOrgCodes($orgCodes, $columns);
$this->getCacheService()->clear($cacheName);
$this->getCacheService()->set($cacheName, $result, time() + 60 * 3);
return $result;
}
public function getOrgMaxDepth($conditions)
{
return $this->getOrgDao()->getMaxDepth($conditions);
}
public function resetOrg()
{
$currentUser = $this->getCurrentUser();
if ($currentUser->isSuperAdmin() || $currentUser->hasPermission('admin_org_sync_department')) {
$org = $this->getOrg(CTConst::ROOT_ORG_CODE);
$this->getOrgDao()->wave([$org['id']], ['childrenNum' => -$org['childrenNum']]);
$this->getOrgDao()->update($org['id'], ['syncId' => 0]);
return $this->getOrgDao()->deleteOrgsWithoutOrgCode(CTConst::ROOT_ORG_CODE);
}
return false;
}
public function resetOrgSyncId()
{
$this->getOrgDao()->resetOrgSyncId();
}
public function buildOrgTreeByCode($orgCode)
{
if (empty($orgCode)) {
return [];
}
$orgInfo = $this->getOrgByOrgCode($orgCode);
$orgs = $this->findOrgsByPrefixOrgCode($orgCode);
$orgs = ArrayToolkit::index($orgs, 'id');
for ($i = CTConst::ORG_MAX_DEPTH; $i >= ($orgInfo['depth'] + 1); --$i) {
foreach ($orgs as $key => $org) {
if (!empty($org['depth']) && $org['depth'] == $i && $org['depth'] > 1) {
$orgs[$org['parentId']]['nodes'][] = $org;
unset($orgs[$key]);
}
}
}
return array_values($orgs);
}
public function buildVisibleOrgTreeByOrgCodes(array $orgCodes)
{
return array_values(OrgTreeToolkit::makeTree($this->getVisibleOrgTreeDataByOrgCodes($orgCodes, true)));
}
/**
* @param $settingOrgIds
* 被设置的用户或资源的部门orgIds
* @param bool $filter
*
* @return array|mixed
*
* 部门设置特定树结构(展示管理员的管理范围及被操作用户的超出管理员权限部分的部门,部门树中超出我管理范围的部分只展示顶级)
*/
public function getPermissionOrgTreeData($settingOrgIds, $filter = false)
{
$orgCodes = $this->getCurrentUser()->getManageOrgCodes();
if (empty($orgCodes)) {
return [];
}
$cacheKey = $this->getPermissionOrgTreeDataLocalCacheKey($orgCodes, $settingOrgIds, $filter);
if (isset($this->visibleOrgTreeDataLocalCacheArray[$cacheKey])) {
return $this->visibleOrgTreeDataLocalCacheArray[$cacheKey];
}
$orgs = $this->findOrgsByPrefixOrgCodes($orgCodes);
$orgCodes = ArrayToolkit::column($orgs, 'orgCode');
$settingOrgs = $this->findOrgsByIds($settingOrgIds);
$settingOrgCodes = ArrayToolkit::column($settingOrgs, 'orgCode');
$diffOrgCodes = array_diff($settingOrgCodes, $orgCodes);
if (in_array('1.', $diffOrgCodes, true)) {
$parentOrg = $this->getOrgByOrgCode('1.');
$allOrgs = $this->findOrgsByParentId($parentOrg['id']);
$allOrgs = array_merge($allOrgs, [$parentOrg], $orgs);
if ($filter) {
$allOrgs = $this->filterOrgs($allOrgs);
}
foreach ($allOrgs as &$org) {
$org['disableCheckbox'] = true;
$org['selectable'] = false;
}
} else {
$diffOrgs = $this->findOrgsByOrgCodes(array_values($diffOrgCodes));
$orgCodeIds = $this->exploreOrgCodes($orgCodes);
$parentOrgIds = array_diff($orgCodeIds, ArrayToolkit::column($orgs, 'id'));
$parentOrgs = $this->findOrgsByIds(array_values($parentOrgIds));
$allOrgs = array_merge($orgs, $parentOrgs, $diffOrgs);
if ($filter) {
$allOrgs = $this->filterOrgs($allOrgs);
}
$diffOrgTreeOrgCodes = [];
if (!empty($diffOrgCodes)) {
$diffOrgTree = $this->findOrgsByPrefixOrgCodes($diffOrgCodes, ['orgCode']);
$diffOrgTreeOrgCodes = ArrayToolkit::column($diffOrgTree, 'orgCode');
}
foreach ($allOrgs as &$org) {
if (in_array($org['id'], $parentOrgIds) || in_array($org['orgCode'], $diffOrgTreeOrgCodes)) {
$org['selectable'] = false;
$org['disableCheckbox'] = true;
} else {
$org['selectable'] = true;
$org['disableCheckbox'] = false;
}
}
}
$indexedAllOrgs = ArrayToolkit::index($allOrgs, 'orgCode');
ksort($indexedAllOrgs);
$treeData = array_values($indexedAllOrgs);
$this->visibleOrgTreeDataLocalCacheArray[$cacheKey] = $treeData;
return $treeData;
}
/*
* 获取可见的部门树组件数据,直线上级及所有下级
*/
public function getVisibleOrgTreeDataByOrgCodes(array $orgCodes, $filter = false)
{
$cacheKey = $this->getVisibleOrgTreeDataLocalCacheKey($orgCodes, $filter);
if (isset($this->visibleOrgTreeDataLocalCacheArray[$cacheKey])) {
return $this->visibleOrgTreeDataLocalCacheArray[$cacheKey];
}
$orgs = $this->findOrgsByPrefixOrgCodes($orgCodes);
$orgCodes = ArrayToolkit::column($orgs, 'orgCode');
$orgCodeIds = $this->exploreOrgCodes($orgCodes);
$parentOrgIds = array_diff($orgCodeIds, ArrayToolkit::column($orgs, 'id'));
$parentOrgs = $this->findOrgsByIds(array_values($parentOrgIds));
$allOrgs = array_merge($orgs, $parentOrgs);
if ($filter) {
$allOrgs = $this->filterOrgs($allOrgs);
}
foreach ($allOrgs as &$org) {
if (in_array($org['id'], $parentOrgIds)) {
$org['selectable'] = false;
$org['disableCheckbox'] = true;
} else {
$org['selectable'] = true;
$org['disableCheckbox'] = false;
}
}
$indexedAllOrgs = ArrayToolkit::index($allOrgs, 'orgCode');
ksort($indexedAllOrgs);
$treeData = array_values($indexedAllOrgs);
$this->visibleOrgTreeDataLocalCacheArray[$cacheKey] = $treeData;
return $treeData;
}
public function buildOrgTreeByParentId($parentId, $offset, $limit, $filter = false)
{
$orgs = $this->findOrgsDataByParentId($parentId, $offset, $limit, $filter);
if (empty($orgs)) {
return [];
}
$orgTree = array_values(OrgTreeToolkit::makeTree($orgs));
$childrenCounts = $this->childrenCountsByOrgIds(ArrayToolkit::column($orgs, 'id'));
$childrenCounts = ArrayToolkit::index($childrenCounts, 'parentId');
$orgTree = $this->findChildrenTree($orgTree[0], $parentId, $childrenCounts);
return $orgTree;
}
public function findOrgsDataByParentId($parentId, $offset, $limit, $filter = false)
{
$orgs = $this->searchOrgs(['parentId' => $parentId], ['orgCode' => 'ASC'], $offset, $limit);
if (empty($orgs)) {
return [];
}
$parentOrg = $this->getOrg($parentId);
$parentIds = $this->parentOrgIdsByOrgCodes([$parentOrg['orgCode']]);
$orgs = array_merge($orgs, $this->findOrgsByIds(array_merge($parentIds, [$parentId])));
if ($filter) {
$orgs = $this->filterOrgs($orgs);
}
foreach ($orgs as &$org) {
if (in_array($org['id'], $parentIds, true)) {
$org['selectable'] = false;
$org['disableCheckbox'] = true;
} else {
$org['selectable'] = true;
$org['disableCheckbox'] = false;
}
}
return $orgs;
}
public function buildCanManageOrgTreeByParentId($parentId, $settingOrgIds, $offset, $limit, $filter = false)
{
$orgs = $this->findCanManageOrgsDataByParentId($parentId, $settingOrgIds, $offset, $limit, $filter);
if (empty($orgs)) {
return [];
}
$orgTree = array_values(OrgTreeToolkit::makeTree($orgs));
$childrenCounts = $this->childrenCountsByOrgIds(ArrayToolkit::column($orgs, 'id'));
$childrenCounts = ArrayToolkit::index($childrenCounts, 'parentId');
$orgTree = $this->findChildrenTree($orgTree[0], $parentId, $childrenCounts);
return $orgTree;
}
public function findCanManageOrgsDataByParentId($parentId, $settingOrgIds, $offset, $limit, $filter = false)
{
$manageOrgCodes = $this->getCurrentUser()->getManageOrgCodes();
if (empty($manageOrgCodes)) {
return [];
}
list($manageOrgIds, $lastOrgIds) = $this->exploreOrgCodesAndLastOrgIds($manageOrgCodes);
$noPermissionOrgIds = array_values(array_filter($this->parentOrgIdsByOrgCodes($manageOrgCodes)));
$noPermissionSettingOrgIds = array_intersect($noPermissionOrgIds, $settingOrgIds);
$parentOrg = $this->getOrg($parentId);
$parentOrgIds = $this->parentOrgIdsByOrgCodes([$parentOrg['orgCode']]);
$conditions = ['parentId' => $parentId];
if (!in_array('1', $lastOrgIds, true)) {
if (empty(array_intersect($manageOrgIds, $parentOrgIds)) || (in_array(
$parentId,
$manageOrgIds,
true
) && !in_array($parentId, $lastOrgIds, true))) {
$conditions['orgIds'] = $manageOrgIds;
}
}
$allOrgs = $this->searchOrgs(
$conditions,
['orgCode' => 'ASC'],
$offset,
$limit
);
if (empty($allOrgs)) {
return [];
}
$parentOrgs = $this->findOrgsByIds($parentOrgIds);
$allOrgs = array_merge($allOrgs, $parentOrgs, [$parentOrg]);
if ($filter) {
$allOrgs = $this->filterOrgs($allOrgs);
}
foreach ($allOrgs as &$org) {
$exploreOrgIds = $this->exploreOrgCodes([$org['orgCode']]);
$exploreOrgIds = array_diff($exploreOrgIds, $noPermissionOrgIds);
if ((!empty($noPermissionSettingOrgIds) && !empty(
array_intersect(
$exploreOrgIds,
$noPermissionSettingOrgIds
)
)) || in_array($org['id'], $noPermissionOrgIds, true)) {
$org['selectable'] = false;
$org['disableCheckbox'] = true;
} else {
$org['selectable'] = true;
$org['disableCheckbox'] = false;
}
}
return $allOrgs;
}
public function findOrgsByParentId($orgId)
{
return $this->getOrgDao()->findByParentOrgId($orgId);
}
public function findOrgsByParentIds($orgIds)
{
return $this->getOrgDao()->findByParentOrgIds($orgIds);
}
public function findParentOrgIdsByOrgId($orgId)
{
$parentOrgIds = [];
$parentOrgIds = $this->findParentOrgIdByIdAndCategories($orgId, $parentOrgIds);
return array_merge($parentOrgIds, [$orgId]);
}
protected function findParentOrgIdByIdAndCategories($orgId, &$parentOrgIds)
{
$org = $this->getOrg($orgId);
if (0 != $org['parentId']) {
$parentOrg = $this->getOrg($org['parentId']);
$parentOrgIds = array_merge($parentOrgIds, [$parentOrg['id']]);
$this->findParentOrgIdByIdAndCategories($parentOrg['id'], $parentOrgIds);
}
return $parentOrgIds;
}
/**
* @param $orgIds
*
* @return array 过滤子部门获取顶层部门
*/
public function wipeOffChildrenOrgIds($orgIds)
{
$orgs = $this->findOrgsByIds($orgIds);
$orgs = ArrayToolkit::index($orgs, 'id');
$orgIds = [];
foreach ($orgs as $org) {
if (empty($orgs[$org['parentId']])) {
$orgIds[] = $org['id'];
}
}
return $orgIds;
}
public function wipeOffChildrenCode($codes)
{
if (empty($codes)) {
return [];
}
$orgs = $this->findOrgsByCodes($codes);
$orgs = ArrayToolkit::index($orgs, 'id');
$orgCodes = [];
foreach ($orgs as $org) {
if (empty($orgs[$org['parentId']])) {
$orgCodes[] = $org['code'];
}
}
return $orgCodes;
}
public function childrenCountsByOrgIds($orgIds)
{
return $this->getOrgDao()->childrenCountsByOrgIds($orgIds);
}
public function deleteOrgWithoutDeleteChildren($id)
{
$org = $this->getOrg($id);
if (empty($org)) {
return;
}
if ('1.' == $org['orgCode']) {
throw new AccessDeniedException('顶级部门不可删除!');
}
try {
$this->beginTransaction();
$this->getOrgDao()->delete($id);
$parentOrg = $this->getOrg($org['parentId']);
$groupChildOrgs = ArrayToolkit::group($this->findOrgsByPrefixOrgCode($org['orgCode']), 'parentId');
$updateFields = [];
$orgQueue = [$org];
while ($orgQueue) {
$currentOrg = array_shift($orgQueue);
if ($currentOrg['id'] != $org['id']) {
$updateFields[$currentOrg['id']] = [
'parentId' => $currentOrg['parentId'] == $org['id'] ? $org['parentId'] : $currentOrg['parentId'],
'orgCode' => $currentOrg['parentId'] == $org['id'] ? $parentOrg['orgCode'].$currentOrg['id'].'.' : $updateFields[$currentOrg['parentId']]['orgCode'].$currentOrg['id'],
'depth' => $currentOrg['depth'] - 1,
];
}
if (isset($groupChildOrgs[$currentOrg['id']])) {
$orgQueue = array_merge($orgQueue, $groupChildOrgs[$currentOrg['id']]);
}
}
$this->getOrgDao()->wave([$org['parentId']], ['childrenNum' => $org['childrenNum'] - 1]);
if ($updateFields) {
$this->getOrgDao()->batchUpdate(array_keys($updateFields), $updateFields, 'id');
}
$this->getLogService()->info('org', 'delete_org', "删除部门{$org['name']}", ['org' => $org]);
$this->commit();
} catch (\Exception $e) {
$this->rollback();
throw $e;
}
}
protected function findChildrenTree($tree, $parentId, $childrenCounts)
{
if (empty($tree['nodes'])) {
return $tree;
}
$nodes = $tree['nodes'];
foreach ($nodes as &$org) {
if ($org['id'] == $parentId || 1 == count($org['nodes'])) {
return $this->findChildrenTree($org, $parentId, $childrenCounts);
}
if ($org['parentId'] == $parentId && !empty($childrenCounts[$org['id']])) {
$org['nodes'] = [['name' => '加载中···', 'isExist' => $childrenCounts[$org['id']]['count'] > 0]];
}
}
$tree['nodes'] = $nodes;
return $tree;
}
protected function getVisibleOrgTreeDataLocalCacheKey($orgCodes, $filter)
{
return md5(json_encode($orgCodes).'|'.($filter ? '1' : '0'));
}
protected function getPermissionOrgTreeDataLocalCacheKey($orgCodes, $settingOrgIds, $filter)
{
return md5(json_encode($settingOrgIds).'|'.json_encode($orgCodes).'|'.($filter ? '1' : '0'));
}
protected function filterOrgs($orgs)
{
foreach ($orgs as $key => $org) {
$orgs[$key] = ArrayToolkit::parts(
$org,
[
'id',
'name',
'parentId',
'seq',
'orgCode',
'code',
'depth',
]
);
}
return $orgs;
}
protected function exploreOrgCodes(array $orgCodes)
{
$orgIds = [];
foreach ($orgCodes as $orgCode) {
$orgIds[] = array_filter(explode('.', $orgCode));
}
if (!empty($orgIds)) {
$orgIds = array_merge(...$orgIds);
}
return array_unique($orgIds);
}
protected function exploreOrgCodesAndLastOrgIds(array $orgCodes)
{
$orgGroup = [];
$lastIds = [];
foreach ($orgCodes as $orgCode) {
$orgIds = array_filter(explode('.', $orgCode));
$orgGroup[] = $orgIds;
$lastIds[] = end($orgIds);
}
$orgAllIds = !empty($orgGroup) ? array_merge(...$orgGroup) : [];
return [array_unique($orgAllIds), $lastIds];
}
protected function parentOrgIdsByOrgCodes($orgCodes)
{
$orgIds = [];
foreach ($orgCodes as $orgCode) {
$orgArr = array_filter(explode('.', $orgCode));
array_pop($orgArr);
$orgIds[] = $orgArr;
}
$orgIds = array_merge(...$orgIds);
return array_unique($orgIds);
}
public function filterCurrentUserManageOrgsByOrgs(array $orgs)
{
$orgIds = $this->getCurrentUser()->getManageOrgIds();
if (empty($orgIds) || empty($orgs)) {
return [];
}
$manageOrgs = [];
foreach ($orgs as $org) {
$orgCodeExplode = explode('.', $org['orgCode'] ?? '');
$intersectIds = array_intersect($orgCodeExplode, $orgIds);
if (empty($intersectIds)) {
continue;
}
$manageOrgs[] = $org;
}
return $manageOrgs;
}
/**
* @return array
*/
public function findCurrentUserManageOrgIds()
{
$manageOrgIds = $this->getCurrentUser()->getManageOrgIds();
if (empty($manageOrgIds)) {
return [];
}
$orgs = $this->findOrgsByIds($manageOrgIds, ['orgCode']);
if (empty($orgs)) {
return [];
}
$orgCodes = ArrayToolkit::column($orgs, 'orgCode');
$manageOrgs = $this->findOrgsByPrefixOrgCodes($orgCodes, ['id']);
if (empty($manageOrgs)) {
return [];
}
return ArrayToolkit::column($manageOrgs, 'id');
}
/**
* @return ManagePermissionOrgService
*/
protected function getManagePermissionService()
{
return $this->createService('CorporateTrainingBundle:ManagePermission:ManagePermissionOrgService');
}
/**
* @return LogService
*/
protected function getLogService()
{
return $this->createService('System:LogService');
}
/**
* @return CacheService
*/
protected function getCacheService()
{
return $this->createService('System:CacheService');
}
}