Ask your Symfony questions! Pay money and get answers fast! (more info)

Is this a bug in sfPropelActAsTaggableBehavior plugin? Symfony

  • SOLVED

I am having a problem with sfPropelActAsTaggableBehavior plugin.

My code:

$arrayOfProjects = TagPeer::getModelsTaggedWith($arrayOfTags);


The error:

Fatal error: Undefined class constant 'COUNT' in /home/lawrence/domains/dev9/public_html/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TagPeer.php on line 185

TagPeer has this code:

$c = new Criteria();
$c->addJoin(TagPeer::ID, TaggingPeer::TAG_ID);
$c->add(TagPeer::NAME, $tags, Criteria::IN);
$c->addGroupByColumn(TaggingPeer::TAGGABLE_ID);
$having = $c->getNewCriterion(TagPeer::COUNT, count($tags), Criteria::GREATER_EQUAL);
$c->addHaving($having);
$c->clearSelectColumns();
$c->addSelectColumn(TaggingPeer::TAGGABLE_MODEL);
$c->addSelectColumn(TaggingPeer::TAGGABLE_ID);


The line causing the problem is the one with COUNT in it.

I opened up BaseTagPeer and, sure enough, there is no constant called COUNT. Is this a bug? Am I missing something obvious?

<strong>UPDATE</strong>:

I am trying to write my own version of this method. This is what I've got so far:

public static function getModelsTaggedWithTheseTags($tags = array())
{
if (count(tags)) {
$c = new Criteria();
$c->addJoin(TagPeer::ID, TaggingPeer::TAG_ID);
$c->add(TagPeer::NAME, $tags, Criteria::IN);
$c->addGroupByColumn(TaggingPeer::TAGGABLE_ID);
$c->addSelectColumn(TaggingPeer::TAGGABLE_MODEL);
$c->addSelectColumn(TaggingPeer::TAGGABLE_ID);

$params = array();
$sql = BasePeer::createSelectSql($c, $params);
echo $sql;
$con = Propel::getConnection();
$stmt = $con->prepare($sql);
$position = 1;

foreach ($tags as $tag) {
$stmt->bindValue($position, $tag);
$position++;
}

$stmt->bindValue($position, count($tags));
$rs = $stmt->execute($tags);

$models = array();

while ($object = $rs->fecth(PDO::FETCH_OBJ)) {
$models[] = $object;
}

return $models;
}
}


The SQL is:

<blockquote>SELECT sf_tagging.TAGGABLE_MODEL, sf_tagging.TAGGABLE_ID FROM `sf_tagging`, `sf_tag` WHERE sf_tag.NAME IN (:p1,:p2) AND sf_tag.ID=sf_tagging.TAG_ID GROUP BY sf_tagging.TAGGABLE_ID</blockquote>


The tokens correctly get replaced by the 2 tags that I'm handing in. However, I get this error on execute():

SQLSTATE[HY093]: Invalid parameter number: parameter was not defined

stack trace
at ()
in SF_SYMFONY_LIB_DIR/plugins/sfPropelPlugin/lib/vendor/propel/util/DebugPDOStatement.php line 61 ...
public function execute($input_parameters = null)

{

$this->pdo->incrementQueryCount();

return parent::execute($input_parameters);

}



I tried this:

$stmt->bindValue($position, count($tags));
$rs = $stmt->execute();


and I tried commenting out the last bindValue:

// $stmt->bindValue($position, count($tags));
$rs = $stmt->execute($tags);



I feel like I'm missing something obvious. Any suggestions?


<strong>ANOTHER UPDATE</strong>

I got this working, but it is a bit ugly, especially how I'm creating the "position" values. I'll leave this question open for another 12 hours. If anyone wants to suggest a clean up, it would be welcome. I will then email whatever we have to Lacot, just in case he ever updates the plugin.

public static function getModelsTaggedWithTheseTags($tags = array())
{
if (count(tags)) {
$c = new Criteria();
$c->addJoin(TagPeer::ID, TaggingPeer::TAG_ID);
$c->add(TagPeer::NAME, $tags, Criteria::IN);
$c->addGroupByColumn(TaggingPeer::TAGGABLE_ID);
$c->addSelectColumn(TaggingPeer::TAGGABLE_MODEL);
$c->addSelectColumn(TaggingPeer::TAGGABLE_ID);

$params = array();
$sql = BasePeer::createSelectSql($c, $params);
$con = Propel::getConnection();
$stmt = $con->prepare($sql);
$position = 1;

foreach ($tags as $tag) {
$stmt->bindValue(":p$position", $tag);
$position++;
}

// $stmt->bindValue($position, count($tags));
$stmt->execute();
$models = array();

while ($object = $stmt->fetch(PDO::FETCH_OBJ)) {
$models[] = $object;
}

return $models;
}
}



Answers (5)

2010-03-01

Gert Findel answers:

I use the Plugin in a project with sf 1.2.9 and works good
I had many problems with COUNT because I use in sqlite my dev env. Switching to MySQL solved it for me.

When I had problems with COUNT and this Plugin I used the following code to get things working for my "tag_cloud"

$criteria = DebatePeer::addCriteriaDebatesActivos();
$criteria->addJoin(DebatePeer::ID, TaggingPeer::TAGGABLE_ID, Criteria::INNER_JOIN);
$criteria->addJoin(TaggingPeer::TAG_ID, TagPeer::ID, Criteria::INNER_JOIN);

$criteria->addSelectColumn(TagPeer::NAME);
$criteria->add(TaggingPeer::TAGGABLE_MODEL, 'Debate');
// $criteria->add(TaggingPeer::TAGGABLE_ID, DebatePeer::ID.'='.TaggingPeer::TAGGABLE_ID, Criteria::CUSTOM);
$criteria->addAsColumn('cnt', 'count('.TaggingPeer::TAGGABLE_ID.')');
$criteria->addGroupByColumn(TagPeer::NAME);
$criteria->addDescendingOrderByColumn( 'cnt' , Criteria::CUSTOM);
$criteria->setLimit(7);
$this->tags = BasePeer::doSelect($criteria);


And in the view

<? foreach($tags as $tag): ?>
<li><span>
<?= link_to($tag['NAME'], '@debates_tag?tag='.$tag['NAME'],
array('rel'=>'tag', 'title' => 'Debates etiquetados como '.$tag['NAME']))?> (<?=$tag['cnt']?>)
</span></li>
<? endforeach; ?>


I know it was a workarround but it worked


Gert Findel comments:

Im my version the code works with

foreach ($tags as $tag)
{
$stmt->setString($position, $tag);
$position++;
}

$stmt->setString($position, count($tags));
$models = array();

if (Propel::VERSION >= '1.3')
{
$rs = $stmt->query();

while ($rs->fecth(PDO::FETCH_NUM))
{
$models[] = $rs->getString(1);
}


So I would say your approuch is not much uglier than the author's implementation.


Gert Findel comments:

with the following query in my action


$criteria = new Criteria();
$criteria->addJoin(TaggingPeer::TAG_ID, TagPeer::ID, Criteria::INNER_JOIN);

$criteria->addSelectColumn(TaggingPeer::TAGGABLE_MODEL);
$criteria->add(TagPeer::NAME, array('toto','tutu'), Criteria::IN);
$criteria->addAsColumn('cnt', 'count('.TaggingPeer::TAGGABLE_ID.')');
$criteria->addGroupByColumn(TaggingPeer::TAGGABLE_MODEL);
$criteria->addDescendingOrderByColumn( 'cnt' , Criteria::CUSTOM);
$this->models = BasePeer::doSelect($criteria);


I obtained (print_r($models))

SELECT sf_tagging.TAGGABLE_MODEL, count(sf_tagging.TAGGABLE_ID) AS cnt FROM sf_tagging INNER JOIN sf_tag ON (sf_tagging.TAG_ID=sf_tag.ID) WHERE sf_tag.NAME IN (:p1,:p2) GROUP BY sf_tagging.TAGGABLE_MODEL ORDER BY cnt

And inside of a foreach($models as $model) "print_r($model)" returns

Array (
[taggable_model] => BlogPost
[0] => BlogPost
[cnt] => 6
[1] => 6
)

and

Array (
[taggable_model] => Debate
[0] => Debate
[cnt] => 2
[1] => 2
)


Maybe you could try something like this.


Gert Findel comments:

IMHO this is cleaner

2010-03-01

Kiril Angov answers:

Yes, looks like it: http://svn.symfony-project.com/plugins/sfPropelActAsTaggableBehaviorPlugin/trunk/config/schema.yml

There is no database field "count" defined at all.

Try this:

$having = $c->getNewCriterion('COUNT('.TagPeer::NAME.')', count($tags), Criteria::GREATER_EQUAL);


Kiril Angov comments:

Try this:

$having = $c->getNewCriterion('COUNT('.TagPeer::NAME.')', count($tags), Criteria::GREATER_EQUAL);


Lawrence Krubner comments:

The error then becomes:

Fatal error: Call to undefined method DebugPDO::prepareStatement() in /home/lawrence/domains/dev9/public_html/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TagPeer.php on line 195


Lawrence Krubner comments:

TagPeer tries to handle Propel version 1.3 with this block of code:

if (Propel::VERSION >= '1.3')
{
$rs = $stmt->query();

while ($rs->fecth(PDO::FETCH_NUM))
{
$models[] = $rs->getString(1);
}
}
else
{
$rs = $stmt->executeQuery(ResultSet::FETCHMODE_NUM);

while ($rs->next())
{
$models[] = $rs->getString(1);
}
}


I'm unclear why this does not work.

2010-03-01

michalg answers:

Hello,

I think that you're using version of propel which this plugin don't support. Look at this:

http://propel.phpdb.org/trac/changeset/1068/trunk/generator/classes/propel/engine/builder/om/php5/PHP5PeerBuilder.php

addCountConstants method has been removed in peer builder


michalg comments:

Here are more information:

http://propel.phpdb.org/trac/changeset/939/branches/1.3/generator/classes/propel/engine/builder/om/php5/PHP5PeerBuilder.php


michalg comments:

Symfony 1.2.5 uses propel 1.3:

http://propel.mirror.svn.symfony-project.com/branches/1.3/generator/classes/propel/engine/builder/om/php5/PHP5PeerBuilder.php

Clearly in this version there isn't addCountConstants method.

2010-03-01

Scott Meves answers:

The constant should be defined on line 125 of your generated BaseTagPeer.php file, right above the doCount() definition:

const COUNT = 'COUNT(sf_tag.ID)';
const COUNT_DISTINCT = 'COUNT(DISTINCT sf_tag.ID)';


This is with symfony 1.0.22. Perhaps you are trying to use the plugin with symfony 1.2?


Lawrence Krubner comments:

Scott, yes, Symfony version 1.2.5. The plugin says it supports 1.2:

http://www.symfony-project.org/plugins/sfPropelActAsTaggableBehaviorPlugin


Lawrence Krubner comments:

Off topic: Scott, do you still use Symfony 1.0.22 ?

2010-03-02

Taboubi Issam answers:

make sure that when you build your model , check in your propel.ini if propel.builder.addBehaviors = true . clear cache it should be correct