CakePHP less than or equal to a variable - cakephp-2.0

In CakePHP to do an equal to or less than statment you do this,
'conditions' => array('Model.field <=' => $variable)
However, i don't know how to do it with the variable on the other side of the condition,
'conditions' => array($variable<= =>'Model.field')
As you can imagine this doesn't work and i don't know what to do.
I am confused and annoyed at how to get this to work

Related

Ways to use array in cakephp

Hello I am having a tought time figuring out how to use arrays in cakephp. right now i have a view with 2 columns, active and startYear. i need to grab the start years for all of the columns in the view and sho i have this code.
public function initialize(array $config)
{
$this->setTable('odb.SchoolYear');
}
controller
public function index()
{
$deleteTable = $this->loadModel('DeletedTranscripts');
$this->$deleteTable->find('all', array(
'conditions' => array(
'field' => 500,
'status' => 'Confirmed'
),
'order' => 'ASC'
));
$this->set('startYear',$deleteTable );
}
once i have the array captured and put into lets say startYear can in input a statement like this into my dropdown list to populate it?
<div class="dropdown-menu">
<a class="dropdown-item" href="#"><?= $delete->startYear; ?></a>
</div>
i have been looking for answers for quite awhile any help would be awesome.
Couple of things:
Loading Tables in CakePHP
For this line:
$deleteTable = $this->loadModel('DeletedTranscripts');
While you can get a table this way, there's really no reason to set the return of loadModel to a variable. This function sets a property of the same name on the Controller, which almost correctly used on the next line. Just use:
$this->loadModel('DeletedTranscripts');
Then you can start referencing this Table with:
$this->DeletedTranscripts
Additionally, if you're in say the DeletedTranscriptsController - the corresponding Table is loaded for you automatically, this call might be unnecessary entirely.
Getting Query Results
Next, you're close on the query part, you've can start to build a new Query with:
$this->DeletedTranscripts->find('all', array(
'conditions' => array(
'field' => 500,
'status' => 'Confirmed'
),
'order' => 'ASC'
));
But note that the find() function does not immediately return results - it's just building a query. You can continue to modify this query with additional functions (like ->where() or ->contain()).
To get results from a query you need to call something like toArray() to get all results or first() to get a single one, like so:
$deletedTranscriptsList = $this->DeletedTranscripts->find('all', array(
'conditions' => array(
'field' => 500,
'status' => 'Confirmed'
),
'order' => 'ASC'
))->toArray();
Sending data to the view
Now that you've got the list, set that so it's available in your view as an array:
$this->set('startYear', $deletedTranscriptsList );
See also:
Using Finders to Load Data
Setting View Variables
I also noticed you've had a few other related questions recently - CakePHP's docs are really good overall, it does cover these systems pretty well. I'd encourage you to read up as much as possible on Controller's & View's.
I'd also maybe suggest running through the CMS Tutorial if you've not done so already, the section covering Controllers might help explain a number of CakePHP concepts related here & has some great working examples.
Hope this helps!

HABTM with self requires 2x the rows in join table?

I'm trying to build a CMS with Nodes as the main model. Each Node belongsTo a NodeType, and every Node can be related to any/every other Node.
So - thought this called for HABTM:
//Node model
public $hasAndBelongsToMany = array(
'AssociatedNode' => array(
'className' => 'Node',
'foreignKey' => 'node_id',
'associationForeignKey' => 'associated_node_id',
'joinTable' => 'node_associations'
)
);
The problem is, it seems like the only way it works is if I have TWO rows for each association.
Example with just one association row:
Nodes
ER (id=1)
George Clooney (id=2)
A single row in the join-table describing the relationship between those two nodes:
'node_id' = 1
'associated_node_id' = 2
Now - If I query for TV Shows and Contain it's Actor nodes:
$nodes = $this->Node->find('all', array(
'conditions' => array(
'Node.node_type_id' => '645' //tv shows
),
'contain' => array(
'AssociatedNode' => array(
'conditions' => array(
'AssociatedNode.node_type_id' => '239' //actors
),
)
)
));
This works, and I get ER -> George Clooney.
But - what if I want to pull all shows that George Clooney is in?
$nodes = $this->Node->find('all', array(
'conditions' => array(
'Node.node_type_id' => '239' //actors
),
'contain' => array(
'AssociatedNode' => array(
'conditions' => array(
'AssociatedNode.node_type_id' => '645' //tv shows
),
)
)
));
This doesn't work because it's looking for George Clooney's ID to be in the 'node_id' field, and ER's ID to be in the 'associated_node_id' field - when in reality they're reversed.
The only solution I've thought of is to keep two rows for EVERY association. But this seems overkill. But then I have to come up with some kind of custom something that makes sure to keep each duplicate in sync w/ the other every time an association is saved or deleted...etc - and this seems like a large can of worms.
Is there something I'm missing?
You could probably do it with a custom query, but to keep with standard Cake functions, one thing I can think of would be to declare two relationships between the Nodes:
public $hasAndBelongsToMany = array(
'AssociatedNode1' => array(
'className' => 'Node',
'foreignKey' => 'node_id',
'associationForeignKey' => 'associated_node_id',
'joinTable' => 'node_associations'
),
'AssociatedNode2' => array(
'className' => 'Node',
'foreignKey' => 'associated_node_id',
'associationForeignKey' => 'node_id',
'joinTable' => 'node_associations'
)
);
and then you could merge both arrays in an afterFind callback.
function afterFind($results)
{
foreach($results as &$result)
{
if(isset($result['AssociatedNode1']) || isset($result['AssociatedNode2']))
{
$associated_nodes = array();
if(isset($result['AssociatedNode1']))
{
foreach($result['AssociatedNode1'] as $associated_node)
{
$associated_nodes[] = $associated_node;
}
}
if(isset($result['AssociatedNode2']))
{
foreach($result['AssociatedNode2'] as $associated_node)
{
$associated_nodes[] = $associated_node;
}
}
$result['AssociatedNode'] = $associated_nodes;
}
}
unset($result);
return $results;
}
But this would force you to declare both AssociatedNode1 and AssociatedNode2 in the call to contain();
I'm not sure what the details of your use case are, but I've got a couple of alternate options for you:
You might look into using the Tree Behavior - this is built for storing things in trees, which it sounds like might be what you're doing. I haven't used it myself, so I'm not sure how applicable it is to your use.
On the other hand, if you store the relationships in a consistent direction (i.e. always TV Show->Actor) and know which direction your queries run (looking up the tree for TV Shows an Actor is in vs looking down for finding Actors in a TV Show), you should be able query AssociatedNode when you're going the reverse direction, e.g.
$nodes = $this->AssociatedNode->find('all', array(
'conditions' => array(
'AssociatedNode.node_type_id' => '239' //actors
),
'contain' => array(
'Node' => array(
'conditions' => array(
'Node.node_type_id' => '645' //tv shows
),
)
)
));
In this case, it might be better to use "ChildNode" instead of "AssociatedNode" for clarity.
But again, both of these answers depend on the particulars of your use case - nIcO's answer is a good general solution. It is (necessarily) awkward and possibly slower, but it abstracts away the awkwardness nicely.
One thing I've done in the past that might help is to make a model for the join table. I was able to store extra data in there and do whatever I wanted with my queries. Then on both sides of that join model just define a hasMany association (maybe a belongsTo as well). Then you can do a find using the join model and write something like (from a controller):
$this->Node->NodesNode->find('all', array('conditions'=>array("or"=>array('node_id'=>$id,'sub_node_id'=>$id))));
IMHO: there is nothing really forcing you to use cake conventions. I love cake, but sometimes both it and the ORMs complicate really easy things. You may just want to write your own query and parse the results yourself. It'd probably be faster than dealing with the overhead of another behavior or model plus you could probably write a way better query than the defaults given.
Oh and lastly, I'd watch out when you are using 1 model for multiple purposes. Really think if that one model should really be supporting everything. I've found that whenever I've done that I've just rewritten the entire thing within a year or two. You will quickly hit a bottle neck where some nodes need extra behavior in this way, others need something else and you have if statements (or maybe something more clever) scattered everywhere. Plus it really slows thing down to do crazy tree based queries in a db.

CakePHP magic findBy method for comparisons

We have plots and beans that can be planted into the plots.
I am absolutely determined to use the following to find all plots the owner has, with a bean inside them.
$plots = $this->Plot->findAllByOwnerAndBean_id(uid, '> 0');
However, it gives me the SQL WHEREPlot.owner= '15' ANDPlot.bean_id= '> 0'
This suggests it may be impossible, but I don't feel it's definitive. (potentially, even relevant as 2.2?) And it may be, so the question is two-fold:
How do I get what I want out of the findBy, and if I really can't, how could I avoid less code than the following, which I can confirm works?
$plots = $this->Plot->find('all', array(
'conditions' => array(
'owner' => uid,
'bean_id >' => 0
)
));
I don't see how it would be possible with magic methods (may work with DboSource::expression() but if its user input you'd have to sanitize it yourself). You can, however, just make a helper method in your model.
class Plot extends AppModel {
public function findAllByOwnerAndBeanId($owner, $beanId) {
return $this->find('all', array(
'conditions' => array(
'owner' => $owner,
'bean_id >' => $beanId,
),
));
}
}
Edit: You may instead try the following, but note that it's not tested.
$ds = $this->Plot->getDataSource();
$plots = $this->Plot->findAllByOwnerAndBean_id($uid, $ds->expression('> ' . intval($userInputtedBeanId)));
May be better for Sanitize::escape() rather than intval.

Containable behavior issue with non-standard keys?

I'm working with a legacy database whose keys follow a convention, but not the cake convention, unfortunately, and I've bumped into something odd with the containable behavior -- it's pulling the wrong data. Here's my setup:
TechnologyIncentive belongsTo...
array(
'Incentive' => array(
'className' => 'Incentive',
'type' => 'inner',
'foreignKey' => false, # actually 'incentive_id', but we need to fool Cake
'conditions' => array( 'TechnologyIncentive.incentive_id = Incentive.incentive_id' ),
),
'Technology' => array(
'className' => 'Technology',
'type' => 'inner',
'foreignKey' => false, # actually 'incentive_tech_id', but we need to fool Cake
'conditions' => array( 'TechnologyIncentive.incentive_tech_id = Technology.incentive_tech_id' )
),
);
You can see that I've had to fool Cake into working with my non-standard keys by setting the foreignKey to false and defining the link in my where clause. So far so good.
Now, when I try to run a query from the TechnologyIncentive model:
$this->find( 'all', array(
'contain' => array( 'Incentive', 'Technology' ),
'fields' => array( 'Incentive.name', 'Technology.name', 'TechnologyIncentive.amount' ),
'conditions' => array( /** conditions... */ )
);
Everything works great. Stuff is nicely contained and I get exactly what I'd expect. Then I need to include a TechnologyGroup, which hasMany Technology and things breakdown for some reason.
Now my contain option looks like this:
'contain' => array( 'Incentive', 'Technology' => array( 'TechnologyGroup' ) )
And what I get back is an Incentive record contains an incentive record. That's not entirely surprising since I'm specifying a few fields in one place (the main fields option) and implicitly all fields in the contain option, but what's really weird to me is that they're different incentives. The "contained" incentive is just wrong.
Inspecting the SQL, it looks like the query was run with no effective where clause at all, so everything is being pulled and then artificially limited to a single record. Note the difference between $result['Incentive']['incentive_id'] and $result['Incentive']['Incentive']['incentive_id'].
Array
(
[Incentive] => Array
(
[incentive_id] => MD046
[name] => Incentive name
[category] =>
[Incentive] => Array
(
[incentive_id] => AK004
[code] => AK04F
[version] => 2
[category] => Incentive Category
)
)
)
Has anyone ever bumped into this? It's not a problem until I want to retrieve an extended record (TechnologyGroup). Any thoughts would be much appreciated.
It looks like this was directly attributed to the non-standard keys. The Containable behavior, more so, it seems, that other elements of Cake really wants the convention followed. Moreover, some of the key associations included a double underscore (__) in the field name and that caused other problems.
Kids, don't try this at home. Follow the conventions, even if it means manipulating a legacy database.

Can i give conditions in contain in cakephp 1.3

i m facing some problem in find function. im fetching value fro find function.i have model.contian another model .
Can i give conditions in contain in cakephp
is it possiblehi
$this->Post->find('all', array('contain' => array(
'Comment' => array(
'conditions' => array('Comment.author =' => "Daniel"),
'order' => 'Comment.created DESC'
)
)));
You should always try the documentation first :).
isnt conditions in the format $this->ModelName->find('all',array('conditions'=>array('Table.name'=>1))); working for you?
Yes you can give conditions in contain

Resources