according to Symfony 3 docs after running 3 commands:
php bin/console doctrine:mapping:import --force AcmeBlogBundle xml
php bin/console doctrine:mapping:convert annotation ./src
php bin/console doctrine:generate:entities AcmeBlogBundle
I should get the result of something like:
// src/Acme/BlogBundle/Entity/BlogComment.php
namespace Acme\BlogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Acme\BlogBundle\Entity\BlogComment
*
* #ORM\Table(name="blog_comment")
* #ORM\Entity
*/
class BlogComment
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="bigint")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string $author
*
* #ORM\Column(name="author", type="string", length=100, nullable=false)
*/
private $author;
.....
unfortunately instead of I get roughly mapped class with getters and setters looking like so:
<?php
namespace Clashers\PanelBundle\Entity;
/**
* Users
*/
class Users
{
/**
* #var string
*/
private $username;
/**
* Set username
*
* #param string $username
*
* #return Users
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Get username
*
* #return string
*/
public function getUsername()
{
return $this->username;
}
Does any of you have faced such an issue and have solved it with no need to manually assign every property to DB type, column?
Is there any Doctrine setting(s) I've missed to generate those entities properly?
OK, problem solved. I've just rerun once again those command and somehow I've just missed an error that was caused by having already created Users entity. This will likely prevent Doctrine from creating other entities and running last command
php bin/console doctrine:generate:entities AcmeBlogBundle
without fully processed
php bin/console doctrine:mapping:convert annotation ./src
will end up with missing annotations like I've had.
Related
am getting this error when seeding data into my database. apparently the I have 2 models bookings and bookingstatus model.the bookingstatus seeder is working well and is seeding the status very well but when it comes to the bookings the data is unable to seed.this is the error that pops up
ErrorException
Undefined variable:
at F:\Main Server\htdocs\voskillproject\database\seeders\BookingsSeeder.php:73
69▕ 'event_details'=>'we would like to book you for a wedding'
70▕
71▕ ]);
72▕ $Approved->bookingstatus()->attach($Approvedstatus);
➜ 73▕ $Cancelled->bookingstatus()->attach($$Cancelledstatus);
74▕ $DepositPaid->bookingstatus()->attach($DepositPaidstatus);
75▕ $Published->bookingstatus()->attach($Publishedstatus);
76▕ }
77▕ }
1 F:\Main Server\htdocs\voskillproject\database\seeders\BookingsSeeder.php:73
Illuminate\Foundation\Bootstrap\HandleExceptions::handleError("Undefined variable: ", "F:\Main Server\htdocs\voskillproject\database\seeders\BookingsSeeder.php")
2 F:\Main Server\htdocs\voskillproject\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php:36
Database\Seeders\BookingsSeeder::run()
this is my BookingsFactory
<?php
namespace Database\Factories;
use App\Models\Bookings;
use Illuminate\Database\Eloquent\Factories\Factory;
class BookingsFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Bookings::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'is_booking'=>0,
'full_name'=>$this->faker->unique()->name,
'location'=>$this->faker->location,
'phone'=>$this->faker->number,
'is_booking'=>3,
'email'=>$this->faker->safeEmail,
'date'=>$this->faker->date,
'event_id'=>$this->faker->event_id,
'event_details'=>$this->faker->paragraph,
];
}
}
this is my database seeder
<?php
namespace Database\Seeders;
use App\Models\Role;
use App\Models\Bookingstatus;
use Illuminate\Database\Seeder;
use Database\Seeders\RoleSeeder;
use Database\Seeders\Userseeder;
use Database\Seeders\BookingsSeeder;
use Database\Seeders\BookingstatusSeeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
$this->call([
BookingsSeeder::class,
BookingstatusSeeder::class,
]);
\App\Models\Bookingstatus::factory()->hasbookings(10)->create();
}
}
i have not understood where ie gone wrong in the code
i figure out where the issue was
1.first on the bookings factory i have to change the faker details to this
return [
'is_booking'=>0,
'full_name'=>$this->faker->unique()->name,
'location'=>$this->faker->address,
'phone'=>$this->faker->numerify('###-###-####'),
'is_booking'=>3,
'email'=>$this->faker->safeEmail,
'date'=>$this->faker->unique()->dateTime()->format('Y/m/d'),
'event_id'=>$this->faker->randomDigit(),
'event_details'=>$this->faker->paragraphs(2, true),
];
also i should have imported this code at the top of the bookingstatus factory
use Illuminate\Support\Str;
As far as I understand, Api Platform deletes and updates one by one the resources of a Collection. For example, I have an Activity Entity, which has a Many-To-One relation with OpeningHours: if I want to delete or add multiples OpeningHours through an Admin Back Office, I must call a "delete" operation for each openingHour with its unique #id. As long as I have very few OpeningHours, it's quite all right : the job is done in a few seconds. But what am I supposed to do when I have thousand of them ? Just wait ?
So I've created a Custom Controller and a Custom Route - so far only for the Delete Operation ; the update operation will come after.
First Question : is this the right way to do it or have I missed something in the docs?
Here is my API configuration for the Activity Entity:
/**
* #ApiResource(
* collectionOperations={
* "get"={"normalization_context"={"groups"="activity:list"}},
* "post"={"denormalization_context"={"groups"="activity:post"}},
* },
* itemOperations={
* "get"={"normalization_context"={"groups"="activity:item"}},
* "put"={"denormalization_context"={"groups"="activity:item"}},
"delete_opening_hours"={
* "method"="DELETE",
* "path"="/admin/activity/{id}/delete_opening_hours",
* "controller"=DeleteOpeningHoursAction::class,
* "read"=false,
* },
* "delete", "patch"
* },
* attributes={"pagination_items_per_page"=10}
* )
And my Custom Controller :
/**
* Class DeleteOpeningHoursAction
* #Security("is_granted('ROLE_ADMIN')")
*/
final class DeleteOpeningHoursAction extends AbstractController
{
/**
* #Route(
* name="delete_opening_hours",
* path="/admin/activity/{id}/delete_opening_hours",
* methods={"DELETE"},
* )
*/
public function deleteHours(Activity $data):Activity
{
$em = $this->getDoctrine()->getManager();
$activity = $em->getRepository('App\Entity\Activity')->find($data);
$openingHours = $activity->getOpeningHours();
foreach ($openingHours as $hour) {
$em->remove($hour);
}
$em->flush();
$response = new Response();
$response->setStatusCode(204);
return $response;
}
}
It does the requested job: all the OpeningHours are deleted at once, but it returns a 500 Error:
Return value of App\Controller\Action\DeleteOpeningHoursAction::deleteHours() must be an instance of App\Entity\Activity, instance of Symfony\Component\HttpFoundation\Response returned
And if I return $activity instead of the response above, the error message becomes :
Return value of App\Controller\Action\DeleteOpeningHoursAction::deleteHours() must be an instance of Symfony\Component\HttpFoundation\Response, instance of App\Entity\Activity returned
So what am I doing wrong? What is the correct response for a Custom Controller?
I'm quite confused.
Thanks for any help.
I have to log the changes of each entity. I've Listener which listens for doctrine's events on preRemove, postUpdate and postDelete.
My entity AccessModule has relations:
App\Entity\AccessModule.php
/**
* #ORM\OneToMany(targetEntity="App\Entity\AccessModule", mappedBy="parent")
* #ORM\OrderBy({"id" = "ASC"})
*/
private $children;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\AccessModule", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true)
*/
private $parent;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\AccessModuleRoute", inversedBy="access_modules")
* #ORM\JoinTable(name="access_routes",
* joinColumns={#ORM\JoinColumn(name="access_module_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="route_id", referencedColumnName="id")})
*
*/
private $routes;
in listener:
App\EventListener\EntityListener.php
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
$encoders = [new XmlEncoder(), new JsonEncoder()];
$normalizer = new ObjectNormalizer();
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getId();
});
$this->serializer = new Serializer([$normalizer], $encoders);
public function createLog(LifecycleEventArgs $args, $action){
$em = $args->getEntityManager();
$entity = $args->getEntity();
if ($this->tokenStorage->getToken()->getUser()) {
$username = $this->tokenStorage->getToken()->getUser()->getUsername();
} else {
$username = 'anon'; // TODO Remove anon. set null value
}
$log = new Log();
// $log->setData('dddd')
$log->setData($this->serializer->serialize($entity, ''json)
->setAction($action)
->setActionTime(new \DateTime())
->setUser($username)
->setEntityClass(get_class($entity));
$em->persist($log);
$em->flush();
}
I've problem with serialization
When I use $log->setData($entity) I get problem with Circular.
Whan I do serialization $log->setData($this->serializer->serialize($entity, ''json) I get full of relations, with parent's children, with children children. In a result I get full tree :/
I'd like to get
Expect
[
'id' => ID,
'name' => NAME,
'parent' => parent_id // ManyToOne, I'd like get its id
'children' => [$child_id, $child_id, $child_id] // array of $id of children array collection
]
(ofcourse this is draft before encode it to json)
How can I get expected data without full relations?
Thing you are looking for is called serialization groups: here and here.
Now let me explain how it works. It's quite simple. Say you have Post Entity:
class Post
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"default"})
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\User\User")
* #Groups({"default"})
*/
private $author;
}
And you have also User Entity:
class User
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"default"})
*/
private $id;
/**
* #ORM\Column(type="string", length=40)
* #Groups({"default"})
*/
private $firstName;
/**
* #ORM\Column(type="string", length=40)
*/
private $lastName;
}
Post can have author(User) but I don't want to return all User data every single time. I'm interested only in id and first name.
Take a closer look at #Groups annotation. You can specify so called serialization groups. It's nothing more than convinient way of telling Symfony which data you would like to have in your result set.
You have to tell Symfony serializer which relationships you would like to keep by adding relevant groups in form of annotation above property/getter. You also have to specify which properties or getters of your relationships you would like to keep.
Now how to let Symfony know about that stuff?
When you prepare/configure your serializaition service you just simply have to provide defined groups like that:
return $this->serializer->serialize($data, 'json', ['groups' => ['default']]);
It's good to build some kind of wrapper service around native symfony serializer so you can simplify the whole process and make it more reusable.
Also make sure that serializer is correctly configured - otherwise it will not take these group into account.
That is also one way(among other ways) of "handling" circular references.
Now you just need to work on how you will format your result set.
ignored_attributes provides a quick, and easy way to accomplish what you're looking for.
$serializer->serialize($object, 'json', ['ignored_attributes' => ['ignored_property']]);
Heres how its used with the serializer:
use Acme\Person;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
$person = new Person();
$person->setName('foo');
$person->setAge(99);
$normalizer = new ObjectNormalizer();
$encoder = new JsonEncoder();
$serializer = new Serializer([$normalizer], [$encoder]);
$serializer->serialize($person, 'json', ['ignored_attributes' => ['age']]);
Documentation: https://symfony.com/doc/current/components/serializer.html#ignoring-attributes
Tested in Symfony 4.1, here is the documentation that actually works https://symfony.com/blog/new-in-symfony-2-7-serialization-groups
Robert's explanation https://stackoverflow.com/a/48756847/579646 is missing the $classMetadataFactory in order to work. Here is my code:
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$encoders = [new JsonEncoder()];
$normalizer = new ObjectNormalizer($classMetadataFactory);
$normalizer->setCircularReferenceLimit(2);
// Add Circular reference handler
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getId();
});
$normalizers = [$normalizer];
$serializer = new Serializer($normalizers, $encoders);
$jsonContent = $serializer->serialize($jobs, 'json', array('groups' => ['default']));
return JsonResponse::fromJsonString($jsonContent);
In order to upgrade an existing system, I have to import extended tt_news records to tx_news. The problem is, that the extending of the tx_news Model seems not to work proper and of course this, the import neither.
But in Backend I can see and store data in my additional fields.
What I've done so far:
I've extended tx_news Version 3.2.8
My Model:
class News extends \GeorgRinger\News\Domain\Model\News {
/**
* uidForeign.
*
* #var int
*/
protected $uidForeign;
/**
* Sets the uidForeign.
*
* #param int $uidForeign
*
* #return void
*/
public function setUidForeign($uidForeign)
{
$this->uidForeign = $uidForeign;
}
/**
* Returns the uidForeign.
*
* #return int $uidForeign
*/
public function getUidForeign()
{
return $this->uidForeign;
}
/**
* tableForeign.
*
* #var string
*/
protected $tableForeign;
/**
* Sets the tableForeign.
*
* #param string $tableForeign
*
* #return void
*/
public function setTableForeign($tableForeign)
{
$this->tableForeign = $tableForeign;
}
/**
* Returns the tableForeign.
*
* #return string $tableForeign
*/
public function getTableForeign()
{
return $this->tableForeign;
}
}
ext_localconf:
$GLOBALS['TYPO3_CONF_VARS']['EXT']['news']['classes']['Domain/Model/News'][] = 'news_extend';
I think that should work. The generated class in typo3temp seems correct. My fields including their getter/setter are in there.
But in Controller and FE I can not access these fields.
What am I missing? What else can I check?
If you upgrade a project, I don't know really the reason why you are using an old version of EXT:news.
What could be missing is the TCA definition of the field.
If you want to migrate from tt_news to news, there is a ready-to-use solution which can be found here https://github.com/ext-news/news_ttnewsimport
The reason was an configuration setting for the backend cache.
they have bees set to TYPO3\CMS\Core\Cache\Backend\NullBackend:class instead TYPO3\CMS\Core\Cache\Backend\NullBackend.
Now it works.
i'm working with doctrine & i have some problem in many-to-many self referencing which has some extra fields.
lets describe my scenario :
i have a table named Drug , drugs can have conflicts with each other & this conflicts may appear under some conditions & may have some solutions.
i've read doctrine documents about many-to-many relations & it's mentioned that it's not good for JoinTable to have some extra fileds.
so what's the best solution for this problem?
here is my solution, but i'm not sure that this is the best one or not.
class Drug{
..
/**
* #var DrugConfilict
*
* #ORM\OneToMany(targetEntity="DrugConfilict", mappedBy="drug1")
*/
private $drugConfilict1s;
/**
* #var DrugConfilict
*
* #ORM\OneToMany(targetEntity="DrugConfilict", mappedBy="drug2")
*/
private $drugConfilict2s;
}
class DrugConfilict
{
/**
* #var string
*
* #ORM\Column(name="confilict_conditions", type="text", nullable=true)
*/
private $confilictConditions;
/**
* #var string
*
* #ORM\Column(name="what_should_do", type="text", nullable=true)
*/
private $whatShouldDo;
/**
* #var Drug
*
* #ORM\ManyToOne(targetEntity="Drug", inversedBy="drugConfilict1s")
* #ORM\JoinColumn(name="drug1_id", referencedColumnName="id")
*/
private $drug1;
/**
* #var Drug
*
* #ORM\ManyToOne(targetEntity="Drug", inversedBy="drugConfilict2s")
* #ORM\JoinColumn(name="drug2_id", referencedColumnName="id")
*/
private $drug2;
}
thanks for your answers :)
The solution you provided is correct. Perhaps if you can describe the nature of the actual conflict their might be a better data model or data handling for it.