Bug with my relation HasMany/BelongsTo - sql

I have a model Work with this relation
public function types()
{
return $this->belongsTo('App\Models\Type');
}
And a model Type with this relation
public function works()
{
return $this->hasMany('App\Models\Work');
}
I try to access in my view show view to type but I've a lot of errors
Undefined property: Illuminate\Database\Eloquent\Relations\BelongsTo::$name
I try this : $work->types()->name for get data.
In my DB, my table 'Works' have a foreignkey 'type_id'.
I would like to get the 'type' of the post. There can be only one per post.
Thank you very much !

Semantically you want to make your relationships like so:
Work
// A work is of a single type
public function type()
{
return $this->belongsTo('App\Models\Type');
}
Type
// A type of work can have many items of work
public function works()
{
return $this->hasMany('App\Models\Work');
}
You can then access the relationship like so:
$type = Work::first()->type // return object of type Type
$works = Type::first()->works // return collection of objects of type Work
EDIT
By accessing the relationship with () you are returning the underlying query builder instance of the relationship and you will need to finish your statement with ->get() like so:
$works = Type::first()->works()->get();

You should have on Work Model:
public function type()
{
return $this->belongsTo('App\Models\Type');
}
and on your view:
$work->type->name;

Since you are not using default id as foreign key you should add
protected $primaryKey = "type_id";
in your model

Related

Kohana - Best way to pass an ORM object between controllers?

I have Model_Group that extends ORM.
I have Controller_Group that gets a new ORM:
public function before()
{
global $orm_group;
$orm_group = ORM::factory('Group');
}
...and it has various methods that use it to get different subsets of data, such as...
public function action_get_by_type()
{
global $orm_group;
$type = $this->request->param('type');
$result = $orm_group->where('type', '=', $type)->find_all();
}
Then I have another controller (in a separate module) that I want to use to manipulate the object and call the relevant view. Let's call it Controller_Pages.
$orm_object = // Get the $result from Controller_Group somehow!
$this->template->content = View::factory( 'page1' )
->set('orm_object', $orm_object)
What is the best way to pass the ORM object from Controller_Group to Controller_Pages? Is this a good idea? If not, why not, and what better way is there of doing it?
The reason for separating them out into different controllers is because I want to be able to re-use the methods in Controller_Group from other modules. Each module may want to deal with the object in a different way.
This is the way I would do it, but first I would like to note that you shouldn't use global in this context.
If you want to set your ORM model in the before function, just make a variable in your controller and add it like this.
public function before()
{
$this->orm_group = ORM::factory('type');
}
In your Model your should also add the functions to access data and keep the controllers as small as possible. You ORM model could look something like this.
public class Model_Group extends ORM {
//All your other code
public function get_by_type($type)
{
return $this->where('type', '=', $type)->find_all();
}
}
Than in your controllers you can do something like this.
public function action_index()
{
$type = $this->request->param('type');
$result = $this->orm_group->get_by_type($type);
}
I hope this helps.
I always create an helper class for stuff like this
Class Grouphelper{
public static function getGroupByType($type){
return ORM::factory('Group')->where('type','=',$type)->find_all();
}
}
Now you're been able to get the groups by type where you want:
Grouphelper::getGroupByType($type);

How to change the format of an attribute in a CActiveRecord returned by a findAll method?

I have an attribute in my model that is stored in binary format inside database.
In case the attribute is a geometric( polygon ) object.
This object can be casted to several string representations.
So how can I attach an event after a find execution that allows me to change the attribute on returned set only?
My first guess was to use the onAfterFind event but it is not calling the handler with the created element as documentation suggests. My first attempt was the following in the controller.
// an activeRecord class
GeoTableBinaryData extends CActiveRecord {
... // normal active record with a table which has a binary attribute called geom
}
$model = GeoTableBinaryData::model();
$model->onAfterFind->add(
function( CEvent $evt ){
// get the finded object to update the geom attribute on the fly here want
// a text representation in other case would transform it to XML or JSON
}
);
foreach ( $model->findAll() as $geoInfo )
{
... // output serialized geometry
}
The correct way of doing this, is that in your model have a afterFind method like:
protected function afterFind()
{
$this->someAttribute = $this->methodToChangeTheAttribute($this->someAttribute);
return parent::afterFind();
}
and that's all, when you will use AR's methods, every found model will pass through afterFind() and alter the someAttribute as you want.
You can also write getters for your different formats:
public function getGeoAsString()
{
// Create the string from your DB value. For example:
return implode(',', json_decode($this->geom));
}
Then you can use the geoAsString like a regular (read-only) attribute. You can also add a setter method, if you want to make it writeable.

Save data from a form collection

I have been following http://framework.zend.com/manual/2.1/en/modules/zend.form.collections.html and it works great with validation and so on.
When the form is valid the guide just runs a var_dump on the entity and it looks something like this:
object(Application\Entity\Product)[622]
protected 'name' => string 'Chair' (length=5)
protected 'price' => string '25' (length=2)
protected 'categories' =>
array (size=2)
0 =>
object(Application\Entity\Category)[615]
protected 'name' => string 'Armchair' (length=8)
1 =>
object(App1ication\Entity\Category)[621]
protected 'name' => string 'Office' (length=6)
The categories can be more then 2 or just 1. How to save a normal form to a database table I understand and have no problem with. But here we have data for two different tables. I guess I could manually read the categories in my controller and fill them in to a model and save them row by row. But that doesn't feel like the best way of doing it.
How do I get the data from the entity to a model or my database? Can it be done without Doctrine?
You have two choices: getData() or bind().
bind() is the "automatic" way - you bind an entity to your form object which has a property on that entity which matches the name of your collection. Then, when the form's isValid() method is called, the binding mechanism will pass the values from the collection's elements to the matching property on the entity.
Alternatively, you can use getData() on the collection object and then do whatever you need to.
Once you have an entity, to save it, consider using ZfcBase as that does the hard work for you.
This is a simple example mapper:
namespace MyModule\Mapper;
use ZfcBase\Mapper\AbstractDbMapper;
use Zend\Stdlib\Hydrator\ArraySerializable;
use MyModule\Entity\MyEntity;
class MyMapper extends AbstractDbMapper
{
protected $tableName = 'my_table';
public function __construct()
{
$this->setHydrator(new ArraySerializable());
$this->setEntityPrototype(new MyEntity());
}
public function save(MyEntity $entity)
{
if (!$entity->getId()) {
$result = $this->insert($entity);
$entity->setId($result->getGeneratedValue());
} else {
$where = 'id = ' . (int)$entity->getId();
$this->update($entity, $where);
}
}
public function fetchAll($choiceGroupId)
{
$select = $this->getSelect($this->tableName);
return $this->select($select);
}
public function loadById($id)
{
$select = $this->getSelect($this->tableName)
->where(array('id' => (int)$id));
return $this->select($select)->current();
}
}
This mapper is using the ArraySerializable hydrator, so your entity object (MyEntity in the example) must implement the methods getArrayCopy() and populate(). getArrayCopy() returns an array of data to be saved and populate() is used to fill the entity from an array of data from database.

Fluid NHibernate, Custom Types and Id mapping

I have an object in C# that I want to use as a primary key in a database that auto-increments when new objects are added. The object is basically a wrapper of a ulong value that uses some bits of the value for additional hints. I want to store it as a 'pure' ulong value in a database but I would like get an automatic conversion when the value is loaded / unloaded from DB. IE, apply the 'hint' bits to the value based on the table they come from.
I went on a journey of implementing my own IUserType object based on number of examples I found online ( tons of help on this forum ).
I have an ObjectId class that acts is an object ID
class ObjectIdType: IUserType
{
private static readonly NHibernate.SqlTypes.SqlType[] SQL_TYPES = { NHibernateUtil.UInt64.SqlType };
public NHibernate.SqlTypes.SqlType[] SqlTypes
{
get { return SQL_TYPES; }
}
public Type ReturnedType
{
get { return typeof(ObjectId); }
}
...
}
I have a mapping class that looks like this:
public class ObjectTableMap()
{
Id(x => x.Id)
.Column("instance_id")
.CustomType<ObjectIdType>()
.GeneratedBy.Native();
}
At this point I get an exception at config that Id can only be an integer. I guess that makes sense but I was half expecting that having the custom type implemented, the native ulong database type would take over and work.
I've tried to go down the path of creating a custom generator but its still a bit out of my skill level so I am stumbling though it.
My question is, is it possible for me to accomplish what I am trying to do with the mapping?
I think, it is not possible, because your mapping uses the native generator for the Id. This can only be used for integral types (and GUIDs). You can try to use assigned Ids with your custom type, so you are responsible for assigning the values to your Id property.
There is another alternative: Why not set your information bits on class level, instead depending on your table? Your entities represent the tables, so you should have the same information in your entity classes. Example:
class Entity
{
protected virtual ulong InternalId { get; set; } // Mapped as Id
public virtual ulong Id // This property is not mapped
{
get
{
var retVal = InternalId;
// Flip your hint bits here based on class information
return retVal;
}
}
}
You could also turn InternalId into a public property and make the setter protected.

Dynamic Type Creation

I'm trying to create a dynamic type in .Net.
I want to get a group of Key Value pairs from a DB table and create a new type of object that has a Property-Value relation.
Example:
If I have a row in the table that has a field that says "Licence Plate" and the other field says "STKOVFL". I want to create an object that has a Property called Licence_Plate, and returns the String "STKOVFL".
Is it possible with introspection?
Best Regards!
Here is an very simple example of what your trying to do.
public class ExampleD : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
if (binder.Name == "Licence_Plate")
result = "STKOVFL";
return result != null;
}
}
Console.WriteLine(d.License_Plate);