Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 2 additions & 24 deletions src/Activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use LimitIterator;
use SplFileObject;
use Throwable;
Expand All @@ -23,11 +21,13 @@
use Workflow\Middleware\WithoutOverlappingMiddleware;
use Workflow\Models\StoredWorkflow;
use Workflow\Serializers\Serializer;
use Workflow\Traits\ActivityWithWebhookSupport;
use Workflow\Traits\ResolvesMethodDependencies;
use Workflow\Traits\SerializesModels;

class Activity implements ShouldBeEncrypted, ShouldBeUnique, ShouldQueue
{
use ActivityWithWebhookSupport;
use Dispatchable;
use InteractsWithQueue;
use Queueable;
Expand Down Expand Up @@ -89,20 +89,6 @@ public function workflowId()
return $this->storedWorkflow->id;
}

public function webhookUrl(string $signalMethod = ''): string
{
$workflow = Str::kebab(class_basename($this->storedWorkflow->class));

if ($signalMethod === '') {
return route("workflows.start.{$workflow}");
}

$signal = Str::kebab($signalMethod);
return route("workflows.signal.{$workflow}.{$signal}", [
'workflowId' => $this->storedWorkflow->id,
]);
}

public function handle()
{
if (! method_exists($this, 'execute')) {
Expand Down Expand Up @@ -174,12 +160,4 @@ public function failed(Throwable $throwable): void
$this::class
);
}

public function heartbeat(): void
{
pcntl_alarm(max($this->timeout, 0));
if ($this->timeout) {
Cache::put($this->key, 1, $this->timeout);
}
}
}
38 changes: 38 additions & 0 deletions src/Traits/ActivityWithWebhookSupport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Workflow\Traits;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;

/**
* Optional trait providing webhook and heartbeat support for activities.
* Use this trait if you need webhook URLs or heartbeat functionality.
* Activities without this trait will analyze faster in static analysis tools.
*/
trait ActivityWithWebhookSupport
{
public function webhookUrl(string $signalMethod = ''): string
{
$workflow = Str::kebab(class_basename($this->storedWorkflow->class));

if ($signalMethod === '') {
return route("workflows.start.{$workflow}");
}

$signal = Str::kebab($signalMethod);
return route("workflows.signal.{$workflow}.{$signal}", [
'workflowId' => $this->storedWorkflow->id,
]);
}

public function heartbeat(): void
{
pcntl_alarm(max($this->timeout, 0));
if ($this->timeout) {
Cache::put($this->key, 1, $this->timeout);
}
}
}
80 changes: 74 additions & 6 deletions src/Traits/ResolvesMethodDependencies.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@

namespace Workflow\Traits;

use Illuminate\Routing\ResolvesRouteDependencies;
use ReflectionClass;
use ReflectionFunctionAbstract;
use ReflectionMethod;
use ReflectionNamedType;
use ReflectionParameter;
use stdClass;

trait ResolvesMethodDependencies
{
use ResolvesRouteDependencies {
resolveMethodDependencies as private resolveMethodDependenciesBase;
}

public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector)
public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector): array
{
$instanceCount = 0;

Expand All @@ -37,4 +36,73 @@ public function resolveMethodDependencies(array $parameters, ReflectionFunctionA

return $parameters;
}

protected function resolveClassMethodDependencies(array $parameters, object $instance, string $method): array
{
if (! method_exists($instance, $method)) {
return $parameters;
}

return $this->resolveMethodDependencies($parameters, new ReflectionMethod($instance, $method));
}

protected function transformDependency(
ReflectionParameter $parameter,
array $parameters,
object $skippableValue
): mixed {
$className = $this->getParameterClassName($parameter);

if ($className !== null && ! $this->alreadyInParameters($className, $parameters)) {
$isEnum = (new ReflectionClass($className))->isEnum();

return $parameter->isDefaultValueAvailable()
? ($isEnum ? $parameter->getDefaultValue() : null)
: $this->container->make($className);
}

return $skippableValue;
}

protected function alreadyInParameters(string $className, array $parameters): bool
{
foreach ($parameters as $parameter) {
if ($parameter instanceof $className) {
return true;
}
}

return false;
}

protected function spliceIntoParameters(array &$parameters, int $offset, mixed $value): void
{
array_splice($parameters, $offset, 0, [$value]);
}

protected function getParameterClassName(ReflectionParameter $parameter): ?string
{
$type = $parameter->getType();

if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) {
return null;
}

$name = $type->getName();
$class = $parameter->getDeclaringClass();

if ($class === null) {
return $name;
}

if ($name === 'self') {
return $class->getName();
}

if ($name === 'parent') {
return $class->getParentClass()?->getName();
}

return $name;
}
}
Loading