Trying to make models in Kohana, relations problem - orm

I have a table of Hits, Articles and Categories
Now, a Hit belongs_to an Article/Category (depends on where it was done).
so I have a column on Hits table with the name 'parenttype'
That tells me 'Article' or 'Category'.
I wrote in the Hit model (extends ORM)
protected $_belongs_to= array(
'page' => array('model'=> $this->parenttype)
);
Now it complains about $this->parenttype not being expected?

you should declare the variable protected $_belongs_to = NULL;
and on the constructor set it's value after calling the parent class constructor
public function __construct() {
parent::__construct();
$this->_belongs_to = array('page' => array('model' => $this->parenttype));
}

How do you intend to access $this if the object is just about to be instantiated?
( even if you could, $this->parenttype definitely hasn't been loaded before relations were )
This means you need to define that relation some other way, a little bit later :)
( I still don't like the way you're doing it )

Related

LINQ query take(count) from collection of child elements

How can I make LINQ query (I am using Entity Framework) that returns top n elements in a child collection?
Here are example classes
public class A {
public int ID
public ICollection<B> bData
}
public class B {
public int ID
public string Name
}
This is kind of query I was thinking;
db.A.Where(a => a.ID == query_id).Include(a => a.bData.Take(count)).ToList();
Normally this doesn't work, how could I accomplish this?
The Include method is intended for eager loading the related entity data. It's all or nothing and cannot be used for filtering, sorting, grouping etc.
So what are you asking for can be accomplished with projection (select). It would be simpler if you project to anonymous or custom type (a.k.a. DTO object), because EF does not allow projecting to entity type. But it's still doable by using anonymous type projection in LINQ to Entities query and doing second projection in LINQ to Objects to attach the filtered child collection to its parent entity like this:
var result = db.A
.Where(a => a.ID == query_id)
.Select(a => new { a, bData = a.bData.Take(count).ToList() })
.AsEnumerable() // Switch to LINQ to Object context
.Select(x =>
{
x.a.bData = x.bData;
return x.a;
})
.ToList();
Please note that in order the above to work, bData member should not be virtual or db.Configuration.LazyLoadingEnabled should be false (i.e. lazy loading should be off, otherwise the bData collections will be fully reloaded when first accessed).

Gii doesn't recognize many-to-many relationship to itself?

So I am trying to implement a friendlist, the above is the SQL diagram I made for my simple project and after generating the Models. I realized there was something wrong with the way Gii generated the model.
I wanted to make a many-to-many relationship with User to itself, but this is what I got:
class User {
...
public function getPosts()
{
return $this->hasMany(Post::className(), ['userId' => 'id']);
}
}
class Friend {
...
public function getFriend()
{
return $this->hasOne(Member::className(), ['id' => 'friendId']);
}
}
The User class doesn't have any relationship with itself, I expected something like getUsers() inside of User, but it didn't generate it. I initially thought about not making a model with the junction table, but I did so just to see what would happen. I don't think I need it. So I am not sure how to do this correctly? Do I need to get rid of my Junction Table Models and Do I need to make the relationship between User to itself and User to Message manually? I thought about doing a many-to-many in User and Message and a many-to-many in User for User. Is this the right thing? Tell me if I am wrong. Thank you.
You are on a true way. You need a junction table for implementing your goal. Easily as you done this, you must define two model: User and Friend. Now on your User model at first you must define a relation for get the list of all friends, Suppose call it getFriendsLists:
public function getFriendsLists()
{
return $this->hasMany(Friend::className(), ['userId' => 'id']);
}
This relation says that "Get me all account that are connected with me, i.e. if my id is 102, this relation return all record of friend table that their userIds are 102". Well, now we get all friends with a relation on User model, let call him getFriends:
public function getFriends()
{
return $this->hasMany(User::className(), ['friendId' => 'id']
->via('friendsList');
}
Notice that 'friendsList' as is a parameter of via method, is our predefined relation on top of this answer. Now easily you can get all account that are friends of our example (User with id 102):
public FriendController extends Controller
{
// Some code goes here!
public function actionFriendList($id)
{
$user = User::findOne($id);
$friends = $user->friends;
return $this->render('friend-list', ['friendsArray' => $friends]);
}
}
And use them on your friend-list view file as $friendsArray variable. Extra note that $user->friends use friends relation that you defined on User model with getFriends method.

Lithium Framework Architecture - Call One Controller from Another

I'm working on a web app using the Lithium Framework with a MongoDB database.
On one page of the application - I want to display data from multiple object types. I understand the concept of relationships (i.e. belongsTo, hasMany, etc.) between models. But, my questions has to do with Controller relationships.
For example, assume I have two objects named "People" and "Companies". I want to show specific information about Companies on a "people" view. I have done the following:
1) In the "People" model, I've added the following line:
public $belongsTo = array('Companies');
2) In the "PeopleController" file, I've also included a reference to the Companies Model, such as:
use app\models\Companies;
Now, within the PeopleController, I want to call a method in the CompaniesController file.
Do I access this by directly calling the CompaniesController file? Or, do I have to go thru the Company model.
In either case, I'll need help with the syntax. I'm having rouble figuring out the best way this should be called.
Thanks in advance for your help!
You should rethink your structure - you controller method should really grab all the resources you need for that view, it doesn't matter what they are.
So if you have a url '/people/bob' and you want to get the company data for Bob just add that to the view method of your People controller. Something like
People::first(array('conditions' => array('name' => 'Bob'), 'with' => 'Companies'));
You could instantiate a CompaniesController (maybe passing in $this->request to the 'request' option in the process) and then call the method in it. However, a better way to organize it is to move the common functionality from CompaniesController to Companies and call it from both places.
use app\models\Companies does not really make a "reference." It simply indicates that Companies really means app\models\Companies. I think an "alias" is a better way to think of it. See http://php.net/manual/en/language.namespaces.importing.php.
Example:
// in app/models/Companies.php
namespace app\models;
class Companies extends \lithium\data\Model {
public static function doSomething() {
// do something related to companies.
}
}
// in app/controllers/CompaniesController.php
namespace app\controllers;
use app\models\Companies;
class CompaniesController extends \lithium\action\Controller {
public function index() {
$result = Companies::doSomething();
return array('some' => 'data', 'for' => 'the view');
}
}
// in app/controllers/PeopleController.php
namespace app\controllers;
use app\models\Companies;
class PeopleController extends \lithium\action\Controller {
public function index() {
$result = Companies::doSomething();
return array('some' => 'data', 'for' => 'the view');
}
}

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.

Fluent NHibernate - override type for one specific property on one specific class?

I have a class that has a password property that I want to store encrypted in the db. The property is a string type, and I have a custom type EncryptedStringType that I want NHibernate to use to map this to the database. Here is my relevant automapping code:
var mappings = AutoMap.AssemblyOf<Business>()
.Where(x=>x.IsSubclassOf(typeof(EntityBase)))
.IgnoreBase(typeof(EntityBase))
.Conventions.Add
(
ConventionBuilder.Id.Always(x =>
x.GeneratedBy.HiLo(HILO_TABLE, HILO_COLUMN, HILO_MAX_LO)),
ConventionBuilder.HasMany.Always(x => x.Cascade.AllDeleteOrphan()),
Table.Is(o => Inflector.Pluralize(o.EntityType.Name)),
PrimaryKey.Name.Is(o => "Id"),
ForeignKey.EndsWith("Id"),
DefaultLazy.Always(),
DefaultCascade.All()
);
I cannot figure out the syntax to override the type for the UserPassword property of the Business class though. I thought I should be able to do something with overrides like:
mappings.Override<Business>(map=> /* Not sure what to do here */);
Any help is appreciated.
Found the answer myself.
mappings.Override<Business>(map =>
{
map.Map(x => x.UserPassword).CustomType<EncryptedStringType>();
});
You could always create a mapping override class. Any conventions that can still be applied will be, but you can basically specify mappings similarly to a ClassMap that override the default conventions.
Using the call to mappings.Override(), it'd look something like:
mappings.Override<Business>(map=>map.Map(x=>x.UserPassword).CustomType(typeof(EncryptedStringType)));