Symfony 2 Variable Entity Naming - symfony

I feel like this shouldn't be to hard, but try as I might, I keep getting errors.
What I'm wanting to do, is to have a single "add" function that will handle the basic functionality of adding records to any / all tables. Basically, the post data will contain the table name, as well as the fields / values to be inserted. The controller itself, confirms the user has access to do these things, and then verifies the fields are valid, before creating a new instance of the entity, that's where things go haywire:
$entityName = 'Products';
$row = new $entityName(); //doesn't work
$row new Products(); //works
I haven't found a way or any examples of creating a new entity using the Entity Manager, or else that might work, because i've created functions using EM to do queries, updates, and deletes, but I just can't get this to work with the add functions.

1. Your problem is almost certainly namespacing (see below). Try this instead:
$entityName = 'My\Bundle\Entity\Products';
$row = new $entityName();
Should work. ;)
2. If you want to create new instances using an EntityManager, try this:
$entityName = 'My\Bundle\Entity\Products';
$row = $em->getClassMetadata($entityName)->newInstance();
...assuming $em is your EntityManager. :-)
3. To "prove" that your problem is namespacing, try this in a plain .php file that you run from the command line:
namespace Foo;
class Test {}
$class1 = 'Foo\Test';
$class2 = 'Test';
$x = new Test(); // Will work
$y = new $class1(); // Will work
$z = new $class2(); // Will trigger "Class 'Test' not found" fatal error

Two things:
Try with "Products" instead of 'Products'
I suppose that your entity Products has a namespace, it is required (even if you declared an use statement). So try with "My\Bundle\Entity\Products".

Related

How does persist work in Symfony?

I am new to Symfony, and I could not find an answer on the official site.
Can I use one variable to persist more then once ?
For example:
for ($i = 0; $i < count($allArea); $i++) {
$area = new Area();
$area->setValue($i);
$em->persist($area);
}
$em->flush();
The persist($area) call tells Doctrine to "manage" the $area object. This does not cause a query to be made to the database.
When the flush() method is called, Doctrine looks through all of the objects that it's managing to see if they need to be persisted to the database.
So basically in this case use flush() inside the loop or, if you want to use it once outside - create new 'area' obejects and do use the same $area.

FOSUserBundle setExpiresAt($date) doesn't work?

I want to modify the expires_at of my client , when i do persist($client) and flush(); every method works fine except setExpiresAt() it doesn't change the value in table.
$client = $em->getRepository('ClientBundle:Client')->FindClient($id);
$expiresat = $client->getExpiresAt(); // the can see the (*)
$expiresat->modify($durationcontract);
$client->setExpiresAt($expiresat);
// $durationcontract can be 6 months or one year
$client->setDuration($durationcontract);
$em->persist($client);
$em->flush();
(*) this method doesn't exist in Class User or the FOSUserBundle its created by me. you can see it here
Maybe Doctrine doesn't see the difference between objects.
So, try this:
$expiresat = $client->getExpiresAt();
$expiresat = clone $expiresat;
$expiresat->modify($durationcontract);
$client->setExpiresAt($expiresat);

Add data when running Symfony migrations

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

Symfony2, Doctrine, Updation OneToMany entries

i have function
private function updateCharacters($oApiKeyInfo) // argument is base entity
{
$aXmlCharacter = $this->fXml->getXmlRowset($this->oXml, 'row');
// insert new
foreach ($aXmlCharacter as $oXmlCharacter)
{
$loopData = $this->fXml->getXmlAttributesAsArray($oXmlCharacter);
$oApiKeyInfoCharacters = new apiKeyInfoCharacters();
$oApiKeyInfoCharacters
->setKeyID($this->keyID)
->setCharacterID($loopData['characterID'])
->setCharacterName($loopData['characterName'])
->setCorporationID($loopData['corporationID'])
->setCorporationName($loopData['corporationName'])
->set_apiKeyInfo_byKeyID($oApiKeyInfo);
$this->em->persist($oApiKeyInfoCharacters);
}
// $this->em->flush() is in main (public) function
}
but, it creates dublicates... and i want that in db was ONLY that entries that is in $aXmlCharacter (array), others must be deleted
now code above is only adding new entries, but i need remove previous
can someone help to deal with it? and please show working examples
Dublicate entries i can not see any definition for uniquenes.
Deleting an Object vom database is simple as the documentation shows.
$product = $em->getRepository('YourBundle::apiKeyInfoCharacters')->find($id);
$em->remove($product);
$em->flush();
But why do you want to delete the existing one instead of updating?

Silverstripe 3 query with variable

I have used the following query in Silverstripe 2.x projects:
$obj = DataObject::get_one('Post', "\"URLSegment\" = '$segment'")
Does anyone know how I would replicate this query in the new ORM?
I have tried :
$obj = Post::get()->filter("\"URLSegment\" = '$segment'")
$obj = Post::get()->where("\"URLSegment\" = '$segment'")
And neither appear to work.
Thanks!
The issue you're having is that DataObject::get() will return a collection of objects, whereas DataObject::get_one() will return a single object of the specified class. The Silverstripe 3 equivalent is:
$obj = Post::get()->where("\"URLSegment\" = '$segment'")->First();
With this scenario (as with SS2) you would need to make sure you're explicitly taking care escaping to avoid injection vulnerabilities. However the filter function will now take care of that for you. So what you really want now is:
$obj = Post::get()->filter('URLSegment', $segment)->First();
The related documentation is at: http://doc.silverstripe.org/framework/en/topics/datamodel
DataList::create('Post')->filter(array('URLSegment' => $segment))->First();
will also work.

Resources