Skip to content

Commit

Permalink
Merge branch '6.4' into 7.0
Browse files Browse the repository at this point in the history
* 6.4: (22 commits)
  fix merge
  [AssetMapper] Check asset/vendor directory is writable
  detect wrong e-mail validation modes
  detect wrong usages of minMessage/maxMessage in options
  [Security] Remove workflow from empty folder
  read form values using the chain data accessor
  [Validator] Review Bulgarian (bg) translation
  Reviewed italian translation
  Fix french translation
  call substr() with integer offsets
  [Finder] Also consider .git inside the basedir of in() directory
  review: FR translation
  [Serializer] Add AbstractNormalizerContextBuilder::defaultConstructorArguments()
  Update spanish and catalan translations
  Update AbstractSchemaListener.php to adjust more database params
  Updated id=113 Arabic translation.
  #53771 Updated validator Lithuanian translations
  review: translation RU
  [PropertyInfo] Fix PHPStan properties type in trait
  explicitly cast boolean SSL stream options
  ...
  • Loading branch information
xabbuh committed Apr 28, 2024
2 parents bee1999 + ea61ad3 commit ea2eafa
Show file tree
Hide file tree
Showing 36 changed files with 345 additions and 157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception\TableNotFoundException;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;

abstract class AbstractSchemaListener
Expand All @@ -22,8 +24,16 @@ abstract public function postGenerateSchema(GenerateSchemaEventArgs $event): voi
protected function getIsSameDatabaseChecker(Connection $connection): \Closure
{
return static function (\Closure $exec) use ($connection): bool {
$schemaManager = $connection->createSchemaManager();

$checkTable = 'schema_subscriber_check_'.bin2hex(random_bytes(7));
$connection->executeStatement(sprintf('CREATE TABLE %s (id INTEGER NOT NULL)', $checkTable));
$table = new Table($checkTable);
$table->addColumn('id', Types::INTEGER)
->setAutoincrement(true)
->setNotnull(true);
$table->setPrimaryKey(['id']);

$schemaManager->createTable($table);

try {
$exec(sprintf('DROP TABLE %s', $checkTable));
Expand All @@ -32,7 +42,7 @@ protected function getIsSameDatabaseChecker(Connection $connection): \Closure
}

try {
$connection->executeStatement(sprintf('DROP TABLE %s', $checkTable));
$schemaManager->dropTable($checkTable);

return false;
} catch (TableNotFoundException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\AssetMapper\ImportMap;

use Symfony\Component\AssetMapper\Exception\RuntimeException;

/**
* Manages the local storage of remote/vendor importmap packages.
*/
Expand Down Expand Up @@ -52,7 +54,9 @@ public function save(ImportMapEntry $entry, string $contents): void
$vendorPath = $this->getDownloadPath($entry->packageModuleSpecifier, $entry->type);

@mkdir(\dirname($vendorPath), 0777, true);
file_put_contents($vendorPath, $contents);
if (false === @file_put_contents($vendorPath, $contents)) {
throw new RuntimeException(error_get_last()['message'] ?? sprintf('Failed to write file "%s".', $vendorPath));
}
}

public function saveExtraFile(ImportMapEntry $entry, string $extraFilename, string $contents): void
Expand All @@ -64,7 +68,9 @@ public function saveExtraFile(ImportMapEntry $entry, string $extraFilename, stri
$vendorPath = $this->getExtraFileDownloadPath($entry, $extraFilename);

@mkdir(\dirname($vendorPath), 0777, true);
file_put_contents($vendorPath, $contents);
if (false === @file_put_contents($vendorPath, $contents)) {
throw new RuntimeException(error_get_last()['message'] ?? sprintf('Failed to write file "%s".', $vendorPath));
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,15 @@ public static function getRequirePackageTests(): iterable
];

yield 'single_package_with_a_path' => [
'packages' => [new PackageRequireOptions('some/module', path: self::$writableRoot.'/assets/some_file.js')],
'expectedProviderPackageArgumentCount' => 0,
'resolvedPackages' => [],
'expectedImportMap' => [
'some/module' => [
// converted to relative path
'path' => './assets/some_file.js',
'packages' => [new PackageRequireOptions('some/module', path: self::$writableRoot.'/assets/some_file.js')],
'expectedProviderPackageArgumentCount' => 0,
'resolvedPackages' => [],
'expectedImportMap' => [
'some/module' => [
// converted to relative path
'path' => './assets/some_file.js',
],
],
],
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class RemotePackageStorageTest extends TestCase
protected function setUp(): void
{
$this->filesystem = new Filesystem();
if (!file_exists(self::$writableRoot)) {
if (!$this->filesystem->exists(self::$writableRoot)) {
$this->filesystem->mkdir(self::$writableRoot);
}
}
Expand All @@ -41,14 +41,30 @@ public function testGetStorageDir()
$this->assertSame(realpath(self::$writableRoot.'/assets/vendor'), realpath($storage->getStorageDir()));
}

public function testSaveThrowsWhenVendorDirectoryIsNotWritable()
{
$this->filesystem->mkdir($vendorDir = self::$writableRoot.'/assets/acme/vendor');
$this->filesystem->chmod($vendorDir, 0555);

$storage = new RemotePackageStorage($vendorDir);
$entry = ImportMapEntry::createRemote('foo', ImportMapType::JS, '/does/not/matter', '1.0.0', 'module_specifier', false);

$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('file_put_contents('.$vendorDir.'/module_specifier/module_specifier.index.js): Failed to open stream: No such file or directory');
$storage->save($entry, 'any content');

$this->filesystem->remove($vendorDir);
}

public function testIsDownloaded()
{
$storage = new RemotePackageStorage(self::$writableRoot.'/assets/vendor');
$entry = ImportMapEntry::createRemote('foo', ImportMapType::JS, '/does/not/matter', '1.0.0', 'module_specifier', false);
$this->assertFalse($storage->isDownloaded($entry));

$targetPath = self::$writableRoot.'/assets/vendor/module_specifier/module_specifier.index.js';
@mkdir(\dirname($targetPath), 0777, true);
file_put_contents($targetPath, 'any content');
$this->filesystem->mkdir(\dirname($targetPath));
$this->filesystem->dumpFile($targetPath, 'any content');
$this->assertTrue($storage->isDownloaded($entry));
}

Expand All @@ -57,9 +73,10 @@ public function testIsExtraFileDownloaded()
$storage = new RemotePackageStorage(self::$writableRoot.'/assets/vendor');
$entry = ImportMapEntry::createRemote('foo', ImportMapType::JS, '/does/not/matter', '1.0.0', 'module_specifier', false);
$this->assertFalse($storage->isExtraFileDownloaded($entry, '/path/to/extra.woff'));

$targetPath = self::$writableRoot.'/assets/vendor/module_specifier/path/to/extra.woff';
@mkdir(\dirname($targetPath), 0777, true);
file_put_contents($targetPath, 'any content');
$this->filesystem->mkdir(\dirname($targetPath));
$this->filesystem->dumpFile($targetPath, 'any content');
$this->assertTrue($storage->isExtraFileDownloaded($entry, '/path/to/extra.woff'));
}

Expand Down Expand Up @@ -92,7 +109,7 @@ public function testGetDownloadedPath(string $packageModuleSpecifier, ImportMapT
$this->assertSame($expectedPath, $storage->getDownloadPath($packageModuleSpecifier, $importMapType));
}

public static function getDownloadPathTests()
public static function getDownloadPathTests(): iterable
{
yield 'javascript bare package' => [
'packageModuleSpecifier' => 'foo',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ public function __construct(\Iterator $iterator, string $baseDir)
{
$this->baseDir = $this->normalizePath($baseDir);

foreach ($this->parentDirectoriesUpwards($this->baseDir) as $parentDirectory) {
if (@is_dir("{$parentDirectory}/.git")) {
$this->baseDir = $parentDirectory;
foreach ([$this->baseDir, ...$this->parentDirectoriesUpwards($this->baseDir)] as $directory) {
if (@is_dir("{$directory}/.git")) {
$this->baseDir = $directory;
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ protected function tearDown(): void
*
* @dataProvider getAcceptData
*/
public function testAccept(array $gitIgnoreFiles, array $otherFileNames, array $expectedResult)
public function testAccept(array $gitIgnoreFiles, array $otherFileNames, array $expectedResult, string $baseDir = '')
{
$otherFileNames = $this->toAbsolute($otherFileNames);
foreach ($otherFileNames as $path) {
Expand All @@ -51,7 +51,8 @@ public function testAccept(array $gitIgnoreFiles, array $otherFileNames, array $

$inner = new InnerNameIterator($otherFileNames);

$iterator = new VcsIgnoredFilterIterator($inner, $this->tmpDir);
$baseDir = $this->tmpDir.('' !== $baseDir ? '/'.$baseDir : '');
$iterator = new VcsIgnoredFilterIterator($inner, $baseDir);

$this->assertIterator($this->toAbsolute($expectedResult), $iterator);
}
Expand All @@ -74,6 +75,55 @@ public static function getAcceptData(): iterable
],
];

yield 'simple file - .gitignore and in() from repository root' => [
[
'.gitignore' => 'a.txt',
],
[
'.git',
'a.txt',
'b.txt',
'dir/',
'dir/a.txt',
],
[
'.git',
'b.txt',
'dir',
],
];

yield 'nested git repositories only consider .gitignore files of the most inner repository' => [
[
'.gitignore' => "nested/*\na.txt",
'nested/.gitignore' => 'c.txt',
'nested/dir/.gitignore' => 'f.txt',
],
[
'.git',
'a.txt',
'b.txt',
'nested/',
'nested/.git',
'nested/c.txt',
'nested/d.txt',
'nested/dir/',
'nested/dir/e.txt',
'nested/dir/f.txt',
],
[
'.git',
'a.txt',
'b.txt',
'nested',
'nested/.git',
'nested/d.txt',
'nested/dir',
'nested/dir/e.txt',
],
'nested',
];

yield 'simple file at root' => [
[
'.gitignore' => '/a.txt',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
namespace Symfony\Component\Form\Extension\Core\DataAccessor;

use Symfony\Component\Form\DataAccessorInterface;
use Symfony\Component\Form\DataMapperInterface;
use Symfony\Component\Form\Exception\AccessException;
use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\PropertyAccess\Exception\AccessException as PropertyAccessException;
use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException;
Expand Down Expand Up @@ -51,15 +53,25 @@ public function setValue(object|array &$data, mixed $value, FormInterface $form)
throw new AccessException('Unable to write the given value as no property path is defined.');
}

$getValue = function () use ($data, $form, $propertyPath) {
$dataMapper = $this->getDataMapper($form);

if ($dataMapper instanceof DataMapper && null !== $dataAccessor = $dataMapper->getDataAccessor()) {
return $dataAccessor->getValue($data, $form);
}

return $this->getPropertyValue($data, $propertyPath);
};

// If the field is of type DateTimeInterface and the data is the same skip the update to
// keep the original object hash
if ($value instanceof \DateTimeInterface && $value == $this->getPropertyValue($data, $propertyPath)) {
if ($value instanceof \DateTimeInterface && $value == $getValue()) {
return;
}

// If the data is identical to the value in $data, we are
// dealing with a reference
if (!\is_object($data) || !$form->getConfig()->getByReference() || $value !== $this->getPropertyValue($data, $propertyPath)) {
if (!\is_object($data) || !$form->getConfig()->getByReference() || $value !== $getValue()) {
$this->propertyAccessor->setValue($data, $propertyPath, $value);
}
}
Expand Down Expand Up @@ -93,4 +105,13 @@ private function getPropertyValue(object|array $data, PropertyPathInterface $pro
return null;
}
}

private function getDataMapper(FormInterface $form): ?DataMapperInterface
{
do {
$dataMapper = $form->getConfig()->getDataMapper();
} while (null === $dataMapper && null !== $form = $form->getParent());

return $dataMapper;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,12 @@ public function mapFormsToData(\Traversable $forms, mixed &$data): void
}
}
}

/**
* @internal
*/
public function getDataAccessor(): DataAccessorInterface
{
return $this->dataAccessor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor;
use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormConfigBuilder;
use Symfony\Component\Form\FormFactoryBuilder;
Expand Down Expand Up @@ -403,6 +405,25 @@ public function testMapFormsToDataMapsDateTimeInstanceToArrayIfNotSetBefore()

$this->assertEquals(['date' => new \DateTime('2022-08-04', new \DateTimeZone('UTC'))], $form->getData());
}

public function testMapFormToDataWithOnlyGetterConfigured()
{
$person = new DummyPerson('foo');
$form = (new FormFactoryBuilder())
->getFormFactory()
->createBuilder(FormType::class, $person)
->add('name', TextType::class, [
'getter' => function (DummyPerson $person) {
return $person->myName();
},
])
->getForm();
$form->submit([
'name' => 'bar',
]);

$this->assertSame('bar', $person->myName());
}
}

class SubmittedForm extends Form
Expand Down Expand Up @@ -439,4 +460,9 @@ public function rename($name): void
{
$this->name = $name;
}

public function setName($name): void
{
$this->name = $name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ public function __construct(array $options, \Redis|Relay|\RedisCluster|null $red
throw new InvalidArgumentException('Cannot configure Redis Sentinel and Redis Cluster instance at the same time.');
}

$booleanStreamOptions = [
'allow_self_signed',
'capture_peer_cert',
'capture_peer_cert_chain',
'disable_compression',
'SNI_enabled',
'verify_peer',
'verify_peer_name',
];

foreach ($options['ssl'] ?? [] as $streamOption => $value) {
if (\in_array($streamOption, $booleanStreamOptions, true) && \is_string($value)) {
$options['ssl'][$streamOption] = filter_var($value, \FILTER_VALIDATE_BOOL);
}
}

if ((\is_array($host) && null === $sentinelMaster) || $redis instanceof \RedisCluster) {
$hosts = \is_string($host) ? [$host.':'.$port] : $host; // Always ensure we have an array
$this->redis = static fn () => self::initializeRedisCluster($redis, $hosts, $auth, $options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,14 @@ private function getDocBlockFromProperty(string $class, string $property): ?arra
return null;
}

$reflector = $reflectionProperty->getDeclaringClass();

foreach ($reflector->getTraits() as $trait) {
if ($trait->hasProperty($property)) {
return $this->getDocBlockFromProperty($trait->getName(), $property);
}
}

// Type can be inside property docblock as `@var`
$rawDocNode = $reflectionProperty->getDocComment();
$phpDocNode = $rawDocNode ? $this->getPhpDocNode($rawDocNode) : null;
Expand Down

0 comments on commit ea2eafa

Please sign in to comment.