I'm building an app with Laravel 4 and using Eloquent as the ORM.
I think the easiest way to describe my question is with an example, albeit an unlikely one...
I have a Cookie model (as in OREO etc). Cookie can in turn belong to a Human or an Alien. So...
Is it possible (correct) to say:
A Cookie belongs to Human
AND
A Cookie belongs to Alien?
The same Cookie can't belong to both a Human and and Alien or shared between members of the same species.
So I guess what I'm really asking is, can the Cookie table have two foreign key columns, one for Humans and one for Aliens?
Thanks in advance for your advice.
You can have this:
name type nullable
------------------------------
id int no
name text no
human_id int yes
alien_id int yes
Those could be your classes:
class Cookie extends Eloquent {
public function human()
{
return $this->belongsTo('Human', 'human_id');
}
public function alien()
{
return $this->belongsTo('Alien', 'alien_id');
}
}
class Alien extends Eloquent {
public function cookie()
{
return $this->hasOne('Cookie', 'alien_id');
}
}
class Human extends Eloquent {
public function cookie()
{
return $this->hasOne('Cookie', 'human_id');
}
}
And then you could use them this way:
$human = Human::find(1);
echo $human->cookie->name;
$cookie = Cookie::find(1);
if ($cookie->human) echo $cookie->human->name;
if ($cookie->alien) echo $cookie->alien->name;
Related
Imagine you have some Entity class and want another class that groups multiple instances of Entity.
How do you name it?
CompoundEntity?
CompositeEntity?
something else?
This is a common thing I do, and my colleagues use different naming convention. I have no idea what is better and also I'm not a native English speaker.
Concrete example:
public final class CompoundSetUpAction: SetUpAction {
private let setUpActions: [SetUpAction]
public init(
setUpActions: [SetUpAction])
{
self.setUpActions = setUpActions
}
public func setUp() -> TearDownAction {
return CompoundTearDownAction(
tearDownActions: Array(setUpActions.map { $0.setUp() }.reversed())
)
}
}
I am new to Laravel and a bit confused about some definitions of ORM.
I am currently working on a simple Trouble ticket management system, and here is my question :
(table: column, column,...)
tickets : id, description, equipment_id
equipments: id, name, vendor_id
vendor: id, name
This is a very short resume of my tables and its relations, following Laravel's conventions. How can I build these models?
Basically I need to retrieve, for example, how many tickets were opened to a certain vendor (how many times I called the vendor for support).
Thank you in advance
What zwacky said is entirely (edit: maybe not entirely correct in the end) true for close relations, but in your situation there is nested relation:
Vendor -> Equipment -> Ticket
Then to retrieve tickets for particular vendor you would define relation on Vendor model like this:
class Vendor extends Eloquent {
public function equipment()
{
return $this->hasMany('Equipment');
}
public function tickets()
{
return $this->hasManyThrough('Ticket', 'Equipment');
}
class Equipment extends Eloquent {
public function tickets()
{
return $this->hasMany('Ticket');
}
public function vendor()
{
return $this->belongsTo('Vendor');
}
class Ticket extends Eloquent {
public function equipment()
{
return $this->belongsTo('Equipment');
}
and to get count of total tickets for the vendor (not currently open):
Vendor::find($id) // retrieve particular vendor
->tickets()->count(); // get count on tickets table
// and this way you retrieve collection of related tickets
Vendor::find($id) // retrieve particular vendor
->tickets; // get Eloquent Collection
Also you may find it helpful: http://softonsofa.com/querying-relations-with-eloquent-in-laravel-4/
you'd need to declare these relationships within their models. e.g. your Ticket.php model could look like this:
class Ticket extends Eloquent {
public function equipment()
{
return $this->hasOne('Equipment');
}
public function vendor()
{
return $this->hasOne('Vendor');
}
...
}
for retrieval you'd do it like this:
foreach (Ticket::all() as $ticket) {
$ticket->vendor()->id;
}
check this section of the laravel docs.
edit: for the specific query how many tickets are open to a certain vendor:
Ticket::where('open', '=', 1)->vendor()->where('id', '=', 42);
I want to make the program with the following classes:
Class Player, which stores some information about players with get/set functions.
Player can be as AttackPlayer, which will have own data with get/set functions.
Also Player can be as ProtectorPlayer, also with some other own data with get/set functions different than in AttackPlayer.
Also Player can be TeamPlayer or FreePlayer, each of these classes have own data etc.
The question is how to implement the hierarchy correctly?
At first I thought about multiple inheritance, which is not good anyway.
Something like:
Player
AttackPlayer extends Player
ProtectorPlayer extends Player
TeamPlayer extend AttackPlayer or ProtectorPlayer
FreePlayer extend AttackPlayer or ProtectorPlayer
Also I thought something about strategy pattern, but it is not applicable here, because there are no common algorithms.
Are there any approaches which helps to organize such interaction?
Another way to do it is to have a field in the Player class, which helps to identify wether the TeamPlayer/FreePlayer is Attack or Protector type, and access appropriate fields depending on that.
In this case inheritance would be like this:
Player
TeamPlayer extends Player
FreePlayer extends Player
Attack, Protect structs or classes without inheritance, but as fields in Player class.
But I don't like such an approach and I am searching for a better design.
IMHO inheritance is the wrong model for this. Instead I would have a player class and different roles for it. It depends if a player can have multiple roles at the same time. I would use a strategy pattern.
How about composition and interface/dependency injection ?
<?php
interface IPlayer {
public function __toString();
}
class Player implements IPlayer {
protected $_id;
protected $_name;
public function __construct( $id, $name ) {
$this->_id = $id;
$this->_name = $name;
}
public function getId() { return $this->_id; }
public function setId($id) { $this->_id = $id; }
public function setName($n) { $this->_name = $n; }
public function getName() { return $this->_name; }
public function __toString() {
return 'my name is ' . $this->_name . ' and my id is ' . $this->_id;
}
}
class ComposedPlayer implements IPlayer {
protected $_player;
public function __construct( IPlayer $p ) {
$this->_player = $p;
}
public function __set($k, $v) {
$this->_player->$k = $v;
}
public function __get($k) {
return $this->_player->$k;
}
public function __call($func, $args) {
return call_user_func_array( array( $this->_player, $func ), $args );
}
public function __toString() {
return $this->_player->__toString();
}
}
class AttackPlayer extends ComposedPlayer {
function getNameMod() {
return 'attack player ' . $this->getName();
}
public function __toString() {
return parent::__toString() . ' and im an attack player';
}
}
class ProtectedPlayer extends ComposedPlayer {
function getNameMod() {
return 'protected player ' . $this->getName();
}
public function __toString() {
return parent::__toString() . ' and im an protected player';
}
}
class TeamPlayer extends ComposedPlayer {
function getIdMod() {
return $this->getId() - 10;
}
public function __toString() {
return parent::__toString() . ' and im an team player';
}
}
class FreePlayer extends ComposedPlayer {
function getIdMod() {
return $this->getId() + 10;
}
public function __toString() {
return parent::__toString() . ' and im an free player';
}
}
$free_attack_player = new FreePlayer( new AttackPlayer( new Player( 100, 'John' ) ) );
$free_protected_player = new FreePlayer( new ProtectedPlayer( new Player( 101, 'Bob' ) ) );
$team_attack_player = new TeamPlayer( new AttackPlayer( new Player( 102, 'Bill' ) ) );
$team_protected_player = new TeamPlayer( new ProtectedPlayer( new Player( 104, 'Jim' ) ) );
foreach ( array( $free_attack_player, $free_protected_player, $team_attack_player, $team_protected_player ) as $p ) {
echo 'id: ', $p->getId(), ' name: ', $p->getName(), ' mod id: ', $p->getIdMod(), ' mod name: ', $p->getNameMod(), PHP_EOL;
}
foreach ( array( $free_attack_player, $free_protected_player, $team_attack_player, $team_protected_player ) as $p ) {
echo $p, PHP_EOL;
}
Executing this will yield:
id: 100 name: John mod id: 110 mod name: attack player John
id: 101 name: Bob mod id: 111 mod name: protected player Bob
id: 102 name: Bill mod id: 92 mod name: attack player Bill
id: 104 name: Jim mod id: 94 mod name: protected player Jim
my name is John and my id is 100 and im an attack player and im an free player
my name is Bob and my id is 101 and im an protected player and im an free player
my name is Bill and my id is 102 and im an attack player and im an team player
my name is Jim and my id is 104 and im an protected player and im an team player
EDIT: updated to add a __toString() to the interface, an easy example of method composition.
This may be a problem where TDD can come very handy. The approach seems slow at first, but it is very useful when the design in not obvious. TDD tends to cause the design to emerge from the code itself.
If you are interested in giving TDD a try, you can maybe start from this blog, written by our company coach. Also, if you can, take a look at the two episodes here related to TDD (episode 6a and 6b): they are from Uncle Bob, so really suggested lectures/watch.
Player can be TeamPlayer or FreePlayer
TeamPlayer extend AttackPlayer or ProtectorPlayer FreePlayer extend AttackPlayer or ProtectorPlayer
I think, that this approach is ok. Think about the storing data. If you want to store it in the db, it would be nice approach: you have Player table with all of the player data, and create other tables(that extend Player table) to store data for different types of players.
Look at the Class Table Inheritance
In fact, inheritance hierarchy can be greater than one, but not more than 4. If inheritance is obvious, that is ok. The main rule is keeping complexity low.
On the other hand, if you are not going to store this data in db or foreign keys in player object to Free object etc. seems more obvious in your case - use another approach.
It can be mix of factory and Strategy as below:
Player can be Team Player or Free Player and can play using Attacker or Protector strategy. So Free Player or Team Player can inherit Player class and in them we can associate Playing strategy which can be Attacker or Protector. So in this case program initiator can call Factory to decide whether player is Free Player or Team Player and can pass the Strategy to use to play. Having strategy as association in Player will help keep code more extensible to add new strategies. Factory for type of player is separate from strategy so can extend independently. Using too much inheritance can cause issues in performance and maintenance of code.
Please do not take words like "extend" as java specific.
In the case that I have a class called Payment that it is a superclass of another class named Card, how can I join that class with another that verifies if the card is valid.
My UML diagram would be like this:
Payment<---------Card
I have thought of two ways of doing this, but I would like to know which one would be the correct one:
1) model with association to check if the credit card is valid, but not join this to paymentCard:
Card_list---1--------------1*---<>Card
so within my class Card I call something like:
class paymentCard extends Payment
{
public authorized() ---abstract method
{
if card.verified(card_number) return true; ---here I call the card class
else return false;
}
}
2) I have read that I can use aggregation, but I am a little dubious how to use it:
class paymentCard extends Payment
{
Card creditcard //aggregation
public authorized()
{
creditcard=new Card(numberCard)
if creditcard.verified() return true;
else return false;
}
}
which one of the two forms is better? For me, the first one looks like a query to a external class that can be also a database, while the second one I am not pretty sure about it
Any comment?
One day you could want to have other payment methods.
IMO, a Payment has a payment_method that can be ByCard, By..., so:
class Payment
{
protected PaymentMethodoption;
}
abstract class PaymentMethod
{
public abstract bool authorized();
}
class PaymentByCreditCard : PaymentMethod
{
public override bool authorized() { return card.verified(card_number); }
}
Well, you basically answered your own question. The key-question is: how expensive is creating a credit-card object? Probably is not just pass a number to it as you did on your second example, which means pobably you'll have them stored somewhere else.
I have a set of componentes registered to StructureMap. What should be the best way to resolve a component depending on the actual Tenant?
Small example:
There are two tenants, say, Yellow and Green.
I have an IValidator that has two implementations: YellowValidator and GreenValidator.
Say the application is MVC and that the tentant comes form the URL.
So, I just need the proper IValidator to be injected depending on the tenant.
I've seen many solutions for multi-tenant applications that deals only with multitenancy of data, normaly configuring different databases depending on the tenant. That involves only parameter passing. But this is the case where variation occurs in behavior, not in data. I want the IoC container to Resolve the right instance transparently.
EDIT: more info:
The IValidator interface have a simple method bool Validate(), but the implementation require some injection.
There are other custom validators, but they are used by both tenants.
There is a clear tentant strategy based on the URL. This means that each request can have a different tenant, and that a single application serves both tenants.
There are many ways to skin a cat. It's hard for me to guess the design of your application, so here is an idea. Things that come in mind are to hide validators behind a composite, to allow users of the IValidator interface to know nothing about having many implementations. Such composite can look like this:
public class ValidatorComposite : IValidator
{
private IEnumerable<IValidator> validators;
public ValidatorComposite(
IEnumerable<IValidator> validators)
{
this.validators = validators;
}
public bool Validate(object instance)
{
return this.validators.All(v => v.Validate(instance));
}
}
You can create multiple composites and register them by key where the key is the name of the tenant (but without keyed registrations is probably just as easy). Those composites can be wrapped in yet another composite that will delegate to the proper tenant-specific composite. Such a tenant-selecting composite could look like this:
public class TenantValidatorComposite : IValidator
{
private ITenantContext tenantContext;
private IValidator defaultValidator;
private IDictionary<string, IValidator> tenantValidators;
public ValidatorComposite(
ITenantContext tenantContext,
IValidator defaultValidator,
IDictionary<string, IValidator> tenantValidators)
{
this.tenantContext = tenantContext;
this.defaultValidator = defaultValidator;
this.tenantValidators = tenantValidators;
}
public bool Validate(object instance)
{
string name = this.tenantContext.CurrentTenant.Name;
return this.defaultValidator.Validate(instance) &&
this.tenantValidators[name].Validate(instance);
}
}
The ITenantContext is an abstraction that allows you to get the current tenant within the current context. You probably already have something like that in place, but I imagine an implementation to look something like this:
class UrlBasedTenantContext : ITenantContext
{
public Tenant Current
{
get
{
// Naive implementation.
if (HttpContext.Current.Request.Url.Contains("tenant1"))
{
return Tenant1;
}
return Tenant2;
}
}
}
Create a TenantValidatorComposite would be easy:
var defaultValidator = CompositeValidator(
GetAllDefaultValidators());
var tenantValidators = new Dictionary<string, IValidator>()
{
{ "tenant1", new CompositeValidator(GetValidatorsFor("tenant1")) },
{ "tenant2", new CompositeValidator(GetValidatorsFor("tenant2")) },
};
var tenantValidator = new TenantValidatorComposite(
new UrlBasedTenantContext(),
defaultValidator,
tenantValidators);
I hope this helps.