Skip to content

Commit ccb4528

Browse files
Merge pull request #7158 from christianbeeznest/GH-7155
Internal: Add language attribute to resources - refs #7155
2 parents fcc2acf + 6102578 commit ccb4528

File tree

4 files changed

+178
-30
lines changed

4 files changed

+178
-30
lines changed

src/CoreBundle/Entity/ResourceFile.php

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,14 @@ class ResourceFile implements Stringable
138138
#[Groups(['resource_file:read', 'resource_node:read', 'document:read', 'message:read', 'personal_file:read'])]
139139
#[ORM\Column(type: 'integer')]
140140
protected ?int $size = 0;
141-
141+
/**
142+
* Optional language for the file variant.
143+
* This is used for indexing and future-proof resource variations.
144+
*/
145+
#[Groups(['resource_file:read', 'resource_node:read', 'document:read', 'personal_file:read'])]
146+
#[ORM\ManyToOne(targetEntity: Language::class)]
147+
#[ORM\JoinColumn(name: 'language_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
148+
protected ?Language $language = null;
142149
#[Vich\UploadableField(
143150
mapping: 'resources',
144151
fileNameProperty: 'title',
@@ -192,6 +199,22 @@ public function __toString(): string
192199
{
193200
return $this->getOriginalName();
194201
}
202+
/**
203+
* Get the file language (can be null if unknown/multilingual).
204+
*/
205+
public function getLanguage(): ?Language
206+
{
207+
return $this->language;
208+
}
209+
/**
210+
* Set the file language (nullable by design).
211+
*/
212+
public function setLanguage(?Language $language): self
213+
{
214+
$this->language = $language;
215+
216+
return $this;
217+
}
195218
public function isText(): bool
196219
{
197220
$mimeType = $this->getMimeType();
@@ -251,29 +274,11 @@ public function setSize(?int $size): self
251274
return $this;
252275
}
253276

254-
/*public function isEnabled(): bool
255-
* {
256-
* return $this->enabled;
257-
* }
258-
* public function setEnabled(bool $enabled): self
259-
* {
260-
* $this->enabled = $enabled;
261-
* return $this;
262-
* }*/
263277
public function getId(): ?int
264278
{
265279
return $this->id;
266280
}
267281

268-
/*public function getDescription(): string
269-
* {
270-
* return $this->description;
271-
* }
272-
* public function setDescription(string $description): self
273-
* {
274-
* $this->description = $description;
275-
* return $this;
276-
* }*/
277282
public function getMimeType(): ?string
278283
{
279284
return $this->mimeType;
@@ -308,7 +313,6 @@ public function getWidth(): int
308313
{
309314
$data = $this->getDimensions();
310315
if ([] !== $data) {
311-
// $data = explode(',', $data);
312316
return (int) $data[0];
313317
}
314318

@@ -318,7 +322,6 @@ public function getHeight(): int
318322
{
319323
$data = $this->getDimensions();
320324
if ([] !== $data) {
321-
// $data = explode(',', $data);
322325
return (int) $data[1];
323326
}
324327

src/CoreBundle/Entity/ResourceNode.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ class ResourceNode implements Stringable
107107
#[ORM\JoinColumn(name: 'resource_format_id', referencedColumnName: 'id')]
108108
protected ?ResourceFormat $resourceFormat = null;
109109

110+
/**
111+
* Optional language for the node.
112+
* This is used for indexing and future-proof resource variations.
113+
*/
114+
#[Groups(['resource_node:read', 'document:read', 'personal_file:read'])]
115+
#[ORM\ManyToOne(targetEntity: Language::class)]
116+
#[ORM\JoinColumn(name: 'language_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
117+
protected ?Language $language = null;
118+
110119
/**
111120
* @var Collection<int, ResourceLink>
112121
*/
@@ -246,6 +255,24 @@ public function setCreator(?User $creator): self
246255
return $this;
247256
}
248257

258+
/**
259+
* Get the node language (can be null if unknown/multilingual).
260+
*/
261+
public function getLanguage(): ?Language
262+
{
263+
return $this->language;
264+
}
265+
266+
/**
267+
* Set the node language (nullable by design).
268+
*/
269+
public function setLanguage(?Language $language): self
270+
{
271+
$this->language = $language;
272+
273+
return $this;
274+
}
275+
249276
/**
250277
* Returns the children resource instances.
251278
*
@@ -351,15 +378,6 @@ public function getPathForDisplayRemoveBase(string $base): string
351378
*/
352379
public function convertPathForDisplay(string $path): string
353380
{
354-
/*$pathForDisplay = preg_replace(
355-
'/-\d+'.self::PATH_SEPARATOR.'/',
356-
' / ',
357-
$path
358-
);
359-
if ($pathForDisplay !== null && strlen($pathForDisplay) > 0) {
360-
$pathForDisplay = substr_replace($pathForDisplay, '', -3);
361-
}
362-
*/
363381
$pathForDisplay = preg_replace('/-\d+\\'.self::PATH_SEPARATOR.'/', '/', $path);
364382
if (null !== $pathForDisplay && '' !== $pathForDisplay) {
365383
$pathForDisplay = substr_replace($pathForDisplay, '', -1);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/* For licensing terms, see /license.txt */
6+
7+
namespace Chamilo\CoreBundle\Migrations\Schema\V200;
8+
9+
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
10+
use Doctrine\DBAL\Schema\Schema;
11+
12+
final class Version20200101020000 extends AbstractMigrationChamilo
13+
{
14+
public function getDescription(): string
15+
{
16+
return 'Add language_id foreign keys to resource_node and resource_file (nullable, for indexing and variants).';
17+
}
18+
19+
public function up(Schema $schema): void
20+
{
21+
// resource_node.language_id
22+
$this->addSql('ALTER TABLE resource_node ADD language_id INT DEFAULT NULL');
23+
$this->addSql('ALTER TABLE resource_node ADD CONSTRAINT FK_8A5F48FF82F1BAF4 FOREIGN KEY (language_id) REFERENCES language (id) ON DELETE SET NULL');
24+
$this->addSql('CREATE INDEX IDX_8A5F48FF82F1BAF4 ON resource_node (language_id)');
25+
26+
// resource_file.language_id
27+
$this->addSql('ALTER TABLE resource_file ADD language_id INT DEFAULT NULL');
28+
$this->addSql('ALTER TABLE resource_file ADD CONSTRAINT FK_83BF96AA82F1BAF4 FOREIGN KEY (language_id) REFERENCES language (id) ON DELETE SET NULL');
29+
$this->addSql('CREATE INDEX IDX_83BF96AA82F1BAF4 ON resource_file (language_id)');
30+
}
31+
32+
public function down(Schema $schema): void
33+
{
34+
// Drop resource_node FK/index/column
35+
$this->addSql('ALTER TABLE resource_node DROP FOREIGN KEY FK_8A5F48FF82F1BAF4');
36+
$this->addSql('DROP INDEX IDX_8A5F48FF82F1BAF4 ON resource_node');
37+
$this->addSql('ALTER TABLE resource_node DROP language_id');
38+
39+
// Drop resource_file FK/index/column
40+
$this->addSql('ALTER TABLE resource_file DROP FOREIGN KEY FK_83BF96AA82F1BAF4');
41+
$this->addSql('DROP INDEX IDX_83BF96AA82F1BAF4 ON resource_file');
42+
$this->addSql('ALTER TABLE resource_file DROP language_id');
43+
}
44+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/* For licensing terms, see /license.txt */
6+
7+
namespace Chamilo\CoreBundle\Migrations\Schema\V200;
8+
9+
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
10+
use Doctrine\DBAL\Schema\Schema;
11+
12+
final class Version20251212104300 extends AbstractMigrationChamilo
13+
{
14+
public function getDescription(): string
15+
{
16+
return 'Prefill resource_node.language_id from course language and copy it to resource_file.language_id when missing.';
17+
}
18+
19+
public function up(Schema $schema): void
20+
{
21+
// Decide whether we can join directly via resource_node.cid (preferred)
22+
// or need a fallback via resource_link.c_id (when cid is not present).
23+
$hasCid = false;
24+
25+
if ($schema->hasTable('resource_node')) {
26+
$table = $schema->getTable('resource_node');
27+
$hasCid = $table->hasColumn('cid');
28+
}
29+
30+
if ($hasCid) {
31+
// Preferred: "created in course" is stored on resource_node.cid
32+
$sqlNode = <<<SQL
33+
UPDATE resource_node rn
34+
INNER JOIN course c ON c.id = rn.cid
35+
INNER JOIN language l ON l.isocode = c.course_language
36+
SET rn.language_id = l.id
37+
WHERE rn.language_id IS NULL
38+
AND rn.cid IS NOT NULL
39+
AND c.course_language IS NOT NULL
40+
AND c.course_language <> ''
41+
SQL;
42+
$this->addSql($sqlNode);
43+
} else {
44+
// Fallback: infer a course from existing links (best-effort).
45+
// We pick MIN(c_id) per resource_node_id to have a deterministic choice.
46+
$sqlNode = <<<SQL
47+
UPDATE resource_node rn
48+
INNER JOIN (
49+
SELECT rl.resource_node_id, MIN(rl.c_id) AS c_id
50+
FROM resource_link rl
51+
WHERE rl.c_id IS NOT NULL
52+
GROUP BY rl.resource_node_id
53+
) x ON x.resource_node_id = rn.id
54+
INNER JOIN course c ON c.id = x.c_id
55+
INNER JOIN language l ON l.isocode = c.course_language
56+
SET rn.language_id = l.id
57+
WHERE rn.language_id IS NULL
58+
AND c.course_language IS NOT NULL
59+
AND c.course_language <> ''
60+
SQL;
61+
$this->addSql($sqlNode);
62+
}
63+
64+
// Copy node language to files when file language is not set yet.
65+
$sqlFile = <<<SQL
66+
UPDATE resource_file rf
67+
INNER JOIN resource_node rn ON rn.id = rf.resource_node_id
68+
SET rf.language_id = rn.language_id
69+
WHERE rf.language_id IS NULL
70+
AND rn.language_id IS NOT NULL
71+
SQL;
72+
73+
$this->addSql($sqlFile);
74+
}
75+
76+
public function down(Schema $schema): void
77+
{
78+
// remove language inference.
79+
// Note: if later you start setting languages explicitly, a rollback would also unset them.
80+
$this->addSql('UPDATE resource_file SET language_id = NULL');
81+
$this->addSql('UPDATE resource_node SET language_id = NULL');
82+
}
83+
}

0 commit comments

Comments
 (0)