I'm using Symfony 1.4 and Propel 1.6. I was confounded at first by various classnames that used improper pluralization.
For example some table relations were things like CommerceItemss, which was easily traced down in my schema.yml where I specified plural instead of singular table names.
After I corrected that, I was still left with one more type of error in the auto generated classes. Namely, I had a table named "Match" which Propel was pluralizing to Matchs.
For example, lines like:
if (null === $this->matchsScheduledForDeletion) {
...
$this->matchsScheduledForDeletion = clone $this->collMatchs;
So I'm left with the question of, "how to get Propel to pluralize properly"?
The solution was buried deep in the Propel ORM docs:
http://propelorm.org/reference/buildtime-configuration.html
Namely, edit your default.properties:
./plugins/sfPropelORMPlugin/lib/vendor/propel/generator/default.properties
./plugins/propel/generator/default.properties
Look for the line that says:
propel.builder.pluralizer.class = builder.util.DefaultEnglishPluralizer
Replace with:
propel.builder.pluralizer.class = builder.util.StandardEnglishPluralizer
It handles the problem with Match->Matchs properly (and I presume would also handle Category->Categories, etc.) so this could be the solution if you have a similar problem.
Related
I am fairly new to laravel and I built a little "similar posts" section. So every post has a tag and I query all the id's from the current tag. And then I find all the posts with thoses id's. Now my problem is that the current post is always included. Is there an easy way to exclude the current id when querying?
I can't seem to find anything in the helper function on the laravel docs site
this is my function:
public function show($id)
{
$project = Project::findOrFail($id);
foreach ($project->tags as $tag){
$theTag = $tag->name;
}
$tag_ids = DB::table('tags')
->where('name', "=", $theTag)
->value('id');
$similarProjects = Tag::find($tag_ids)->projects;
return view('projects.show', ['project' => $project, 'similarProjects' => $similarProjects]);
}
An easy way to solve your issue would be to use the Relationship method directly instead of referring to it by property, which you can add additional filters just like any eloquent transaction.
In other words, you would need to replace this:
Tag::find($tag_ids)->projects
With this:
Tag::find($tag_ids)->projects()->where('id', '!=', $id)->get()
Where $id is the current project's id. The reason behind this is that by using the method projects(), you are referring your model's defined Relationship directly (most probably a BelongsToMany, judging by your code) which can be used as a Query Builder (just as any model instance extending laravel's own Eloquent\Model).
You can find more information about laravel relationships and how the Query Builder works here:
https://laravel.com/docs/5.1/eloquent-relationships
https://laravel.com/docs/5.1/queries
However, the way you are handling it might cause some issues along the way.
From your code i can assume that the relationship between Project and Tag is a many to many relationship, which can cause duplicate results for projects sharing more than 1 tag (just as stated by user Ohgodwhy).
In this type of cases is better to use laravel's whereHas() method, which lets you filter your results based on a condition from your model's relation directly (you can find more info on how it works on the link i provided for eloquent-relationships). You would have to do the following:
// Array containing the current post tags
$tagIds = [...];
// Fetch all Projects that have tags corresponding to the defined array
Project::whereHas('tags', function($query) use ($tagIds) {
$query->whereIn('id', $tagIds);
})->where('id', !=, $postId)->get();
That way you can exclude your current Project while avoiding any duplicates in your result.
I don't think that Tag::find($tag_ids)->projects is a good way to go about this. The reason being is that multiple tags may belong to a project and you will end up getting back tons of project queries that are duplicates, resulting in poor performance.
Instead, you should be finding all projects that are not the existing project. That's easy.
$related_projects = Project::whereNotIn('id', [$project->id])->with('tags')->get();
Also you could improve your code by using Dependency Injection and Route Model Binding to ensure that the Model is provided to you automagically, instead of querying for it yourself.
public function show(Project $project)
Then change your route to something like this (replacing your controller name with whatever your controller is:
Route::get('/projects/{project}', 'ProjectController#show');
Now your $project will always be available within the show function and you only need to include tags (which was performed in the "with" statement above)
So, going into the problem straight away. someone told me that we dont need to make a pivot table if we only want to have ids of the table. laravel can itself handle this situation. I dont know how this works. I have a table community and another table idea. relation is like this;
One community can contain many ideas and an idea can be found in many
communities.
Relation in idea Model:
public function community() {
return $this->belongsToMany('App\Community')->withTimestamps();
}
Relation in community Model:
public function idea() {
return $this->belongsToMany('App\idea');
}
Now i want to fetch all the records related to a single community to show on its page Let's say the community is Arts.
Here is Controller function:
public function showCommunities($id) {
$community = Community::findOrFail($id)->community()->get();
return view('publicPages.ideas_in_community', compact('community'));
}
When i attach ->community()->get() to the Community::findOrFail($id) Then it throws the error
SQLSTATE[42S02]: Base table or view not found laravel
Any help would be appreciated.
Edit:
Logically, this piece of code Community::findOrFail($id)->community()->get() should be like this Community::findOrFail($id)->idea()->get(). Now it is true but it has little issue. it throws an error
Fatal error: Class 'App\idea' not found
The way you define the many-to-many relation looks ok - I'd just call them communities() and ideas(), as they'll return a collection of objects, not a single object.
Make sure you use correct class names - I can see you refering to your model classes using different case - see App\Community and App\idea.
In order to find related models, Eloquent will look for matching rows in the pivot table - in your case it should be named community_idea and have 3 fields: community_id, idea_id and autoincrement primary key id.
With that in place, you should be able to get all ideas linked to given community with:
$ideas = Community::findOrFail($communityId)->ideas;
If you need communities linked to given idea, just do:
$communities = Idea::findOrFail($ideaId)->communities;
You can read more about how to use many-to-many relationships here: https://laravel.com/docs/5.1/eloquent-relationships#many-to-many
someone told me that we dont need to make a pivot table if we only want to have ids of the table
The above is not true (unless I've just misunderstood).
For a many-to-many (belongsToMany) their must be the two related table and then an intermediate (pivot) table. The intermediate table will contain the primary key for table 1 and the primary key for table 2.
In laravel, the convention for naming tables is plural for your main tables i.e. Community = 'communities' and Idea = 'ideas'. The pivot table name will be derived from the alphabetical order of the related model names i.e.
community_idea.
Now, if you don't want/can't to follow these conventions that's absolutely fine. For more information you can refer to the documentation: https://laravel.com/docs/5.2/eloquent-relationships#many-to-many
Once you're happy that you have the necessary tables with the necessary fields you can access the relationship by:
$ideas = $community->ideas()->get();
//or
$ideas = $community->ideas;
So you controller would look something like:
public function showCommunities($id)
{
$community = Community::findOrFail($id);
//The below isn't necessary as you're passing the Model to a view
// but it's good for self documentation
$community->load('ideas');
return view('publicPages.ideas_in_community', compact('community'));
}
Alternatively, you could add the ideas to the array of data passed to the view to be a bit more verbose:
public function showCommunities($id)
{
$community = Community::findOrFail($id);
$ideas = $community->ideas
return view('publicPages.ideas_in_community', compact('community', 'ideas));
}
Hope this helps!
UPDATE
I would imagine the reason that you're receiving the App\idea not found is because the model names don't match. It's good practice (and in certain environments essential) to Capitalise you class names so make sure of the following:
Your class name is Idea and it's file is called Idea.php
The class has it's namespace declared i.e. namespace App;
If you've added a new class and it's not being found you might need to run composer dump-autoload from the command line to update the autoloader.
I have upgraded to Doctrine 2.2.2 now. I have managed to successfully connect my database to my application and was able to generate proxies and repositories. I have no problem with those generation. I am just confused with regards to using the DQL of doctrine 2.2.2.
The case is this: I currently have a repository class responsible for user registration, authentication, etc. I have managed to execute the DQL on it but I just felt weird about this stuff (in my repository class).
$query = $em->createQuery("SELECT u FROM MyProject\\Entity\\AdminUsers u");
I tried also:
$query = $em->createQuery("SELECT u FROM AdminUsers u");
The last did not work but the first one works fine but it seems weird. Is it really the right way of executing DQL in doctrine 2? or am I missing something important.
NOTE: on the above declaration of this repository class is:
namespace MyProject\Repository;
use Doctrine\ORM\EntityRepository,
MyProject\Entity\AdminUsers;
It almost is the right way to do it. If you would use single quotes ', you could just use a single backslash \ instead of a double backslash \\.
Doctrine cant find out (or it would be extremely expensive to do so) which classes you imported via use statements.
But you can use a typed repository which you retrieve from the entity manager via:
$repo = $em->getRepository('MyDomain\Model\User');
$res = $repo->findSomeone();
And in the findSomeone() function you can do this:
$qb = $this->createQueryBuilder('u');
$dql = $qb->where('u.id = 1')->getDQL();
return $this->_em->createQuery($dql)->getSingleResult();
Meaning, the repository is already typed on your entity and knows which class to select from.
Some documentation:
Querying with doctrine
Querybuilder
10 step get started guide (which covers the basics including repositories)
I'm using Zend Framework with Doctrine. I'm creating an object, editing, then saving it. That works fine. However, when I later try to find that object based on one of the column values, Doctrine throws an error saying, "Message: Invalid field name to find by:". Notice there is no field name listed in the error message after the :.
My database table does have a column called status and the model base class does know about it. I'm using base classes and table classes in my setup.
Here is my code. The first section works fine and the record gets created in the database. Its the second line of the second section where the error gets thrown. I've tried different variations of the findBy calls, findBy('status', 'test1'), findByStatus('test1'), etc.
$credit = new Model_Credit();
$credit['buyer_id'] = 1;
$credit['status'] = 'test1';
$credit->save();
$creditTable = Doctrine_Core::getTable('Model_Buyer');
$credit = $creditTable->findOneByStatus('test1'); // dying here
$credit['status'] = 'test2';
$credit->save();
Never mind! I hate when you see the answer right after posting a big long question. In the second section I referred to a different model (Model_Buyer) instead of Model_Credit.
Using Doctrine PHP
If I have a user with a many to many relationship with the model address and each address has a foreign key to a address type (home, office). Doctrine doesn't automatically load the related records for that address type.
$user = Doctrine::getTable('User')->findOneById(1); // bob
echo $user->Address[0]->address_type_id; // 4
echo isset($user->Address[0]->AddressType); // false
$user->Address[0]->refreshRelated(); // or $user->Address[0]->loadReference('AddressType');
echo isset($user->Address[0]->AddressType); // true
echo $user->Address[0]->AddressType->name; // office
Not sure if this is a bug or not in doctrine or my model.
But is this the best way to load related models beyond one level deep or is there another way to achieve the same result?
Have you simply tried joining you relations one by one?
Works pretty well, if you relations are set up correct.
$user = Doctrine::getTable('User')
->createQuery('u')
->leftJoin('u.Address a')
->leftJoin('a.AddressType t')
->findOneById(1);
You also spare your db 2 sql queries, compared to your example.
Are you saying you can't do this:
echo $user->Address[0]->AddressType->name;
If you try that without the isset, Doctrine should check to see that the value is set before retrieving it for you automatically.