Different implementation of Eloquent instance for the same table - php

I'm currently working a tournament organization project, I would like to what's the best technique to have different implementation for the same model, for example I have model called matches, than retrieves data related to matches, but these matches may have different types depending on match_type field specified in matches model, what I did is creating parent class /Match , and having different types of matches extend this parent class. Ex:
Class SinglElimination/Match extends /Match{}
Class GroupStage/Match extends /Match{}
so with this design I have to get the parent match first to get the match_type then re-run the query to get a match with the needed child model
$match=Match::find($id);
$type = $match->match_type;
$childMatch = new $match_type.'/Match'();
$match = $match->where('_id', $this->_id)->first();
which I know is nowhere near clean, so how would you implement this ?

If I were you I would separate those 3 classes and exclude any extending. Take a look at Polymorphic relationships in Laravel, here is the quick link. It will be a cleaner approach and in my opinion it would be the best approach here, all you'll have to do is design the tables properly and do relationships properly too.

Related

Retrieve nested relationships for a model instance in Laravel's Eloquent

My scenario is this:
I have a Course model
Each Course can have many CourseTopics, through a topics() relationship
Each CourseTopic can have many Lessons, through a lessons() relationship
Is there a compact way to retrieve and handle all the Lessons associated with a single Course (for example, to list them, or to count their total number)?
My aim would be to have a very brief syntax to use in Blade templates; I don't want to involve logic (or at least, keep it to a bare minimum) or raw SQL queries into my template.
What I've tried:
$course->with("topics.lessons")
where $course is the current instance of the course in a template, doesn't work (gives to me all the courses with all their topics and lessons).
EDIT:
A solution is to define a hasManyThrough() relationship like:
$this->hasManyThrough("Lessons", "CourseTopics");
This solves the problem for a 2-level nested relationship. How about a 3-level instead?

Where to place a database query in model? (Symfony framework)

I'm new to PHP programing and Symfony. English isn't my native language so sorry if it sounds strange how I write...
I have two entities: Article and Category, where each Article has a Category. And I need to show how many articles I have for a given category:
Category ------------------ N°
Vehicles -------------------- 4
Electronics ---------------- 20
Food ----------------------- 15
Furniture ------------------ 8
With Doctrine I've made the CRUD files for both entities.
php app/console doctrine:generate:crud
Like I said, the problem is that I want to show a table with properties of a Category (name, description, etc) and how many articles of it are in the inventory.
The SQL query is very simple:
SELECT count(*) FROM Articles a WHERE a.id_category = $id_category
Where to put that?! I'm very confused and don't want to brake best practice rules.
Doctrine generated lots of files: ArticleController.php, ArticleType.php (Form), and all the .twig for the views. Same for Category.
In the spirit of giving a direct answer to your question: what you need is a custom Doctrine Repository, in this case an ArticleRepository.
e.g.
ArticleRepository.php
namespace ACME\DemoBundle\Article;
use Doctrine\ORM\EntityRepository;
class ArticleRepository extends EntityRepository
{
public function countForCategory($id)
{
$result= $this->createQueryBuilder('a')
->join('a.category', 'c')
->where('c.category_id = :id')
->setParameter('id', $id)
->select('count(a')
->getQuery()
->getSingleScalarResult();
return $result;
}
}
And then you set your Article entity to use that ArticleRepository
Article.php
/**
* #ORM\Entity
* #ORM\Table(name="article")
* #ORM\Entity(repositoryClass="ACME\DemoBundle\Entity\ArticleRepository")
*/
class Article
{
/// etc...
You can then get the Repository for the Entity in e.g. your Controller (although as suggested elsewhere you can hide this away in some kind of service to avoid filling your Controller with business logic; it just needs to be reachable somehow from inside your Controller), and run the query:
ArticleController
class ArticleController extends Controller
{
public function countAction($id)
{
$articleRepo = $this->getDoctrine()->getRepository('DemoBundle:Article');
$count = $articleRepo->countForCategory();
//etc...
NB If you really want exactly the output in your example, it may be more efficient to do one query for the whole table, probably in a CategoryRepository, performing a count and grouping by Category. The query would return an array containing Category name and count.
When using Symfony2 + Doctrine2,
don't think (so much) about the database. Think of persistent data objects, so called entities, and let Doctrine handle them. Spend some time on cleanly defining the relations between those objects, though.
forget about the term “MVC”. MVC is a rather abstract concept, things are more complex in reality. Fabian (lead dev of SF) has a nice write-up about this topic: http://fabien.potencier.org/article/49/what-is-symfony2
If you wonder where to put what in your Symfony bundles, read this Cookbook article: http://symfony.com/doc/current/cookbook/bundles/best_practices.html
Create a CategoryManager class in your service layer, and handle any business logic there. You can pass the router to it through dependency injection.
For your example, CategoryManager would have a getUrl(Article $article) method which would use the router instance (that you either injected through __construct or a separate setter method) to generate the Url based on properties of $article, and return it.
This method will ensure that your business logic doesn't pollute the view or controller layers.
Check this link Services Symfony

Doctrine Inheritance and MySQL Join Table Limit

I have a problem with 61 join table limit of mysql. I have 57+ different classes extending Base Class which contain association to comments, likes, tags. And MySQL is crashing when i get most commented. Doctrine has to join whole discriminator maps and comments itself and order by COUNT(comments).
Is there way to fix that ?
And is there another way to achieve comments for different types of entities without inheritance and copying same association all over again?
Here is sample schema of Entities. When I want to add new Entity Type with comments,likes I just extends BaseClass to receive these features.
If I understand correctly what you're trying to do is have many different entity types which can be commented on.
First thing to do would be to step back from Doctrine and thing about the simplest table structure you would need to accomplish this.
Something like this may suffice:
Comments
_______________________
| id | type | entity_id |
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
It is nice in Doctrine to have bi-directional relationships in your base class for convenience but sometimes they are not the best choice. Maybe it would simplify your architecture to perform a query directly on the comments table by entity type and id.
You may also want to consider removing the Base class and having each entity be standalone.
Since a blog post can exist in a context where it does not have comments (on a blog that doesn't allow commenting for example) then $blog->getComments() wouldn't make much sense.
Making this change you could do something like this instead:
$comments = $commentsRepository->findCommentsForEntity($entity);
$commentsCount = count($comments);
and the repository could generate the needed query passing the entity as the entity_id parameter and setting the required comment type based on the entity type.

Multi level getters in symfony2/doctrine2

Im wondering if theres a cleaner way to approach the system i have below, using symfony2/doctrine2.
I currently have three entities
Entity A - many to one relationship with class B, one to many with class C
Entity B - one to many relationship with class A, one to many with class C.
Entity C - Many to one relationship with class A and B.
If i do $entityA->getEntityB()->getEntityC() that will return me all the C entities assigned to entity B, but what i actually want is all the entity C entities that are assigned to both entity B and entity A. Essentially i want to recognise the getter chain, if that makes sense.
At the moment i have to pass entity A into the getEntityC method and filter out the values i dont want which is starting to get a little messy when dealing with more objects and other parts of code.
Is there a way to set this up whereby the last getter will force the relationship from both parents instead of just the immediate one?
Any help would be much appreciated.
I would much recommend not to try to get value by getters, but instead create a query by DoctrineQueryBuilder and use multiple left joins. For example something like this:
$repository = $this->getDoctrine()->getRepository('GreatBundle:Entity');
$q = $repository->createQueryBuilder('e1', 'e2', 'e3')->leftJoin('e1.e2', 'e2')->leftJoin('e1.e3', 'e3');
$columns = array(
'e1.id',
'e2.id as e2_id',
'c3.id as e3_id',
);
$result = $q->select($columns)->getQuery()->getArrayResult();
Sorry that I didn't fully get your usage case, but you will have to recreate query just to fit it.

Interface or type-hint for single object and multiple object class in php

Recently started working with OOP in PHP. Following the "code to an Interface" principle, i got confused as to the type hint to use when passing a single object or multiple as argument to a method.
Currently, i have a "Student" class - represents a row in my students table, i also have a "Students" class that holds multiple student objects in an array.
To fetch the profile of one student, i pass the Students object (holding a single student object) to the profile class. I set a Students type hint in the profile class.
Now i feel this is bad code as i have lines like this
student = new Students();
and students = new Students();
question is,
am i on the right path?
if i remove the Students class and work with Student alone, based on the principle, how do i pass multiple Student objects (assuming array) to the profile class if it accepts a Student type hint?
what options do i have?
Thanks.
If by Students you mean a collection of Student objects, perhaps a better name would be StudentCollection or StudentSet.
There are two ways around the type hint problem:
Introduce a method on StudentCollection called ->getProfiles(); it would return an array of profiles for each Student instance it's managing by calling methods on Profile.
Introduce a (static) method on Profile that operates on a StudentCollection instance.
The first option has feature envy, which is why I've included a workaround.
Instead of reinventing the wheel you might want to try Doctrine or at least take a look at its architecture.
I'm not sure if I get your exact issue... But if you want to go for your own code I would first abstract the DB layer as well and have some base classes like Database, Table, Row, Field that an describe the DB stack and extend them as needed with some magic methods. So when you do Student extends Table it would automatically check for a "students" table or whatever else convention you like to implement. Alternatively you could just pass the table name as arg.
Whatever Object is returning the result set from the database would have to construct a single Row object for each row and add it to a collection of rows that I would name ResultSet and contains all the row objects and return that collection.

Categories