Yii Framework Forum: Active Record - Yii Framework Forum

Jump to content

  • (3 Pages)
  • +
  • 1
  • 2
  • 3
  • You cannot start a new topic
  • You cannot reply to this topic

Active Record

#21 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 05 August 2011 - 06:54 AM

View Postqiang, on 02 August 2011 - 11:55 AM, said:

My point is that AR is a crucial part of Yii and shouldn't be made optional, even though you can choose not to use it.


In my opinion, the entire DB package is a good candidate for a package - the ability to use alternative storage solutions is becoming an increasingly relevant topic every day.

I think I would argue that an entire feature, such as Yii's database abstraction layer (of which AR is a subset) is a great candidate for something optional.

View Postqiang, on 02 August 2011 - 11:55 AM, said:

If we make it optional, the next very natural question would be: should we turn something else into optional, such as different caching components, DB session storage, and so on. Why are we creating these artificial difficulties to ourselves and to end users?


I agree, and I would not argue for distributing Yii without the DB/AR package.

What I would argue though, is that if it came in the distribution in the form of a package, that makes it more obvious to everyone that I have a choice - so I can feel confident hitting the delete key and pulling in an entirely different storage layer. A lot of professionals will prefer Doctrine, for example - and in the future, increasing number of developers will probably prefer a graph/document-database.

I think it's important to show that we've thought of this, and to clarify that nobody is forced to accept every aspect of Yii for every aspect of development.

I don't expect to see Yii's storage layer become something you can "replace" from underneath an existing application. But it would be nice if there were no direct ties between a basic web-application and the built-in database abstraction. It's a matter of choice.
0

#22 User is offline   Haensel 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 444
  • Joined: 14-January 11
  • Location:Vienna (Austria)

Posted 12 August 2011 - 08:22 AM

I already use a graph database in my project (Neo4j) because it is the only sane way I know to model complex relationships. I created my own ActiveRecord like class to talk to the database and it was a real pain to do that as AR is so deeply rooted within the SQL world. So thumbs up for an abstraction layer to allow different storage types.

Anyways, I hope it's not too off topic but another AR-like feature that I personally think is very interesting is the ActiveRESOURCE approach Rails provides (http://api.rubyonrai...ource/Base.html). This could be interesting in terms of SOA as different Yii applications would be able to communicate via a standardized REST layer.
0

#23 User is offline   grigori 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 41
  • Joined: 06-February 11

Posted 01 September 2011 - 07:15 PM

+1 for ability to remove DB access layer completely and replace by Doctrine.
Yii AR is small and efficient, but there are intranet projects with other requirements.

I miss collections that support and optimize multiple rows and relations.
$PostCollection = $new PostCollection;
foreach ($data as $row) $PostCollection->addRow($row);
$PostCollection->save();
$PostCollection->Users->update(...)
0

#24 User is offline   Rodrigo Coelho 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 664
  • Joined: 05-August 10
  • Location:Rio de Janeiro, Brazil

Posted 01 September 2011 - 11:02 PM

View Postsamdark, on 21 July 2011 - 01:30 PM, said:

Possible usage is to create good looking API for related models management:

$tag = new Tag();
$tag->name = 'Yii';

$post = Post::model()->findByPk(1);
// add will save $tag into $forSaving array so AR will save just this one instead of deleting-saving every tag out there
$post->tags->add($tag);
$post->save();



I like this API, but in some cases (like receiving data from a form), you will need to delete-save (or other better approach).
0

#25 User is offline   thyseus 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 300
  • Joined: 18-April 09
  • Location:Leipzig, Germany

Posted 03 September 2011 - 10:13 AM

I would like to see support for automatically validating & updating related Models.

A example:



class Post extends ActiveRecord {
 function relations() {
  return array('comments' => self::HAS_MANY, 'Comment', 'post_id');
}
}

$model = Post::model()->findByPk(5);
$comment = new Comment;
$comment->author = Yii::app()->user->id;
$comment->title = $title;
$model->comments[] = $comment;
$model->save();


This would save the Post model, and as well will save the
comment and attaches it to the post, by setting the post_id to
the primary key of the post model.

Multiple assignments would also be possible, either by passing
object instances or just pk's of the foreign objects.

Validation could also be done something like this:

function rules() {
 return array('comments', 'min' => 3, 'error' => 'In order to save this post, it needs at least 3 comments');
}


There are three implementations for this, from which
i recommend the first two (i never looked at the third):

http://www.yiiframew...ancedarbehavior
http://www.yiiframew...ons-ar-behavior
http://www.yiiframew...n/saverbehavior

What do you think about this idea?
0

#26 User is offline   phtamas 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 526
  • Joined: 26-February 11
  • Location:Mezőtúr, Hungary

Posted 04 September 2011 - 07:28 AM

View Postthyseus, on 03 September 2011 - 10:13 AM, said:

I would like to see support for automatically validating & updating related Models.

A example:




class Post extends ActiveRecord {
 function relations() {
  return array('comments' => self::HAS_MANY, 'Comment', 'post_id');
}
}

$model = Post::model()->findByPk(5);
$comment = new Comment;
$comment->author = Yii::app()->user->id;
$comment->title = $title;
$model->comments[] = $comment;
$model->save();



I think it would be difficult to implement at framework-level in a way that satisfies everyone's needs.
It's pretty clear in your example that you want to add the new comment to existing ones, but what do you think about this:
$post->tags = array($tag1, $tag2);
$post->save();


Should the new tags be added to existing ones or should they replace the old ones?
I'd prefer to handle it at application level - with the help of available extensions.

EDIT: Sorry, it's already solved by samdark's proposal :
$post->tags->add($tag); // add new tag
$post->tags->set(array($tag1, $tag2)); // (or similar syntax) replace tags

This post has been edited by phtamas: 04 September 2011 - 07:47 AM

1

#27 User is offline   lubosdz 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 112
  • Joined: 25-July 10
  • Location:Slovakia, Bratislava

Posted 14 September 2011 - 09:37 AM

Let me add my 3 cents:-)

  • current Yii's AR is very well implemented. It has good API and excellent performance. One of the reasons I opted for Yii. It should continue this way - being lightweight cross storage compatible layer with caching options.
  • replacing with doctrine - no way ! - huge performance degradation.
  • AR should be part of the core. It takes 400 - 500 kB unzipped code, which is irrelevant.
  • API should stay backward compatible as much as possible. It is intuitive and it would ease migrations.


What can be improved regarding AR:
=================================
  • abstracting the storage NOT to be bound only to PDO. SamDark's points 1 + 2.
  • fixing problem with column quoting. Especially the Criteria::where, AR::where conditions - this is currently one of the biggest flaws in version 1.1.X.
  • cross portability should be tested before each release by running standardized CRUD unit tests for EACH supported database. I know it's a pain to set up environment, but would undisclose great part of bugs reported currently for Yii issues regarding AR. If it would not be possible to test all supported storages then it would be good to distribute AR unit tests with core so that users can test it easily.


Lubos
Yii extension: Captcha Extended

Greatest discoveries in 22nd century will be about the gravitation. | http://www.synet.sk | http://ipdf.sk
0

#28 User is offline   Thomas Jensen 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 150
  • Joined: 01-August 09

Posted 16 September 2011 - 06:27 PM

In my opinion Yii AR works very well. I'ts well balanced between not trying to accomplish too much while still dealing with most everyday problems in a nice way.

Yii AR should be a part of the core. As qiang stated, neither space nor IDE performance should be a problem to anyone. Having optional packages is just going to confuse new users more than necessary.

My proposals for AR:

  • Methods should have precedence over db fields. "getName" should be invoked by "->name", even though "name" is also a field in the db.

  • When attributes are changed, their old value should be saved (for trails or other uses), and there should be kept an index with "dirty" attributes allowing AR to only save "dirty" attributes on save.

  • There should be kept an index of all AR models, so that the same model (same primary key) can't be represented by to or more instances. E.g. $a = AR::findByPk(1), $b = AR::findByPk(1), $a->field = 'changed', $a->field === $b->field.

3

#29 User is offline   Gustavo 

  • Master Member
  • Yii
  • Group: Moderators
  • Posts: 916
  • Joined: 27-July 10
  • Location:Curitiba - Brasil

Posted 22 September 2011 - 06:06 PM

View Postqiang, on 22 July 2011 - 11:22 AM, said:

@mindplay: I totally agree with you. We have to be realistic. Our goal is NOT trying to make AR support different storage types under the same set of interfaces. Our abstraction should be very limited, perhaps only to how the fetched data to be retrieved so that they can be used to provide data to the same UI components.


I agree with that.
Altho, it should abstract some classes so users can have an option to create their own extension when needed

Something like this looks fine to me

CConnection as an abstract class that connects with any storage type, with a couple abstract common methods, like connect, executeCommand, openConnection, closeConnection, etc
CDbConnection extending CConnection having specific pdo/sql methods
CAbstractActiveRecord extending CModel, with a couple abstract common methods, like save, find, delete, insert, findAll
CActiveRecord extending CAbstractActiveRecord, that uses CDbConnection and have specific sql methods like findAllBySql, etc

this way users can having something like

myConnection extening CConnection
myActiveRecord extending CAbstractActiveRecord, that uses myConnection and have their own specific command to find, save, delete, etc

What do you think ?
--
Extensions:
translate modue - module to handle translations
multiActiveRecord - db selection in models
redisCache - redis cache component
mpCpanel - interact with cpanel api
mUploadify - use uploadify uploader in your application

Gustavo Salomé Silva
0

#30 User is offline   Psih 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 114
  • Joined: 30-June 10

Posted 23 September 2011 - 03:02 AM

View PostGustavo, on 22 September 2011 - 06:06 PM, said:

I agree with that.
Altho, it should abstract some classes so users can have an option to create their own extension when needed

Something like this looks fine to me

CConnection as an abstract class that connects with any storage type, with a couple abstract common methods, like connect, executeCommand, openConnection, closeConnection, etc
CDbConnection extending CConnection having specific pdo/sql methods
CAbstractActiveRecord extending CModel, with a couple abstract common methods, like save, find, delete, insert, findAll
CActiveRecord extending CAbstractActiveRecord, that uses CDbConnection and have specific sql methods like findAllBySql, etc

this way users can having something like

myConnection extening CConnection
myActiveRecord extending CAbstractActiveRecord, that uses myConnection and have their own specific command to find, save, delete, etc

What do you think ?

Personally I think that the KISS principle should be respected as much as possible. It's too easy to make an abstract on the abstract on the class exteding throught 2 more parent classes.
PHP is not Java - some things need to be simple and straight forward.
Mixing SQL and NOSQL can be done to some degree in Active Record, but reality is - you will gain nothing then. The power of the NOSQL is that there is no structure at all and linking between the entities can be very complex. Not to mention the fetching of the data.
There should be a very careful thinking through process and careful design. And if it doesn't fit together - screw it - just make 2 sets of models - Active Record for SQL and NOSQL models and make them able to link together via relations.
0

#31 User is offline   Rangel Reale 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 68
  • Joined: 14-January 10

Posted 07 November 2011 - 09:43 AM

Some things I've done in my custom Yii version:

- CModel child / parent relationship - CModel has 2 new properties "parentModel" and "parentAttribute" - with this, I can build a tree for saving inner models with a save on the parent.
- CModelCollection: base class for model collections. It is simply a CModel in what each "property" is a CModel. It has a "save" method that saves all models within it. All relations that returned an array now returns a CModelCollection, and a custom CModelCollection class can be specified on the relation parameters.
- In CActiveRecord properties defined as "safe" in rules() that are CModel are saved together with the parent model. I implemented some more checkings for saving order (saving HAS_MANY after the main model as to have the base model autoinc ID ready).

It's a little more complicated than that, but these are the basic ideas.
0

#32 User is offline   Lukas Kahwe Smith 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 13
  • Joined: 05-November 11

Posted 08 November 2011 - 11:24 AM

remember that static methods make unit testing really hard
0

#33 User is offline   dyulax 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 21
  • Joined: 26-May 11
  • Location:Brazil

Posted 16 November 2011 - 10:34 AM

It would be nice if AR does not need a "model" method to be called:

$something = SomeModel::find(...);
// instead of
$something = SomeModel::model()->find(...);


It could be easily solved with a get_called_class() (PHP 5.3).
Do what thou wilt shall be the whole of the Law.
0

#34 User is offline   jellysandwich 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 86
  • Joined: 03-May 11

Posted 24 November 2011 - 12:43 PM

View Postdyulax, on 16 November 2011 - 10:34 AM, said:

It would be nice if AR does not need a "model" method to be called:

$something = SomeModel::find(...);
// instead of
$something = SomeModel::model()->find(...);


It could be easily solved with a get_called_class() (PHP 5.3).


I concur.

But if these methods are still required, at least take them out from the gii generated models and put them into the base class.

For example, this is what I use:

    
class ActiveRecord extends CActiveRecord
{    
    /**
     * Returns the static model of the specified AR class
     * @param string $className
     * @return object the static model class
     */
    public static function model($className = "")
    {
        // gets the input class name, or the called class name (aka, the child class)
        return ($className) 
            ? parent::model($className) 
            : parent::model(get_called_class());
    }
    
    /**
     * Gets table name based on class name
     * @return string the associated database table name
     */
    public function tableName()
    {
        // gets the called class name
        $calledClassName = strtolower(get_called_class());
        
        // adds in table prefix if it is set
        return (Yii::app()->db->tablePrefix) ? '{{'.$calledClassName.'}}' : $calledClassName;
    }
}

1

#35 User is offline   mindplay 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 397
  • Joined: 03-September 09
  • Location:New York

Posted 27 November 2011 - 12:49 PM

My biggest gripe with the current implementation, is the fact that persistence management is mixed into the model type itself.

What I mean is, Post::model() actually returns an instance of Post - some kind of reserved singleton instance of the model-type, with special privileges and responsibilities.

It feels wrong.

I would like to see the repository manager untangled from the model entity.

For example, where you have this:

$post = Post::model()->findByPk(1);

$post->title = 'New title';

$post->save();


I would prefer to have something like this:

$post = Yii::app()->posts->findByPk(1);

$post->title = 'New title';

Yii::app()->posts->save($post);


Yii::app()->posts in this case is the dedicated repository manager for the Post type, which is a pure model-type without the storage aspects blended into it.

Basic CRUD repository operations can be standardized: findByPk(), save() and delete().

The rest can be specific to the storage implementation. The PDO/SQL implementation would support all the usual stuff, findAll(), findFirst() etc. with the usual bits and pieces of SQL-expression where needed. A third-party graph or document storage engine would have it's own dedicated API.

The point is not to try to support multiple engines with one API, except for the basic load/save/delete for individual entities; the idea here, is to separate concerns.

Think about other potential storage engines, such as a flat-file storage engine for configurations, or a cache-provider for some key/value engine. A cache is just another kind of repository.

On a related note, PHP 5.4 has real support for mix-ins in the form of "traits" - which would make it possible to have the same semantic syntax as before, e.g. $post->save() or $post->delete(), rather than the elaborate Yii::app()->posts->save($post); but with the important difference that the save() and delete() methods are not methods of the Post class, avoiding this ugly static dependency for the storage aspect...
1

#36 User is offline   Rodrigo Coelho 

  • Master Member
  • PipPipPipPip
  • Yii
  • Group: Members
  • Posts: 664
  • Joined: 05-August 10
  • Location:Rio de Janeiro, Brazil

Posted 28 November 2011 - 05:17 AM

View Postmindplay, on 27 November 2011 - 12:49 PM, said:

My biggest gripe with the current implementation, is the fact that persistence management is mixed into the model type itself.


I bugs me a little, too.
This is a problem with Active Record itself and with MVC.

There could exist something like P+MVC (or PMVC), where the persistence should explicitly be separated from the domain model.

The decoupling in this architectural pattern would create a better abstraction and more flexibility.
The downsides are some additional complexity (not much, in my opinion) and a new learning curve (something that may be troublesome for Yii 2.0).
0

#37 User is offline   Psih 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 114
  • Joined: 30-June 10

Posted 28 November 2011 - 08:09 AM

Globally the AR we have in 1.1.x is just fine in it's implementation, just missing related model management (saving, deleting and so on) and multilingual functionality.

What really bugs me (and at work we have stumbled on this) is that PDO is quite restrictive in it's feature set. We work with MySQL only (5.5) and we really are considering using a wrapper for the MySQLi extension to replace the PDO because we are in need of features the extension providers (*_ping, *_fetch_array, *_multi_query, even some async queries would be helpful). And our project isn't something that PHP is unfit to deal with - it does it's job perfectly and Yii makes that job even pleasurable. Just inability to use full DB functional due to the PDO not providing ability to use DB specific functions and being stuck in it's development as PHP devs have acknowledged.
0

#38 User is offline   yyeshua 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 18
  • Joined: 15-October 11
  • Location:Honduras

Posted 23 January 2012 - 12:52 AM

Some time without no post here, but I want share some notes.

I like the AR Yii approach, but right now I feel that need some extra stuff.

I has use Doctrine 2. I like it too, but its so complex... well, anyway Doctrine 2 have nice things.

Anyway, following some line like midplay, samdark, Rangel Reale... I think the next AR implementation on Yii must have some little Data-Mapper approach. This for separate the logical from the Model class to a Repository/Store/Storage class.

I see the AR model class/object like a ToyStory alien... but right now we do not have "The Claw". And the claw must have the function for CRUD operation over the ToyStory aliens. :)

So for the next AR implementation on Yii 2 I want somthing like a Claw :)

$theClaw = Yii::app()->db->storage;

$alien = $theClaw->findByPk('Alien', 1);

$alien->eyes = 3;

$theClaw->save($alien);

//or

$dbCriteria = new dbCriteria(...);
$manyAlliens = $theClaw->find('Alien', $dbCriteria);

//or like repos

class ClawForAliens extend BaseClaw{
  public function findByXYZ(){
    $dcCriteria = ...;
    $moreAliens = self::findByCriteria($dcCriteria, 'array');
    return $moreAliens;
  }
}

$aliensClaw = new ClawForAliens();
$moreAliens = $aliensClaw->findByXYZ();


PD: And will be nice more commands for AR from the yiic cli :)
0

#39 User is offline   Weavora Team 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 141
  • Joined: 06-December 10

Posted 23 January 2012 - 02:03 AM

What I will love to see into Yii 2 AR:

1. Separate Model and ModelManager (or ModelService or whatever you like to call it)

$post = PostManager::getByPk(1); // get always return signle Post instance
$posts = PostManager::findByPk(1); // find always return Posts collection
$post = PostManager::getByCustomCriteria();


I mean - model should incapsulate directly related to model instance stuff. Manager should care about how to find model(s), or some other domain logic.


2. Support model collection class

$posts = PostManager::findAll(); // will return PostCollection
$posts->delete(); // delete will perfomed to each posts into collection
$posts->add(new Post());
$posts->someCustomMethod();
$posts->save(); // save all posts into collection
$posts->filterByAttributes(array('type' => Post::PENDING));

$posts->
  each(function($post, $index){
    $post->type = Post::APPROVED;
  })->
  save(); 


3. Save model with relations

$post = PostManager::findByPk(1);
// append comment ([] alias of CommentCollection::add())
$post->comments[] = new Comment();
// delete all comments
$post->comments->delete();
// add new comment
$post->comments[] = new Comment();
$post->save(); // will save post with comments


4. Cover all things with events.

For example there is no onUnsafeAttribute event now. But sometimes it could be very usefull into behaviors.

5. Allow to attach event handlers to models before they were actually created.

PostManager::attachLiveEvent('afterSave', ...);

$post = PostManager::findByPk(1); // will have onAfterSave handler
$post = new Post(); // will have too onAfterSave handler


That will give developers apportunity to create observers which care about attaching to needed events by their own.

class MailObserver extends CComponent {

  public function init() {
    PostManager::attachEvent('afterSave', array($this, 'onPostSave'));
  }

  public function onPostSave($event) {
    // send email to admin
  }
}

1

#40 User is offline   rAWTAZ 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 102
  • Joined: 08-January 10

Posted 19 May 2012 - 10:24 AM

View PostThomas Jensen, on 16 September 2011 - 06:27 PM, said:

My proposals for AR:

  • Methods should have precedence over db fields. "getName" should be invoked by "->name", even though "name" is also a field in the db.

This is soooo important. I cannot second or third or even fourth this enough. Please add this!

To clarify: Make setter and getter methods have precedence over both regular attributes and relations.

Shall I say it again? Please add it! :-)
1

Share this topic:


  • (3 Pages)
  • +
  • 1
  • 2
  • 3
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users