CakePHP 3 Dynamic Finders with underscores - php

I would like to use a dynamic finder method. I've seen in the documentation $this->Users->findByUsername. My problem is that my column name is post_id, and I'm not sure how the underscore affects the name of my dynamic finder function. Here are the ones I've tried so far and can't seem to get working
findByPost_id( $post_id )
findByPost_Id( $post_id )
findByPost_ID( $post_id )
findByPostId( $post_id )
For context here is what my code looks like
//VotesTable.php
public function afterSaveCommit($event, $entity, $options) {
if ( $entity->vote_type_id == self::favorite ) {
$qt = TableRegistry::get('questions');
$question = $qt->findByPostId($entity->post_id);
$question->favorite_count = $question->favorite_count + 1;
if ( ! $qt->save( $question ) ) {
throw new \Exception("Unable to update favorite count", 500);
}
}
}
When I log $question it outputs a query, not an object, and the query can't be run. it ends with WHERE 'questions'.'post_id' = :c0

Cake will convert the underscores to pascal case words, so you find it like this:
$this->findByPostId();
This is the correct way to do it.

If your column name is: post_id, you should use it as follows:
findByPost_id(2);
It seems that problem is somewhere else in the code. For example, if my column name is: item_status, I would use it like this:
// In the controller:
$table = $this->loadModel('ProcessItems');
$result = $table->findByItem_status(100);

Related

Assigning a value to a variable?

I'm working on a PHP project and would love to get some help on variables.
I have a function that looks like this:
function custom_get_tour_nearest_booking_dates( $tour_id, $limit = 2, $exclude_booked_tickets = false ) {
$result = array();
if ( $tour_id < 1 ) {
return $result;
}
The database holds a set of products, each of these with a unique ID made up by numeric values, like 1233,2355,6532 and so on.
If I want to display the characteristics of one of these products, how do I link the ID to the variable $tour_id?
Somewhere you call that method: custom_get_tour_nearest_booking_dates(4);
Like the example above, 4 is the tour_id. Besides that, your method is kinda useless.

Pimcore: Creating Name-Spaced Objects via String Containing Class Name

I've developed an area in Pimcore that allows us to select a Pimcore object classification from a list, and transform it into an HTML renderable form.
I would like to increase the functionality of this by capturing successful submissions as objects in the backend, however I cannot seem to use the standard PHP method for object creation by class name.
What am I doing wrong? Does Pimcore handle this in an different way?
Accepted Answer Edits:
I've altered the code slightly to reflect the suggestions from the accepted answer. As noted, it's important to remember that while class names can have lowercase first letters, their actual namespaced identifiers use initial casing, which is where my code was breaking.
For instance:
$newObj_class was outputting Pimcore\Model\Object\className
$newObj_class should have been Pimcore\Model\Object\ClassName
Notice the distinction in the className vs ClassName...
Here's the core of the area's working view.php file:
// Get a list of available classes...
$form_class = null;
$class_list = new Pimcore\Model\Object\ClassDefinition\Listing();
$class_list->load();
// Turn the class names into dropdown options...
$class_options = array();
foreach( $class_list->getClasses() as $class )
{
$class_options[] = array( $class->name, $class->name );
}
// Admin only code...
if( $this->editmode )
{
$formSource = $this->select(
'formClass',
array(
'store' => $class_options,
'reload' => true
)
);
echo
'<table>'.
'<tr><th>Form Source:</th><td>'.$formSource.'</td></tr>'.
// Additional config fields go here...
'</table>';
}
// Iterate over the classes...
foreach( $class_list->getClasses() as $class )
{
// Skip unselected classes...
if( $this->select( 'formClass' )->getValue() != $class->name )
{
continue;
}
// Handle form submissions...
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
{
// Create an object using the selected class...
$newObj_class = 'Pimcore\\Model\\Object\\'.ucfirst( (string)$this->select( 'formClass' ) );
$newObj = new $newObj_class();
// Assign field values to the object here...
$newObj->save();
}
}
Your object class name probably starts with lower case but the actual class always stars with upper case.
This should fix your problem:
$newClass = 'Pimcore\\Model\\Object\\' . ucfirst($this->select( 'formClass' )->getValue());

Laravel Eloquent: how to filter multiple and/or criteria single table

I am making a real estate related app and I've been having a hard time figuring out how to set up the query so that it would return "Only Apartments or Duplexes within selected areas" I'd like to user to be able to find multiple types of property in multiple selected quadrants of the city.
I have a database with a column "type" which is either "Apartment", "House", "Duplex", "Mobile"
In another column I have quadrant_main with values: "NW", "SW", "NE", "SE".
My code works when there is only 1 quadrant selected, but when I select multiple quadrants, I seem to get results which includes ALL the property types from the second or third or 4th quadrant, instead of only "Apartment" and "Duplex" or whatever types the user selects... Any help will be appreciated! thx in advance.
My controller function looks like this:
public function quadrants()
{
$input = \Request::all();
$currentPage = null;
$column = "price";
$order = "desc";
//
// Looks like the input is like 0 => { key: value } ...
// (an Array of key/value pairs)
$q = Listing::where('status','=','Active')->where(function($query) {
$input = \Request::all();
$currentPage = null;
$typeCount = 0;
$quadrantCount = 0;
foreach( $input as $index => $object ) {
$tempObj = json_decode($object);
$key = key((array)$tempObj);
$val = current((array)$tempObj);
if ( $key == "type" ) {
if ( $typeCount > 0 ) {
$query->orWhere('type', '=', $val );
}
else {
$query->where('type', '=', $val );
$typeCount++;
}
}
if ( $key == "quadrant_main" ) {
if ( $quadrantCount > 0 ) {
$query->orWhere('quadrant_main', '=', $val );
}
else {
$query->where('quadrant_main', '=', $val );
$quadrantCount++;
}
}
// else {
// $query->orWhere($key,$val);
// }
}
if( $currentPage ) {
//Force Current Page to Page of Val
Paginator::currentPageResolver(function() use ($currentPage) {
return $currentPage;
});
}
});
$listings = $q->paginate(10);
return $listings;
Looking at your question, its a bit confusing and not much is given to answer definitely. Probable causes of your troubles may be bad data in database, or maybe corrupted input by user.
Disclaimer: Please note that chances are my answer will not work for you at all.
In that case please provide more information and we will work things
out.
There is one thing that I think you have overlooked and thus you are getting awry results. First let me assume a few things.
I think a sample user input should look like this:
array(
0: '{type: Apartment}',
1: '{type: Duplex}',
2: '{quadrant_main: NW}',
3: '{quadrant_main: SW}',
)
What the user meant was give me any apartment or duplex which belongs in NW or SW region.
So after your loop is over, the final SQL statement should be something like this:
Oh and while we are at SQL topic, you can also log the actual
generated SQL query in laravel so you can actually see what was the
final SQL getting generated. If you can post it here, it would help a
lot. Look here.
select * from listings where status = 'Active' and (type = 'Apartment' or type = 'Duplex' and quadrant_main = 'NW' or quadrant_main = 'SW');
What this query will actually produce is this:
Select any listing which is active and:
1. Type is an apartment, or,
2. Type is a duplex, or,
3. Quadrant is SW, and,
4. Quadrant is NW
So assuming you have a database like this:
id|type|quadrant_main
=====================
1|Apartment|NW
2|Apartment|SW
3|Apartment|NE
4|Apartment|SE
5|Duplex|NW
6|Duplex|SW
7|Duplex|NE
8|Duplex|SE
9|House|NW
10|House|SW
11|House|NE
12|House|SE
You will only receive 1, and 5 in the result set. This result set is obviously wrong, plus it is depended on NW because that was the and condition.
The correct SQL query would be:
select * from listings where status = 'Active' and (type = 'Apartment' or type = 'Duplex') and (quadrant_main = 'NW' or quadrant_main = 'SW');
So structure your L5 app such that it produces this kind of SQL query. Instead of trying to cram everything in one loop, have two loops. One loop should only handle type and another loop should only handle quadrant_main. This way you will have the necessary and condition in the right places.
As a side note:
Never directly use user input. Always sanitize it first.
Its not a best practice to put all your logic in the controller. Use repository pattern. See here.
Multiple where clauses are generally applied via Criteria. Check that out in the above linked repository pattern.
You code logic is very complicated and utterly un-necessary. Instead of sending JSON objects, simply send the state of checkboxes. Don't try to generalize the function by going in loop. Instead handle all checkboxes one by one i.e. is "Apartments" selected, if yes, add that to your clause, if not, don't add.

It appears RedBeanPHP 4KS removed R::setStrictTyping(false). What is a workaround for dispensing beans with underscores?

I am using RedBeanPHP along with an API I am writing to make calls to an existing Database. Everything works great except some of the tables have underscores in their names. According to RedBean "underscores and uppercase chars are not allowed in type and property names."
When searching for solutions people recommended the use of the function.
R::setStrictTyping(false);
This would override the rules and allow you to dispense a bean such as
$post_points = R::dispense( 'user_points' );
However this appears to be missing in RedBeanPHP 4KS because when I put the SetStringTyping line in I recieve the following error:
Plugin 'setStrictTyping' does not exist, add this plugin using: R::ext('setStrictTyping')
There is no plugin for this.
Is there a workaround for this override?
Since I am working with an existing DB schema its not as easy to just change all the table names to conform to RedBeanPHP standards at this point. Nor, as others suggested, just switching to a different system all together such as using Doctrine.
Found out a solution. The check for underscores and uppercase chars only happens in the Facade. By adding this code:
R::ext('xdispense', function($type){
return R::getRedBean()->dispense( $type);
})
You can then do the following without error.
$post_points = R::xdispense( 'user_points' );
Cool.
Or you could extend RedBeanPHP\Facade and override dispense function. Then use new wrapper class instead of R static.
public static function dispense( $typeOrBeanArray, $num = 1, $alwaysReturnArray = FALSE )
{
if ( is_array($typeOrBeanArray) ) {
if ( !isset( $typeOrBeanArray['_type'] ) ) throw new RedException('Missing _type field.');
$import = $typeOrBeanArray;
$type = $import['_type'];
unset( $import['_type'] );
} else {
$type = $typeOrBeanArray;
}
if ( !preg_match( '/^[a-z0-9_]+$/', $type ) ) {
throw new RedException( 'Invalid type: ' . $type );
}
$redbean = parent::getRedBean();
$beanOrBeans = $redbean->dispense( $type, $num, $alwaysReturnArray );
if ( isset( $import ) ) {
$beanOrBeans->import( $import );
}
return $beanOrBeans;
}

Pass IDs to pre_get_posts query in function

I am trying to pass the post ids to the function's query->set and function will return the posts.
add_action( 'pre_get_posts', 'query_booked_posts' );
function query_booked_posts( $query ) {
if ( $condition ) { //the condition
if ( is_home() && $query->is_main_query() )
$results = $wpdb->get_col($wpdb->prepare( "SELECT booked_id FROM $wpdb->userbooking WHERE userid = %d",$current_user_id));
foreach($results as $result){
$results_separated = $result.',';
}
$query->set ('post__in', array($results_separated)); // pass results (post ids) to post__in
return $query;
}
}
After this, the function returns nothing.
If I do $query->set ('post__in', array(45,121));, the query will return the posts of id 45 and id 121, so the query works fine.
But I want to make $results_separated pass the post ids like 45,121,132 to the query, and then $query->set ('post__in', array($results_separated)); will work correctly.
How can I make this happen?
pre_get_posts reference
I guess you have actually a PHP problem. When you do array($results_separated) you're basically creating an array from a string that looks like this: "12,114,56,". By doing that, PHP is creating an array like this:
array(
0 => "12,114,56,"
)
And obviously WordPress cannot find any posts with such ID! What you want is actually an array like this:
array(
0 => "12",
1 => "114",
2 => "56"
)
And actually that's what get_col() returns, so you just need to pass $results to set() function:
$query->set ( 'post__in', $results );
EDIT: Actually I realised that your problem is when you call $wpdb->get_col(...), because it's interfering with the $query you will execute later on... Those variables are using some other global variables that probably get overriden, and that's why you're not getting any results...
Except the extra array() over $results_separated, in my case I had to apply
if (!$query->is_main_query()) {
return $query;
}
at the top of my function (found it in, otherwise, queries inside would be executed for several times and not properly.
Comments in the answer helped me to figure this out.

Categories