Symfony Fixtures - Get Random Entity Instance - symfony

I am trying to load fixtures into my database. I have a post entity and a category entity, and a category can have many posts.
In my fixtures file I would like to create some categories and then assign a random category to each post, but I am not sure how to do this.
How can I get a reference to a random category?
<?php
namespace App\DataFixtures;
use App\Entity\Category;
use App\Entity\User;
use App\Entity\Post;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\EntityManager;
use Faker\Factory;
use Faker\Generator;
class AppFixtures extends Fixture
{
private $faker;
public function load(ObjectManager $manager)
{
$this->faker = Factory::create();
$this->addUsers($manager);
$this->addCategories($manager);
$this->addPosts($manager);
$manager->flush();
}
private function addUsers(EntityManager $em)
{
for ($i = 1; $i <= 10; $i++) {
$user = new User();
$firstname = $this->faker->firstName;
$lastname = $this->faker->lastName;
$user->setFirstName($firstname);
$user->setLastName($lastname);
$user->setEmail($firstname.'.'.$lastname.'#gmail.com');
$user->setRoles(['ROLE_USER']);
$em->persist($user);
$this->addPosts($user);
}
}
private function addCategories(EntityManager $em)
{
$categoryHome = new Category();
$categoryHome->setName('Home');
$em->persist($categoryHome);
$categoryWork = new Category();
$categoryWork->setName('Work');
$em->persist($categoryWork);
}
public function addPosts(EntityManager $em, User $user){
for ($i = 1; $i <= 10; $i++) {
$post = new Post();
$post->setUser($user);
// How can I assign the category randomly?
$post->setCaterory(????)
$em->persist($post);
}
}
}

If you need to create random data (for example for presentation) I think better choice would be using AliceBundle https://github.com/hautelook/AliceBundle which can do this out of box via relations. Plus it will be same on every load of fixtures.
But to answer your question. You make list of categories you created and then just choose one randomly.
<?php
namespace App\DataFixtures;
use App\Entity\Category;
use App\Entity\User;
use App\Entity\Post;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\EntityManager;
use Faker\Factory;
use Faker\Generator;
class AppFixtures extends Fixture
{
private $faker;
private $categories;
public function load(ObjectManager $manager)
{
$this->faker = Factory::create();
$this->addUsers($manager);
$this->addCategories($manager);
$this->addPosts($manager);
$manager->flush();
}
private function addUsers(EntityManager $em)
{
for ($i = 1; $i <= 10; $i++) {
$user = new User();
$firstname = $this->faker->firstName;
$lastname = $this->faker->lastName;
$user->setFirstName($firstname);
$user->setLastName($lastname);
$user->setEmail($firstname.'.'.$lastname.'#gmail.com');
$user->setRoles(['ROLE_USER']);
$em->persist($user);
$this->addPosts($user);
}
}
private function addCategories(EntityManager $em)
{
$categoryHome = new Category();
$categoryHome->setName('Home');
$em->persist($categoryHome);
$this->categories[] = $categoryHome;
$categoryWork = new Category();
$categoryWork->setName('Work');
$em->persist($categoryWork);
$this->categories[] = $categoryWork;
}
public function addPosts(EntityManager $em, User $user){
for ($i = 1; $i <= 10; $i++) {
$post = new Post();
$post->setUser($user);
$post->setCaterory($this->categories[rand(0, count($this->categories))]);
$em->persist($post);
}
}
}

In AddPost Function Add this
public function addPosts(EntityManager $em, User $user){
$categories = $manager->getRepository(Category::class)->findAll();
for ($i = 1; $i <= 10; $i++) {
$post = new Post();
$post->setUser($user);
$category = $categories[array_rand($categories)];
$post->setCategory($category)
$em->persist($post);
}
}
}

Related

I have troube with symfony fixtures

I discovered the symfony framework for a short time. and there, I'm stuck at the fixture level. I managed to create category fixtures, but I can't manage with the product fixtures. If anyone can help, that would be nice.
namespace App\DataFixtures;
use App\Entity\Category;
use App\Entity\Product;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
for ( $i = 1 ; $i <= 10 ; $i++){
$category = new Category();
$category ->setName("category".$i);
$category ->setImage("road to pic".$i);
$manager ->persist($category);
}
$manager ->flush($category);
$productRepo = $manager->getRepository(Product::class);
$allCategory = $productRepo->findAll();
for ( $i = 1 ; $i <= 200 ; $i++){
$product = new Product();
$product ->setName("product".$i);
$product ->setImage("road to pic".$i);
$product ->setPrice(rand(1, 100));
$product ->setStock(rand(1,10));
$product ->setDescription("description".$i);
$product ->setCategory($allCategory[1]);
$manager -> persist($product);
}
$manager->flush($product);
}
}
You are getting the list of categories incorrectly in your example.
Instead of this
$productRepo = $manager->getRepository(Product::class);
$allCategory = $productRepo->findAll();
Use it
$allCategory = $manager->getRepository(Category::class)->findAll();

How to use DI in a fixture class

I want to create a fixture for categories, but I get the error
Could you elaborate on how di works in Symfony. The documentation didn't tell me much.
in config / services.yaml the standard code is already specified which seems to solve the di problem
class CategoryFixtures extends \Doctrine\Bundle\FixturesBundle\Fixture
{
private $category;
public function __construct(
\App\Entity\Category $category
) {
$this->category = $category;
}
public function load(\Doctrine\Persistence\ObjectManager $manager)
{
$this->addMainCategories($manager);
}
private function addMainCategories($manager) {
$mainCategoriesArray = ['111', '222', '333', '444', '555'];
foreach ($mainCategoriesArray as $categoryName) {
$this->category->setName($categoryName);
$manager->persist($this->category);
}
$manager->flush();
}
}
Error
Cannot autowire service "App\DataFixtures\CategoryFixtures": argument "$category" of method "__construct()" references class "App\Entity\Category" but no such service exists.
DI isn't really the issue here.
Untested code to create 5 Category entities:
use App\Entity\Category;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Persistence\ObjectManager;
// Creates Category entities Category0, Category1...
class CategoryFixtures extends AbstractFixture
{
private $mainCategoriesArray = ['111', '222', '333', '444', '555'];
public function load(ObjectManager $manager)
{
for ($i = 0; $i < 5; $i++) {
$name = 'Category' . $i;
$$name = new Category();
$$name->setName($this->mainCategoriesArray[$i]);
$manager->persist($$name);
}
$manager->flush();
}
}

Symfony/FOSUserBundle: Load an existing User from database in Fixtures

My problem comes from the fact that i have a relation in my entities that depends on each other. My entity Link has a relation with an entity User. When I try to load the User using UserManagerInterface it returns NULL.
Here is My AppFixtures class:
<?php
namespace App\DataFixtures;
use App\Component\Localization;
use App\Entity\Link;
use App\Entity\LinkClick;
use App\Entity\LinkView;
use App\Entity\Visitor;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
use Faker;
use FOS\UserBundle\Model\UserManagerInterface;
use PUGX\Shortid\Shortid;
class AppFixtures extends Fixture
{
private $userManager;
private $localisation;
public function __construct(UserManagerInterface $userManager, Localization $localization)
{
$this->userManager = $userManager;
$faker = Faker\Factory::create();
$localization->setParameters($localization::GEO_PLUGIN, $faker->ipv4);
$localization->localize();
$this->localisation = $localization->getResult();
}
public function load(ObjectManager $manager): void
{
$faker = Faker\Factory::create();
$user = $this->userManager->createUser();
$user->setUsername('admin');
$user->setEmail('admin#kss.tk');
$user->setPlainPassword('admin');
$user->setEnabled(true);
$user->setRoles(['ROLE_ADMIN']);
$this->userManager->updateUser($user);
$links = [];
$visitors = [];
for ($i = 0; $i < 100; ++$i) {
$link = new Link();
$link->setUrl($faker->url);
$link->setSlug(Shortid::generate(12, 'abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01', true));
$link->setCreatedAt($faker->dateTime);
$link->setUser($user);
$links[] = $link;
$manager->persist($link);
}
for ($i = 0; $i < 10000; ++$i) {
$visitor = new Visitor();
$visitor->setIp($this->localisation->geoplugin_request);
$visitor->setCountryCode($this->localisation->geoplugin_countryCode);
$visitor->setCountryName($this->localisation->geoplugin_countryName);
$visitors[] = $visitor;
$manager->persist($visitor);
}
for ($i = 0; $i < 10000; ++$i) {
$linkView = new LinkView();
$linkView->setDate($faker->dateTimeBetween('-1 years', 'now'));
$linkView->setVisitor($visitors[rand(0, 999)]);
$linkView->setLink($links[rand(0, 99)]);
$manager->persist($linkView);
}
for ($i = 0; $i < 10000; ++$i) {
$linkClick = new LinkClick();
$linkClick->setDate($faker->dateTimeBetween('-1 years', 'now'));
$linkClick->setVisitor($visitors[rand(0, 999)]);
$linkClick->setLink($links[rand(0, 99)]);
$manager->persist($linkClick);
}
$manager->flush();
}
}
I dont want to flush the database everytime, i want to use and existing user, so i can append fixtures. Right now it throws an error:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'admin' for key 'UNIQ_1483A5E992FC23A8'

Fixtures + Migrations Doctrine, Symfony

I want to create fixture, that generate 10 records in my table (test0-test9), then create migration, wherein I need to rename records, that was created by fixture to (category0-category9).
I have created this fixture:
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager)
{
for ($i = 0; $i < 10; $i++)
{
$product = new Category();
$product->setName('test '.$i);
$id = mt_rand(89,140);
$parent = $manager->getRepository(Category::class)->find($id);
$product->setParent($parent);
$manager->persist($product);
}
$manager->flush();
}
}
But how I can rename this records in doctrine using migration? Any idea?
* I think, I need to create sql queries directly in my migration class...or not
UPDATE
I try to do this, but I think it is bad solution...
public function postUp(Schema $schema)
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
for ($i = 0; $i < 10; $i++)
{
$category = 'category '.$i;
$test = 'test'.$i;
$this->addSql('UPDATE category SET NAME = '.$category.' WHERE NAME = '.$test );
}
}
You can inject the entity manager inside your migration.
Then you can find the object you want to change and change it.
I hope this answers your question
Example:
public function postUp(Schema $schema)
{
$em = $this->container->get('doctrine.orm.entity_manager');
$products = $em->getRepository(Product::class)
->getProductsCustomQuery();
foreach($product as $products){
$product->setName(Whatever);
}
$em->flush();
}
Check this link

Symfony2 get parameters.yml in entity, special case

I know its against the framework to make an entity container aware, but this is a special case, i have a credit card entity, and i want to do this:
/**
* #return mixed
*/
public function getNumber()
{
$number = $this->number;
$crypt = base64_decode($number);
$number = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $crypt, MCRYPT_MODE_ECB);
return trim($number);
}
/**
* #param $number
* #return $this
*/
public function setNumber($number)
{
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $number, MCRYPT_MODE_ECB);
$number = trim(base64_encode($crypt));
$this->number = $number;
return $this;
}
And i want the $key to be the secret from parameters.yml, since i dont want to save it in the code.
I can't pass it as a parameter, when i use the FormType, cause the form type will not pass it when it binds the request.
$credit_card = new CreditCard();
$credit_card->setCustomer($customer);
$payment_form = $this->createPaymentForm($credit_card);
$payment_form->handleRequest($request);
Remove data modifications from your Entity, and add it to your FormType.
public function getNumber()
{
return $this->number;
}
public function setNumber($number)
{
$this->number = $number;
return $this;
}
Make your FormType take the parameter as argument.
class CreditCardType extends AbstractType {
private $key;
public function __construct($key) {
$this->key = $key;
}
// ...
// Listen on the PRE_BIND event to update your value before binding
$builder->addEventListener(FormEvents::PRE_BIND, function (FormEvent $event)
{
$data = $event->getData();
$number = $data['number'];
$crypt = $this->encryptNumber($number);
$data['number'] = $crypt;
$event->setData($data);
});
public function encryptNumber($key, $number)
{
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $number, MCRYPT_MODE_ECB);
$number = trim(base64_encode($crypt));
return $number;
}
}
Now, in your createPaymentForm, add the parameter to your FormType instance, like this :
$param = $this->container->getParameter('yourkeyparam');
$form = $this->createForm(new CreditCardType($param), $credit_card, array());
Hope this is what you need.

Resources