Im using SilverStripe4 and the ModelAdmin to manage DataObjects.
The DataObject has a has_one on File. Everything works so far but on frontend controller the File relation has an empty object.
I see that the file is not in the File_Live table, so i guess its not published and therefor its not found on the frontend controller.
How can i publish File relations from the ModelAdmin?
Basically when a file is uploaded it should be automatically published.
I guess if i use versioned DataObjects i would still need something like this: https://github.com/drzax/silverstripe-bits/tree/master/VersionedModelAdmin
to have publish mechanism on ModelAdmin.
Or is there something builtin in SS4?
Would this cascade down to File relations as well?
Edit:
regarding versioned DataObjects there is a built in publish button in SS4
just use:
private static $extensions = [
Versioned::class,
];
private static $versioned_gridfield_extensions = true;
You can add the following to your DataObject:
private static $owns = ['FileRelationName'];
Example with a relation:
private static $has_one = ['File' => File::class];
private static $owns = ['File'];
Any related object that is being declared as "owned" in this way will be published with the DataObject itself.
Related
So my question is very specific but I couldn't figure out how to make it even after several months of reflection. The following topic will be about Symfony, Doctrine and generating fixtures on-the-go for the tests.
I want to generate fixtures on the go from a test. The goal is to provide a very specific set of fixtures for each tests using helpers without sacrify the readability. That is the goal, so my idea was to create a tests/Resources/EntityProxy which is a mirror of the src/Entity folder, containing the same amount of classes with the exact same name. Each EntityProxy extends from its related Entity, use a custom trait to fill the properties easily.
You guessed it, I want to only use in tests the EntityProxy and use it directly into the functions to tests them. And there is a major issue with that, as Doctrine doesn't recognize the EntityProxy as an entity even if it extends from a real Entity.
Is there a way to say to Doctrine to persist an EntityProxy as its extended Entity?
__
The following code is an example of what I want as en EntityProxy:
namespace Tests\Resources\EntityProxy;
class User extends App\Entity\User
{
use FixtureGenerationTrait;
public function static makeDefault(): self
{
return static::generate([
'username' => self::getFaker()->username,
'email' => self::getFaker()->email,
...
]);
}
public function static make(array $data = []): self
{
$entity = static::makeDefault();
$entity = static::setValues($entity, $data);
return $entity;
}
}
And can be used in the tests like following: User::make(['name' => 'John Wick']);
In the Silverstripe 4 docs the possiblity to use a BLOB or s3 storage is mentioned (https://www.silverstripe.org/learn/lessons/v4/working-with-files-and-images-1)
But I cannot find any documention how to handle a BLOB storage. Is this only about configuration or is some implementation required? Are there examples?
You can create a custom DBField class for BLOB.
Here is the example DBBlobField class works in SS 4.2 with MariaDB.
use SilverStripe\ORM\DB;
use SilverStripe\ORM\FieldType\DBField;
class DBBlobField extends DBField
{
function requireField()
{
DB::require_field($this->tableName, $this->name, "mediumblob");
}
}
mediumblob is the BLOB type supported by your database.
Define the $db field in DataObject.
private static $db = [
"Data" => DBBlobField::class
];
Save file content into Data field.
$dataObject->Data = file_get_contents($filePath);
$dataObject->write();
I have a Symfony project that is using the DoctrineMigrations bundle, and I have a really simple question: When I run a migration (e.g., when I'm pushing an update to production), how can I insert data to the database?
For example: I have an Entity which is the type of an add. The entity is:
private $addType; // String
private $type1; // Boolean
private $type2; // Boolean
private $type3; // Boolean
I add another field ($type4), and I want to add a new record to the database, with this values:
$addType = 'Type number 4';
$type1 = false;
$type2 = false;
$type3 = false;
$type4 = true;
How can this be done with DoctrineMigrations? Is it possible?
Using the Entity Manager as suggested in another answer is not a good idea, as it leads to troubles later.
In the first migration, I created a table with users and populated some users via $em->persist($user); which seemed fine at the beginning.
But after a month, I added a phone column to my User model. And Doctrine generates INSERT statements with this column within the first migration, which fails due to the non-existing column phone. Of course it doesn't exist yet in the first migration. So it is better to go with pure SQL INSERTs.
I just asked a related related question.
It is possible to use the migrations bundle to add data to the database. If you add a new property and use the doctrine mapping then the
php app/console doctrine:migrations:diff
command will generate a new migration file. You can just put your insert statements inside this file using the syntax:
$this->addSql('INSERT INTO your_table (name) VALUES ("foo")');
Make sure you put it after the auto-generated schema changes though. If you want to separate your schema changes and your data changes then you can use
php app/console doctrine:migrations:generate
to create an empty migrations file to put your insert statements in.
Like I said in my related question, this is one way to do it, but it requires manually creating these if you want to change this data in the database.
Edit:
Since this answer seems to get a few views I think it's worth adding that to more clearly separate the data changes from the schema changes there is a postUp method that can be overridden and that will be called after the up method.
https://www.doctrine-project.org/projects/doctrine-migrations/en/3.0/reference/migration-classes.html#postup
I've "found" the correct way to solve my problem (insert data after running migrations, using my entity classes).
Here is: https://stackoverflow.com/a/25960400
The idea is to declare the migration as ContainerAware, and then, from the postUp function, call the DI to get the EntityManager. It's really easy, and you can use all your entities and repositories.
// ...
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Version20130326212938 extends AbstractMigration implements ContainerAwareInterface
{
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function up(Schema $schema)
{
// ... migration content
}
public function postUp(Schema $schema)
{
$em = $this->container->get('doctrine.orm.entity_manager');
// ... update the entities
}
}
when you make the new field you need to enter this annotation "options={"default":1}" and it should work.
/**
* #var boolean
* #ORM\Column(name="type4", type="boolean", options={"default":1})
*/
private $type4 = true;
Took me some time to figure this out :)
It does, if you know how to format the array;
$this->connection->insert('user', ['id' => 1, 'gender' => 'Male']);
this is good solution for me. Just use bin/console make:migration and when migration is generated just edit if and add "DEFAULT TRUE":
$this->addSql('ALTER TABLE event ADD active TINYINT(1) NOT NULL DEFAULT TRUE');
It doesn't sound a good idea to fill date in migration, not its responsibility, symfony has a way of doing that. https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html
I'm trying to access private properties of an entity from his own repository. By doing PHP tells me I can not access private or protected properties or methods.
I'm just calling a custom repository method created by me, passing an instance of the entity. When i try to get the ID for example, php throws me the error.
How I can access it?
public function customMethod($entityInstance)
{
$query = $this->getEntityManager()
->createQuery(
'SELECT c
FROM AcmeMainBundle:Content c
WHERE
c.published = 1
AND
c.id != :id
ORDER BY c.date DESC'
)
->setParameter('id',$entityInstance->id);
return $query->getResult();
}
This is an example of the custom method of my repository. Obviously is just an example, that DQL is not very usefull but when I try to access to $entityInstance->id ...
Can someone helps me?
The relationship between a Repository and an Entity is conceptual, not structural. This means that although you know they are related, PHP doesn't.
If you want to access private members of the Entity from the Repository you will have to do it like with any other class: using getters and setters.
Try this:
->setParameter('id', $entityInstance->getId());
Well, as with all normal PHP scripts, if you want to access a private or protected property you have to create a getter. DQL isn't changing anything from the PHP site, it only adds minor changes to the SQL syntax (which is just a string in PHP).
So actually, I don't see what you're trying to say with this question. That DQL should change the way PHP and OO works?
I'm using Doctrine 2 in a Symfony 2 environment.
I've created a custom data type which extends \Doctrine\DBAL\Types\Type. This data type should map an integer value stored in database to a specific string (like ENUM, but integer and string must be accessible).
At the moment the mapping of these values is hardcoded within the doctrine type using a class variable which holds and array.
class xyType extends \Doctrine\DBAL\Types\Type {
public static $messageTypes = array(
10 => "Wareneingang",
20 => "Polstern",
.
.
.
}
.
.
}
Now I want to put this array into the config.yml of this bundle. But I don't know how to use Dependency Injection in this type class, to be able to access my config parameters in any way...
I hope you can help me. I'm also open for other ideas to implement this.
Thx in advance
Yes, you cannot access DI in your type class, but there is bundle initialization stage where you can save your types from config to your static property. So i suggest using YourBundleExtension to solve this.