cakephp searching databases - sql

hi all I'm trying to search a database for a username using cakephp, the username isnt the primary key in the database but it must be unique. here is the code I have for the search function but cake does not like it.
function index(){
$this->User->recursive = 0;
if ($this->data['users']['username']) {
$this->set('users',
$this->paginate('users', array('or' => array('users.username LIKE' => '%' . )));
else {
$this->set('users', $this->paginate());
}
}
}
the database contains a id(the primary key) and a username. The goal of this is to send a friend request. User searches the username and then if the username is there, the other user will receive their request in a relationship inbox and can select 'yes' or 'no'.
the other thing is, if the username exists I want the data to be stored in a table called users_users - i realize i dont have any code for what to do once the search has happened. but I am pulling my hair out trying to figure this out as their doesnt seem to be many tutorials on the web for this.

Make sure your usernames are unique by validating it when they're entered.
http://book.cakephp.org/2.0/en/models/data-validation.html
I'm not sure, but this users.username looks like you're using the username as foreign key in the jointable!? Thats totally wrong.
Even if it would be then the notation is wrong and does not follow the CakePHP standards and won't work. It should be User.username then.
I would suggest you to start over with the blog tutorial for CakePHP and read the book.

I may be wrong, but why there are a dot besides '%'? The dot is the string concatenation operator and you aren't providing anything as second argument. Also, you're putting an OR condition but there's just one argument. So try this:
function index(){
$this->User->recursive = 0;
if ($this->data['users']['username']) {
$this->set('users',
$this->paginate('users', array('users.username LIKE' => '%')));
}
else {
$this->set('users', $this->paginate());
}
}
Hope this helps

Cake defaults to AND but you can specify any hierarchy of AND and OR
or AND or OR... until you get dizzy in the head :)
Your search could probably be formatted like:
'or' => array(
'Model.column1 LIKE' => '%keyword%',
'Model.column2 LIKE' => '%keyword'

Related

Eloquent many-to-many with filters on both sides

I've been reading the docs but I"m not sure how to do this. http://doc.laravelbook.com/eloquent/#many-to-many
Say I have a users, roles, and a pivot table.
I have belongsToMany set up for both Role and User
In a controller, I want to get a user_id and return what roles they have of a specific type only.
(There is also a role type table, but I can work with the IDs directly).
I start something like this
$specific_type_role = Role::where('role_type_id', 3)::where(?$user_id?)
//need to involve
$circle_users = RoleUser::where('user_id', $user_id)->get();
but I think it should be able to be done automatically. don't know how to include the filter right in the query.
Not sure if it's that what you need but, you probably will be able to do something like that:
public function getAdminRoles()
{
$user = User::find(1);
return $user->roles()->where('role_type_id', 1)->get();
}

Laravel 4 authentication not working

I have a Laravel 4 app in which I have set up one user. In my login route I'm calling Auth::attempt with the email and password but it always comes back as false. I definitely have the password correct and the correct hash in the database as Hash::check returns true.
I think it may be due to using email as the login field instead of username, but I can't see any setting for that. This question implied you could add an option to config/auth.php but it didn't work. This question says to use username as the array key, but then I get SQL error because it tries to select on a username field in the database.
Do I need to add something to the User model to specify the username field? Here is my login route:
Route::post('login', function() {
// data from login form
$credentials = array(
'email' => Input::get('email'),
'password' => Input::get('password')
);
$auth = Hash::check(Input::get('password'), Hash::make('mypass'));
var_dump($auth); // this is TRUE
// login was good
$auth = Auth::attempt($credentials);
var_dump($auth); // this is FALSE
});
I found the problem. As suggested by Jason in the comment above, I had modified the models/User.php file and removed some functions that I didn't realise were necessary.
The getAuthIdentifier() and getAuthPassword() methods must be included in the User model for authentication!
In app/config/app.php make sure you have the 'key' set. This made me pull my hair out. Everything will apear to work, password seems hashed in the DB, but it will always return false until you set this key and re-hash your password into the DB.
"php artisan key:generate"
Had the same problem and made me sweat for hours. Definitively check your User.php model and make sure you have not overwritten the default one. Thanks Jason!

How to only allow approved users to log in to my wiki?

I have added a column in my wikidatabase in the user table called approved_account.
The standard value on that column is 0 (zero).
I would like to add an exception when a user tries to log in to the wiki, such that
if approved_account = 0 then the login attempt is denied.
Does anyone know how and where I should place that if statement?
Edit: I've come this far.
I am using the AbortLogin hook, since I need to verify if my statement is true every time a user tries to log in.
However, my code won't let anyone in. It blocks all login attempts, even if I have the correct value in the approved_account field.
Can anyone help me fix this?
<?php
/**
* Prevent a user from accessing this file directly and provide a helpful
* message explaining how to install this extension.
*/
if ( !defined( 'MEDIAWIKI' ) ) {
echo <<<EOT
To install the Test extension, put the following line in your LocalSettings.php file:
require_once( "$IP/extensions/approvedaccount.php" );
EOT;
exit( 1 );
}
// Extension credits that will show up on Special:Version
$wgExtensionCredits['parserhook'][] = array(
'name' => 'Approved Account extension',
'description' => 'Prevent login',
'author' => 'Me',
'url' => 'http://www.mediawiki.org/wiki/Extension:approvedaccount'
);
$wgHooks['AbortLogin'][] = 'approvedaccount::onAbortLogin';
class approvedaccount
{
public static function onAbortLogin( $user, $password, &$retval ) {
global $wgOut, $wgUser;
$dbr = wfGetDB( DB_SLAVE );
$res = $dbr->select(
'user', // $table
array( 'user_name', 'approved_account' ), // $vars (columns of the table)
'user_name = "'.$wgUser.'"', // $conds
__METHOD__, // $fname = 'Database::select',
array( 'ORDER BY' => 'user_name ASC' ) // $options = array()
);
$output = '';
foreach( $res as $row ) {
$output .= 'Användarnamn: ' . $row->user_name . ' , Approved Account: ' . $row->approved_account . ".";
}
if ($row->approved_account = "1"){
//$this->loadDefaults();
// return false;
header("Location: http://hbg-whirlpool.emea.stream.corp/index.php?title=Special:UserLogout&returnto=Main+Page");
exit(); // you need to exit after a Location header is sent
}
}
}
You could do this with a simple AuthPlugin, overriding the strictUserAuth() method to return true for users that match the condition.
However, I suspect you're approaching this problem the wrong way. Why not just define a new user group, say, approved, and then add the corresponding record to the user_groups table for approved users? You won't be able to prevent unapproved users from logging in, but you can prevent them from making edits by only granting the edit permission to the approved group, like this:
$wgGroupPermissions['*']['edit'] = false;
$wgGroupPermissions['user']['edit'] = false;
$wgGroupPermissions['approved']['edit'] = true;
(If you wanted, you could even revoke the read permission from unapproved users too, but please read the warnings about restricting read access in MediaWiki first.)
Edit: I see a couple of problems with your AbortLogin hook.
Doing a 301 redirect and an exit() in the middle of the hook is probably not a very good idea. Sure, it probably will abort the login, but that's not really how the hook is meant to be used. Rather, you should just have the hook function return false to indicate that the login should be aborted or true to proceed with the normal login checks.
In any case, you're doing the exit() when the approved_account column is 1, which is presumably exactly when you don't want to abort the login.
...or, rather, you're doing the exit() always, because you used the assignment operator = instead of the comparison operator == in the condition, causing it to be always true. (Don't worry, that's a common bug in PHP and other C-like languages. One way to avoid is to get in the habit of using "Yoda conditionals" like 1 == $row->approved_account, which will produce an error if you leave out one =, since you can't assign to 1.)
Also, concatenating a User object with a string probably won't produce anything meaningful; and, even if it did, there would be an SQL injection vulnerability there. And besides, the hook parameters already include a User object, so you should use that instead of the global $wgUser (which might be stale during login anyway).
I admit that some of this stuff is really poorly documented. Besides the AbortLogin docs, I'd suggest looking at the general MediaWiki hook documentation, as well as the actual way the hook is called from SpecialUserlogin.php. For the database access, I'd also point you to the database wrapper function docs; unfortunately, the method documentation pages are giving 404 errors right now, so you'd again need to look directly in the source for the documentation.
Anyway, I'd rewrite your hook like this:
public static function onAbortLogin( $user, $password, &$retval, &$msg ) {
$dbr = wfGetDB( DB_SLAVE );
$row = $dbr->selectRow(
'user',
'approved_account',
array( 'user_id' => $user->getID() ),
__METHOD__
);
if ( !$row || !$row->approved_account ) {
$retval = LoginForm::ABORTED; // actually the default, but let's be sure
$msg = 'login-abort-not-approved'; // optional: custom error message
return false;
}
else {
// account is approved, return true to proceed with other login checks
return true;
}
}
If you want the custom message, you'll also need to create the page MediaWiki:login-abort-not-approved on your wiki. (If you wanted to turn this into a proper MediaWiki extension, you could provide a default message in an i18n file, but that's probably overkill here.)
Edit 2: Yes, you can add as many hooks as you want in an extension. (In fact, you don't even need an extension, it's perfectly fine to define simple site-specific hooks directly in LocalSettings.php if you want.) I think something like this could work for an AddNewAccount hook to log the user out, although I must note that I haven't actually tested this:
public static function onAddNewAccount( $user, $byEmail ) {
global $wgUser;
// try to log out the new user only if they're actually logged in
if ( $user->getName() == $wgUser->getName() ) $user->logout();
return true;
}
The if clause is there because the AddNewAccount is also called when a user creates a new account while logged in to a pre-existing account, in which case logging them out from their original account would be an unwelcome surprise. (Technically, just if ( $user == $wgUser ) ought to suffice, but explicitly comparing the usernames rather than the object references seems safer.)
Note that logging the new user out at that point kind of yanks the carpet out from under the new user creation code, so some unusual things may happen. For example, I suspect that the user creation log may actually end up saying something like "NewUserName created the new user account NewUserName", and the "Account successfully created" page may temporarily show the user as logged in, even though they're actually not.
It would be much cleaner to somehow avoid the auto-login behavior in the first place, but I don't see any obvious way to do that without patching SpecialUserlogin.php: the only check that determines whether the new user is automatically logged in is if ( $this->getUser()->isAnon() ), which only checks whether a user is already logged in. Even faking that somehow (which would be an ugly kluge in itself) doesn't really seem practical, as far as I can tell.
If you don't mind patching the MediaWiki core, though, just replacing that condition with if ( false ) (or if ( false && $this->getUser()->isAnon() ), if you want to keep it self-documenting) should do the trick. Note that you could still keep the AddNewAccount hook as a backup, in case you forget to reapply the patch after upgrading or something.

Yii. Get Users based on role

I am using native CDbAuthManager to implement RBAC in my webapp. How can I get all the users who has permission to do a role? Suppose I have role named updateprofile. I want to get all the users assigned to that role. I searched the documentation and couldnt find a function.
(I know i can iterate through all user models and do a checkAccess() in a foreach loop, but I prefer a nicer solution )
The easiest way I've found to do this is to create an AuthAssignment model that maps to your auth_assignment table. Then, you can setup relationships, scopes, etc for it and query using it to retrieve all user models. There isn't anything particularly special about the auth_assignment table (as it is mainly just roles in there).
code like
class AuthAssginment extends CActiveRecord{.....
public function getUsersBaseOnRole($role) {
return Yii::app()->db->createCommand()
->select('userid')
->from($this->tableName())
->where('itemname=:role', array(
':role' => $role,))
->queryAll() ;
}....
I think the other replies do not give you the perfect result because roles can be hierarchical and so, you cannot use direct queries or relations. My solution which works well is:
// list all users with 'userManagement' role
if($users = Users::model()->findAll()) {
foreach($users as $id => $user) {
if(!$user->checkAccess('userManagement')) {
unset($users[$id]);
}
}
$users = array_values($users); // to reset indices (optional)
}

kohana ORM question

i am using kohana ORM in order to get some results from the database. My problem is: even though i have consulted the documentation, i can't find a way to select only the column i am interested in. To be more explicit, i have:
$sale_stock = Model::factory('product_type')
->where('product_type_id','=', $id )
-> find_all();
var dumping it, it selects me all the "SELECT product_type.* from product_type where etc".
But i want to select only the 'stock' field from the salestock table. doing find('stock') instead find_all() returns a weired object... Where am i wrong, and how can i actually select only the column 'stock' using kohana orm?
thank you!
ORM methods find() and find_all() always select all table columns, so there is two ways to get specified fields:
Load full table rows and get columns
from it:
$sale_stock = Model::factory('product_type')
->where('product_type_id','=', $id )
-> find_all();
// get array of id=>stock values
$columns = $sale_stock->as_array('id', 'stock');
Create special method in model using
Query Builder:
// model Model_Product_Type
public function get_stocks($product_type_id)
{
return DB::select(array('stock'))
->from($this->_table_name)
->where('product_type_id', '=', $product_type_id)
->execute($this->_db);
}
I realise this isn't exactly what you're looking for, but I've pulled the following from the Kohana documentation ...
$articles = ORM::factory('article')->select_list('id', 'title');
foreach ($articles as $id => $title)
{
// Display a list of links
echo html::anchor('articles/'.$id, $title);
}
// Display a dropdown list
echo form::dropdown('articles', $articles);
You could think of it as a discount, two fields for the price of one.
It's common practice for ORMs to return a 'non-standard' object when partial model or merged model fields are requested. This prevents confusing operations using the original object (ie. how do you save an object when it contains only 2 of 8 fields, plus maybe some fields from another model?).
If you print_r the object, and give me an indication of how that looks ... it might be just what you want.
I know this is an old question, but i found maybe easier solution:
$sale_stock = ORM::factory('product_type')
->where( 'product_type_id','=', $id )
->find_all();
die($sale_stock->stock);