snapshot of https://github.com/espocrm/espocrm.git (master, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Test / Test on PHP 8.3 (push) Failing after 5s
Test / Test on PHP 8.4 (push) Failing after 4s
Test / Test on PHP 8.5 (push) Failing after 3s
TypeScript static analysis / TypeScript check (push) Failing after 14s
Test Integration on MySQL / Test on PHP 8.3 (push) Failing after 1s
Test Integration on MySQL / Test on PHP 8.5 (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 fix (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 master (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-18 04:19:15 +05:00
commit 7cc7e6b4f3
10077 changed files with 900756 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace EspoDev\PHPStan\Extensions;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\ClassConstFetch;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\Type;
use PHPStan\Type\ObjectType;
use PHPStan\Type\UnionType;
use PHPStan\Type\NullType;
use PHPStan\Type\Generic\GenericObjectType;
use PhpParser\Node\Scalar\String_;
use RuntimeException;
use Espo\ORM\Entity;
use Espo\ORM\EntityManager;
use Espo\Core\Utils\Util;
use Espo\ORM\Repository\RDBRepository;
use Espo\ORM\Repository\Repository;
class EntityManagerReturnType implements DynamicMethodReturnTypeExtension
{
private $supportedMethodNameList = [
'getEntity',
'getNewEntity',
'getEntityById',
'createEntity',
'getRDBRepository',
'getRepository',
];
private $entityNamespaceList = [
'\\Espo\\Modules\\Crm\\Entities',
'\\Espo\\Entities',
];
public function getClass(): string
{
return EntityManager::class;
}
public function isMethodSupported(MethodReflection $methodReflection): bool
{
return in_array($methodReflection->getName(), $this->supportedMethodNameList);
}
public function getTypeFromMethodCall(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type {
$methodName = $methodReflection->getName();
if ($methodName === 'getEntity' || $methodName === 'getEntityById') {
return $this->getGetEntity($methodReflection, $methodCall, $scope);
}
if ($methodName === 'getNewEntity' || $methodName === 'createEntity') {
return $this->getGetEntityNotNull($methodReflection, $methodCall, $scope);
}
if ($methodName === 'getRDBRepository') {
return $this->getGetRDBRepository($methodReflection, $methodCall, $scope);
}
if ($methodName === 'getRepository') {
return $this->getGetRepository($methodReflection, $methodCall, $scope);
}
throw new RuntimeException("Not supported method.");
}
private function getGetEntity(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type {
$entityType = $this->getEntityTypeFromExpr($methodCall->args[0]->value);
if (!$entityType) {
return new UnionType([
new ObjectType(Entity::class),
new NullType(),
]);
}
$className = $this->findEntityClassName($entityType) ?? Entity::class;
return new UnionType([
new ObjectType($className),
new NullType(),
]);
}
private function getGetEntityNotNull(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type {
$entityType = $this->getEntityTypeFromExpr($methodCall->args[0]->value);
if (!$entityType) {
return new ObjectType(Entity::class);
}
$className = $this->findEntityClassName($entityType) ?? Entity::class;
return new ObjectType($className);
}
private function findEntityClassName(string $entityType): ?string
{
foreach ($this->entityNamespaceList as $namespace) {
$className = $namespace . '\\' . Util::normalizeClassName($entityType);
if (class_exists($className)) {
return $className;
}
}
return null;
}
private function getGetRDBRepository(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type {
$entityType = $this->getEntityTypeFromExpr($methodCall->args[0]->value);
if (!$entityType) {
return new ObjectType(RDBRepository::class);
}
$entityClassName = $this->findEntityClassName($entityType);
if ($entityClassName) {
return new GenericObjectType(RDBRepository::class, [new ObjectType($entityClassName)]);
}
return new ObjectType(RDBRepository::class);
}
private function getGetRepository(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type {
$entityType = $this->getEntityTypeFromExpr($methodCall->args[0]->value);
if (!$entityType) {
return new ObjectType(Repository::class);
}
$entityClassName = $this->findEntityClassName($entityType);
if ($entityClassName) {
return new GenericObjectType(Repository::class, [new ObjectType($entityClassName)]);
}
return new ObjectType(Repository::class);
}
private function getEntityTypeFromExpr(Expr $expr): ?string
{
if ($expr instanceof String_) {
return $expr->value;
}
if ($expr instanceof ClassConstFetch) {
return constant($expr->class . '::' . $expr->name);
}
return null;
}
}