Skip to content

Commit

Permalink
Transpile to PHP 7.0 with Rector and manual replacements (#77)
Browse files Browse the repository at this point in the history
Makes the Blueprints library syntax–compatible with PHP >= 7.0 with
automated transpilation and manual adjustments.

The automated transpilation is done with
[rector](https://github.com/rectorphp/rector),
which downgrades features specific to PHP 7.2 and later features to PHP
7.1.

The manual part requires using regexps and editing the files by hand.

### Automated part

To transpile the code to PHP 7.1, run:

```bash
# Install rector:
composer require rector/rector --ignore-platform-req=php

# Transpile:
php vendor/bin/rector process src
```

Unfortunately, Rector does not support downgrading to PHP 7.0 yet, so we
need to do the
last stretch manually.

### Manual part

Rector will downgrade PHP code to PHP 7.1 but not further. We need PHP
7.0 compat
so here's a few additional regexps to run. Regexps are not, of course,
reliable in
the general case, but they seem to do the trick here.

List of manual replacements

* `: \?[a-zA-Z_0-9]+` -> (empty string) to remove the unsupported return
type
  from `function(): ?SchemaResolver {}` -> `function() {}`.
* `: iterable` to fix `Fatal error: Generators may only declare a return
type of Generator, Iterator or Traversable`.
* `\?[a-zA-Z_0-9]+ \$` -> `$` to remove the unsupported nullable type
from function signatures,
  e.g. `function(?Schema $schema){}` -> `function($schema){}`.
* `(protected|public|private) const` -> `const` as const visibility is
not supported in PHP 7.0.
* `: void` -> `` as `void` return type is unsupported in PHP 7.0.
* `[$ns, $name] = $this->parseName($name);` -> `list($ns, $name) =
$this->parseName($name);`
* `foreach ($data as [$cp, $chars]) {` -> `foreach ($data as list($cp,
$chars)) {`
* Find or write Rector rules for downgrading to PHP 7.0
  • Loading branch information
adamziel authored Mar 19, 2024
1 parent 07a0068 commit adaf722
Show file tree
Hide file tree
Showing 106 changed files with 1,113 additions and 429 deletions.
11 changes: 7 additions & 4 deletions src/WordPress/AsyncHttp/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
*/
class Client {
protected $concurrency = 10;
protected Map $requests;
protected $requests;
protected $onProgress;
protected $queue_needs_processing = false;

Expand Down Expand Up @@ -150,7 +150,7 @@ public function enqueue( $requests ) {
*
* @return resource
*/
public function get_stream( Request $request ) {
public function get_stream( $request ) {
if ( ! isset( $this->requests[ $request ] ) ) {
$this->enqueue_request( $request );
}
Expand All @@ -162,7 +162,10 @@ public function get_stream( Request $request ) {
return $this->requests[ $request ]->stream;
}

protected function enqueue_request( Request $request ) {
/**
* @param \WordPress\AsyncHttp\Request $request
*/
protected function enqueue_request( $request ) {
$stream = StreamWrapper::create_resource(
new StreamData( $request, $this )
);
Expand Down Expand Up @@ -232,7 +235,7 @@ protected function get_streamed_requests() {
* @return false|string
* @throws Exception
*/
public function read_bytes( Request $request, $length ) {
public function read_bytes( $request, $length ) {
if ( ! isset( $this->requests[ $request ] ) ) {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/WordPress/AsyncHttp/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class Request {

public string $url;
public $url;

/**
* @param string $url
Expand Down
4 changes: 2 additions & 2 deletions src/WordPress/AsyncHttp/StreamData.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

class StreamData extends VanillaStreamWrapperData {

public Request $request;
public Client $client;
public $request;
public $client;

public function __construct( Request $request, Client $group ) {
parent::__construct( null );
Expand Down
5 changes: 4 additions & 1 deletion src/WordPress/AsyncHttp/StreamWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ public function stream_open( $path, $mode, $options, &$opened_path ) {
return true;
}

public function stream_cast( int $cast_as ) {
/**
* @param int $cast_as
*/
public function stream_cast( $cast_as ) {
$this->initialize();

return parent::stream_cast( $cast_as );
Expand Down
9 changes: 6 additions & 3 deletions src/WordPress/AsyncHttp/async_http_streams.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,13 @@ function streams_http_requests_send( $streams ) {
$remaining_streams = $streams;
while ( count( $remaining_streams ) ) {
$write = $remaining_streams;
$ready = @stream_select( $read, $write, $except, 0, 5000000 );
sleep( 2 );
$ready = @stream_select( $read, $write, $except, 5, 5000000 );
if ( $ready === false ) {
throw new Exception( "Error: " . error_get_last()['message'] );
} elseif ( $ready <= 0 ) {
var_dump( $ready );
die();
throw new Exception( "stream_select timed out" );
}

Expand Down Expand Up @@ -172,7 +175,7 @@ function parse_http_headers( string $headers ) {
];
$headers = [];
foreach ( $lines as $line ) {
if ( ! str_contains( $line, ': ' ) ) {
if ( strpos($line, ': ') === false ) {
continue;
}
$line = explode( ': ', $line );
Expand Down Expand Up @@ -231,7 +234,7 @@ function streams_http_response_await_headers( $streams ) {
}
foreach ( $bytes as $k => $byte ) {
$headers[ $k ] .= $byte;
if ( str_ends_with( $headers[ $k ], "\r\n\r\n" ) ) {
if ( substr_compare($headers[ $k ], "\r\n\r\n", -strlen("\r\n\r\n")) === 0 ) {
unset( $remaining_streams[ $k ] );
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/WordPress/Blueprints/BlueprintMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function __construct() {
*
* @return Blueprint
*/
public function map( stdClass $blueprint ): Blueprint {
public function map( $blueprint ): Blueprint {
return $this->mapper->hydrate( $blueprint, Blueprint::class );
}

Expand Down
10 changes: 8 additions & 2 deletions src/WordPress/Blueprints/BlueprintParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ public function parse( $raw_blueprint ) {
);
}

public function fromObject( \stdClass $data ) {
/**
* @param \stdClass $data
*/
public function fromObject( $data ) {
$result = $this->validator->validate( $data );
if ( ! $result->isValid() ) {
print_r( ( new ErrorFormatter() )->format( $result->error() ) );
Expand All @@ -64,7 +67,10 @@ public function fromObject( \stdClass $data ) {
return $this->mapper->map( $data );
}

public function fromBlueprint( Blueprint $blueprint ) {
/**
* @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
*/
public function fromBlueprint( $blueprint ) {
$result = $this->validator->validate( $blueprint );
if ( ! $result->isValid() ) {
print_r( ( new ErrorFormatter() )->format( $result->error() ) );
Expand Down
12 changes: 9 additions & 3 deletions src/WordPress/Blueprints/Cache/FileCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
class FileCache implements CacheInterface {
private $filesystem;

public function __construct( private string|null $cacheDirectory = null ) {
private $cacheDirectory;

public function __construct( $cacheDirectory = null ) {
$this->cacheDirectory = $cacheDirectory;
// initialize the Filesystem component
$this->filesystem = new Filesystem();

Expand All @@ -34,7 +37,10 @@ public function __construct( private string|null $cacheDirectory = null ) {
}
}

public function get( $key, $default = null ): mixed {
/**
* @return mixed
*/
public function get( $key, $default = null ) {
$filepath = $this->getFilePathForKey( $key );
if ( ! file_exists( $filepath ) ) {
return $default;
Expand All @@ -47,7 +53,7 @@ public function get( $key, $default = null ): mixed {

public function set( $key, $value, $ttl = null ): bool {
$filepath = $this->getFilePathForKey( $key );
$data = serialize( $value );
$data = serialize( $value );

return file_put_contents( $filepath, $data ) !== false;
}
Expand Down
31 changes: 23 additions & 8 deletions src/WordPress/Blueprints/Compile/BlueprintCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

class BlueprintCompiler {
protected $stepRunnerFactory;
protected ResourceResolverInterface $resourceResolver;
protected $resourceResolver;

public function __construct(
$stepRunnerFactory,
Expand All @@ -27,7 +27,10 @@ public function __construct(
$this->stepRunnerFactory = $stepRunnerFactory;
}

public function compile( Blueprint $blueprint ): CompiledBlueprint {
/**
* @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
*/
public function compile( $blueprint ): CompiledBlueprint {
$blueprint->steps = array_merge( $this->expandShorthandsIntoSteps( $blueprint ), $blueprint->steps );

$progressTracker = new Tracker();
Expand All @@ -42,7 +45,10 @@ public function compile( Blueprint $blueprint ): CompiledBlueprint {
);
}

protected function expandShorthandsIntoSteps( Blueprint $blueprint ) {
/**
* @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
*/
protected function expandShorthandsIntoSteps( $blueprint ) {
// @TODO: This duplicates the logic in BlueprintComposer.
// It cannot be easily reused because of the dichotomy between the
// Step and Step model classes. Let's alter the code generation
Expand Down Expand Up @@ -87,7 +93,11 @@ protected function expandShorthandsIntoSteps( Blueprint $blueprint ) {
return $additional_steps;
}

protected function compileSteps( Blueprint $blueprint, Tracker $progress ) {
/**
* @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
* @param \WordPress\Blueprints\Progress\Tracker $progress
*/
protected function compileSteps( $blueprint, $progress ) {
$stepRunnerFactory = $this->stepRunnerFactory;
// Compile, ensure all the runners may be created and configured
$totalProgressWeight = 0;
Expand All @@ -114,13 +124,17 @@ protected function compileSteps( Blueprint $blueprint, Tracker $progress ) {
return $compiledSteps;
}

protected function compileResources( Blueprint $blueprint, Tracker $progress ) {
/**
* @param \WordPress\Blueprints\Model\DataClass\Blueprint $blueprint
* @param \WordPress\Blueprints\Progress\Tracker $progress
*/
protected function compileResources( $blueprint, $progress ) {
$resources = [];
$this->findResources( $blueprint, $resources );

$totalProgressWeight = count( $resources );
$compiledResources = [];
foreach ( $resources as $path => [$declaration, $resource] ) {
foreach ( $resources as $path => list( $declaration, $resource ) ) {
/** @var $resource ResourceDefinitionInterface */
$compiledResources[ $path ] = new CompiledResource(
$declaration,
Expand Down Expand Up @@ -151,13 +165,14 @@ protected function findResources( $blueprintFragment, &$resources, $path = '', $
// Check if the @var annotation mentions a ResourceDefinitionInterface
foreach ( get_object_vars( $blueprintFragment ) as $key => $value ) {
$reflection = new \ReflectionProperty( $blueprintFragment, $key );
$reflection->setAccessible(true);
$docComment = $reflection->getDocComment();
$parseNestedUrls = false;
if ( preg_match( '/@var\s+([^\s]+)/', $docComment, $matches ) ) {
$className = $matches[1];
if (
str_contains( $className, 'string' ) &&
str_contains( $className, 'ResourceDefinitionInterface' )
false !== strpos( $className, 'string' ) &&
false !== strpos( $className, 'ResourceDefinitionInterface' )
) {
$parseNestedUrls = true;
}
Expand Down
22 changes: 16 additions & 6 deletions src/WordPress/Blueprints/Compile/CompiledBlueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,23 @@
use WordPress\Blueprints\Progress\Tracker;

class CompiledBlueprint {
public $compiledSteps;
public $compiledResources;
public $progressTracker;
public $stepsProgressStage;

public function __construct(
public array $compiledSteps,
public array $compiledResources,
public Tracker $progressTracker,
public Tracker $stepsProgressStage,
) {
/**
* @param $compiledSteps
* @param $compiledResources
* @param $progressTracker
* @param $stepsProgressStage
*/
public function __construct( $compiledSteps, $compiledResources, $progressTracker, $stepsProgressStage ) {
$this->compiledSteps = $compiledSteps;
$this->compiledResources = $compiledResources;
$this->progressTracker = $progressTracker;
$this->stepsProgressStage = $stepsProgressStage;
}


}
13 changes: 10 additions & 3 deletions src/WordPress/Blueprints/Compile/CompiledResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@

class CompiledResource {

public $declaration;
public $resource;
public $progressTracker;

public function __construct(
public $declaration,
public ResourceDefinitionInterface $resource,
public Tracker $progressTracker,
$declaration,
ResourceDefinitionInterface $resource,
Tracker $progressTracker
) {
$this->declaration = $declaration;
$this->resource = $resource;
$this->progressTracker = $progressTracker;
}

}
13 changes: 10 additions & 3 deletions src/WordPress/Blueprints/Compile/CompiledStep.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@

class CompiledStep {

public $step;
public $runner;
public $progressTracker;

public function __construct(
public StepDefinitionInterface $step,
public StepRunnerInterface $runner,
public Tracker $progressTracker,
StepDefinitionInterface $step,
StepRunnerInterface $runner,
Tracker $progressTracker
) {
$this->step = $step;
$this->runner = $runner;
$this->progressTracker = $progressTracker;
}

}
11 changes: 8 additions & 3 deletions src/WordPress/Blueprints/Compile/StepFailure.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@

class StepFailure extends BlueprintException implements StepResultInterface {

public function __construct(
public StepDefinitionInterface $step,
/**
* @var \WordPress\Blueprints\Model\DataClass\StepDefinitionInterface
*/
public $step;
public function __construct(
StepDefinitionInterface $step,
\Exception $cause
) {
parent::__construct( "Error when executing step $step->step", 0, $cause );
$this->step = $step;
parent::__construct( "Error when executing step $step->step", 0, $cause );
}
}
7 changes: 6 additions & 1 deletion src/WordPress/Blueprints/Compile/StepSuccess.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
use WordPress\Blueprints\Model\DataClass\StepDefinitionInterface;

class StepSuccess implements StepResultInterface {
public function __construct( public StepDefinitionInterface $step, public $result ) {
public $step;
public $result;

public function __construct( StepDefinitionInterface $step, $result ) {
$this->step = $step;
$this->result = $result;
}
}
8 changes: 6 additions & 2 deletions src/WordPress/Blueprints/ContainerBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,11 @@ public function __construct() {
}


public function build( string $environment, RuntimeInterface $runtime ) {
/**
* @param string $environment
* @param \WordPress\Blueprints\Runtime\RuntimeInterface $runtime
*/
public function build( $environment, $runtime ) {
$container = $this->container;
$container['runtime'] = function () use ( $runtime ) {
return $runtime;
Expand Down Expand Up @@ -230,7 +234,7 @@ function () use ( $c ) {
$container['resource.supported_resolvers'] = function ( $c ) {
$ResourceResolvers = array();
foreach ( $c->keys() as $key ) {
if ( str_starts_with( $key, 'resource.resolver.' ) ) {
if ( 0 === strpos( $key, 'resource.resolver.' ) ) {
$ResourceResolvers[] = $c[ $key ];
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/WordPress/Blueprints/Engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ public function parseAndCompile( $raw_blueprint ) {
return $this->compiler->compile( $blueprint );
}

public function run( CompiledBlueprint $compiled_blueprint ) {
/**
* @param \WordPress\Blueprints\Compile\CompiledBlueprint $compiled_blueprint
*/
public function run( $compiled_blueprint ) {
return $this->runner->run( $compiled_blueprint );
}
}
Loading

0 comments on commit adaf722

Please sign in to comment.