I have an app and I want to allow modules in it. I find nWidart /Laravel-modules is the best solution for this. I have used it in the past, but in my previous projects I was the sole developer, so when I created a model inside a module, to create the relationships between it and one of my base models, I just went and edit both files:
In App\Models\Disease I would add a new method:
public function symptoms(){
return $this->hasMany( Modules\Treatments\Entities\Symptom::class );
}
In Modules\Treatments\Entities\Symptom, the opposite:
public function disease(){
return $this->belongsTo( App\Models\Symptom::class );
}
Now, I would like to create those relationships, but without writing code in the App\Models files (of course I know there would be some modification required to make it work, I just mean without having to edit the files every time a module is created). Is there a way to do it? Is it possible to work that out?
Ok, in the module Entities I created a new model Modules\Treatments\Entities\Disease which extends from App\Models\Disease and I inserted the relationship method there.
use App\Models\Disease as BaseDisease;
class Disease extends BaseDisease{
/**
* Relationship between a Disease and it's symptoms
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function symptoms(){
return $this->hasMany( Modules\Treatments\Entities\Symptom::class );
}
}
The down side of this approach is that the relationship is only present when I load the Disease from Modules\Treatments\Entities\Disease but I couldn't find another way to do it
Related
I am trying to update/delete/create in belongsTo relations.
Company has many sports
sports is belonging to Company
Here is two models.
class CompanySports
{
public function company()
{
return $this->belongsTo(Company::class, "company_id","id");
}
class Company
public function sports()
{
return $this->hasMany(CompanySports::class,"company_id","id");
}
}
at controller, when sports is added or modified or remove, what is the best practice to update?
i know that many to many, sync can be used. In this, what is the best solution? Should i compare everytime after loading all from database which is not good practice i believe.
From your code, I would first recommend putting your models in separate files, and ensuring they are singular. If you use the artisan make:model command to generate the stubs, it should do this for you.
// app/CompanySport.php // <-- NOTE singular
class CompanySport // <-- NOTE singular
{
public function company()
{
return $this->belongsTo(Company::class, "company_id","id");
}
}
// app/Company.php
class Company {
public function sports()
{
return $this->hasMany(CompanySport::class,"company_id","id"); // singular
}
}
From there, I find it helpful to build helper methods in the various classes so that the grammar sounds natural and more importantly, belongs to the model. For example:
// app/Company.php
class Company
{
...
public function addSport(CompanySport $sport)
{
$this->sports()->save($sport);
}
public function removeSport(CompanySport $sport)
{
$this->sports()->find($sport->id)->delete();
}
}
These helper functions can then be easily called from anywhere, e.g. controller:
// CompanySportsController.php
public function store(Company $company, CompanySport $sport)
{
$company->addSport($sport);
return redirect('/company/' . $company->id);
}
If you are using these helpers, there is no comparing or sync to be done since you are only using a one to many relationship. Eloquent does everything for you.
Also, I've found this cheatsheet particularly helpful when building out the initial relationships and scaffolding of a new app.
While adding new record of Company Model, you need not to do anything as there is no child for it yet.
While updating an instance of a Company model, again you need not to update anything on its children. As relationship are based on id(primary key) which I believe you don't change while updating.
And now for deleting there are some questions. Do you want to delete the children when the parent is deleting? If so, you can use ON DELETE CASCADE which you can set up in migration like
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
in your spors table.
Well you can make your own function too like answered in here
Well if you don't want to delete the children, you can use softdelete on your Model. set up the relations then like
CompanySports
public function company()
{
return $this->belongsTo(Company::class, "company_id","id")->withTrashed();
}
This way you can get the parent of a children without any error though the parent is deleted.
This is probably pretty simple, but I can't find a way to do this.
Is there any way to get a list of class names of the entities that Doctrine manages? Something like:
$entities = $doctrine->em->getEntities();
where $entities is an array with something like array('User', 'Address', 'PhoneNumber') etc...
I know this question is old, but in case someone still needs to do it (tested in Doctrine 2.4.0):
$classes = array();
$metas = $entityManager->getMetadataFactory()->getAllMetadata();
foreach ($metas as $meta) {
$classes[] = $meta->getName();
}
var_dump($classes);
Source
Another way to get the class names of all entities (with namespace) is:
$entitiesClassNames = $entityManager->getConfiguration()->getMetadataDriverImpl()->getAllClassNames();
Unfortunately not, your classes should be organized in the file structure though. Example: a project i'm working on now has all its doctrine classes in an init/classes folder.
There is no built function. But you can use marker/tagger interface to tag entity classes that belong to your application. You can then use the functions "get_declared_classes" and "is_subclass_of" find the list of entity classes.
For ex:
/**
* Provides a marker interface to identify entity classes related to the application
*/
interface MyApplicationEntity {}
/**
* #Entity
*/
class User implements MyApplicationEntity {
// Your entity class definition goes here.
}
/**
* Finds the list of entity classes. Please note that only entity classes
* that are currently loaded will be detected by this method.
* For ex: require_once('User.php'); or use User; must have been called somewhere
* within the current execution.
* #return array of entity classes.
*/
function getApplicationEntities() {
$classes = array();
foreach(get_declared_classes() as $class) {
if (is_subclass_of($class, "MyApplicationEntity")) {
$classes[] = $class;
}
}
return $classes;
}
Please note that my code sample above does not use namespaces for the sake simplicity. You will have to adjust it accordingly in your application.
That said you did't explain why you need to find the list of entity classes. Perhaps, there is a better solution for what your are trying to solve.
I have two models that are associated with a Has And Belongs To Many Association in Cake 2.x. I'm trying to port my application over to Cake 3.3. In general, I'm having an issue replicating the "keepExisting" functionality found in the Cake 2.x associations. Right now, I'm trying to use the "through" functionality, but I'm not sure I'm barking up the right tree.
I have the following Tables:
class ContestsTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->table('contests');
$this->displayField('name');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsToMany('Events', [
'through' => 'ContestsEvents'
]);
}
}
class EventsTable extends Table
{
/**
* Initialize method
*
* #param array $config The configuration for the Table.
* #return void
*/
public function initialize(array $config)
{
parent::initialize($config);
$this->table('events');
$this->displayField('name');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsToMany('Events', [
'saveStrategy' => 'append',
'through' => 'ContestsEvents'
]);
}
}
class ContestsEventsTable extends Table
{
public function initialize(array $config) {
$this->belongsTo('Contests');
$this->belongsTo('Events');
}
}
When I save the initial contest with associated events, the save is fine and the association records are created in the join table. When I edit the contest record and change the list of the events, any of the selected events are added...but the old ones that are not selected anymore are not deleted. The second issue is that a new join record is created for already existing relationships. I would like to keep the already existing records rather than creating new ones. Later on in the app, I'll be using the join records id in an additional relationship...and I do not want the id to be regenerated each time the overlying contest record is updated.
I hope I'm making sense in describing what I'm trying to do. But in the simplest form, I'm trying to replicate the functionality found via the 'unique' => 'keepExisting' option included in Cake 2x, just can't crack the code on how to accomplish this in Cake 3.3?
Thanks in advance for your help.
OK, So here it goes. First, I think I wrote the question above out of frustration, so my apologies if it wasn't clear. I went on to working on other parts of my app, with this issue stuck in the back of my head. Well, I figured it out...so here's my answer:
I was an idiot.
Today, I took some time with a sandbox app and basically got the functionality to work on a sandbox table, but couldn't get it to work on the app's tables. Eventually I narrowed it down to the fact that it was a database issue. Yes...I somehow made the foreign_key fields in my join table VARCHAR and not INT. Yep...that will do it.
Well, I guess my point is to log this for all eternity...Check your database fields and tables are set up correctly!!!
I have 2 controllers and models:
User Controller & Model
Hero Controller & Model
Each user can have unlimited heroes - it means that the relationship between them is one to many.
In my UserController I created the following method:
/**
* Get the heroes of the user.
*/
public function heroes()
{
return $this->hasMany(Hero::Class);
}
while in my HeroController I created this method:
/**
* Get the user that owns the hero.
*/
public function user()
{
return $this->belongsTo(User::class)
}
Added this to my routes file:
Route::get('userHeroes', 'UserController#heroes');
and it returns this error:
{"error":{"message":"Method [hasMany] does not exist.","status_code":500}}
What could have gone wrong.. ?
The controller is just a delegate between the request and the return data - you tell it that you want something, it figures out what you want, and then it calls the appropriate places to get something to return.
The hasMany() and belongsTo() methods, on the other hand, are logic specifically related to the Hero and User models, on the other hand.
What you need is to move the heroes() method to your User model, because a user can have many heroes. Also need the user() method to your Hero model, because a hero belongs to a user.
Then you put an action call in a controller. Let's say, for instance, that you have a UserController which has an getHeroes() method. That might look like this:
public function getHeroes() {
$user = auth()->user();
$heroes = $user->heroes;
return $heroes;
}
And that will format it to JSON. Just an example.
But you might want to read a tutorial or two about this, since it's fairly basic stuff and it's good to get a good handle on early on. Please don't take that the wrong way - we're happy to help if you run into problems, I just think you might need a stronger foundation. The screencasts at Laracasts are highly recommended for this purpose.
it must be declared in models, not in controllers, hasMany() is a method in eloquent models.
hasMany and belongsTo methods are eloquent class methods.
And we inherit eloquent in our model so that we can use the eloquent methods functionality.
In order to use the relation, you have to define the relation method in respective model class and then you can call from controller.
Please refer the documentation Eloquent relationship documentation
Hope i have cleared your doubt.
Thanks
I have an Entity that has bidirectional ManyToOne/OneToMany relationship with another entity:
class BookShelf {
/**
* #OneToMany(targetEntity="Book", mappedBy="shelf", cascade={"persist"})
*/
public $books;
}
class Book {
/**
* #ManyToOne(targetEntity="BookShelf", inversedBy="books", cascade={"persist"})
*/
public $shelf;
}
I'm trying to create a new book, and have that object be listed in the bookshelf.
$book = new Book();
$book->shelf = $shelf;
$em->persist($book); $em->flush();
$shelf->showBooks();
After that, the $shelf->books does not contain the book, but instead it contains NULL. However the book is correctly inserted into the database, and when I run $shelf->showBooks() on another pageload, the book is listed properly.
I tried adding $em->refresh($book) and $em->refresh($shelf) but it doesn't help, the association still isn't refreshed.
Doctrine manual does suggest that I could use $shelf->books->add($book) to manually synchronize the association, but since there are initially no books, $shelf->books is NULL and I cannot call any methods on it.
How can I make Doctrine reload the association to include the newly created associated entity?
(Related: "Doctrine and unrefreshed relationships")
And as I later noticed, the very same Doctrine manual I linked to tells me to set the property as an ArrayCollection in the constructor, excatly so that the $shelf->books->add($book) does work. That is:
public function __construct() {
$this->books = new \Doctrine\Common\Collections\ArrayCollection();
}
Stupid me. I'll post the answer here in case someone else happens to come looking for the same issue, after being just as stupid. Which is unlikely, I guess.