this is the controller
public function store(Request $request) {
$post = new Post;
$photo = new Photo;
$user = Auth::user();
$input = $request->except('file');
$input['user_id'] =$user->id;
$post->create($input);
if ($files = $request->file('file')) {
foreach($files as $file) {
$name = time() . $file->getClientOriginalName();
$file->move('images', $name);
$photo = $photo->create(['file'=>$name, $photo->post_id => $post->id]);
}
}
return 'Upload successful!';
and this is the model
protected $fillable = ['file', 'post_id', 'user_id'];
protected $uploads = '/images/';
public function post() {
return $this->belongsTo('App\Post');
}
public function getFileAttribute($photo) {
return $this->uploads . $photo;
}
i get this error
Integrity constraint violation: 1048 Column 'post_id' cannot be null (SQL: insert into photos (file, post_id, updated_at, created_at
You made a typo:
$photo = $photo->create(['file'=>$name, 'post_id' => $post->id]);
In my project I use FOSUserBundle and HWIOAuthBundle for user authentification. integrated HWIOAuthBundle using this tutorial. But additionaly I need to get user likes. I've already added user_likes in a scope and when I try to login facebook says that I want to get user likes but how do I get those likes for example in a Service. Maybe in a FOSUBUserProvider.php which was created in the link I provided above.
FOSUBUserProvider.php
<?php
namespace Atotrukis\MainBundle\Service;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass;
use Symfony\Component\Security\Core\User\UserInterface;
class FOSUBUserProvider extends BaseClass
{
/**
* {#inheritDoc}
*/
public function connect(UserInterface $user, UserResponseInterface $response)
{
$property = $this->getProperty($response);
$username = $response->getUsername();
//on connect - get the access token and the user ID
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
//we "disconnect" previously connected users
if (null !== $previousUser = $this->userManager->findUserBy(array($property => $username))) {
$previousUser->$setter_id(null);
$previousUser->$setter_token(null);
$this->userManager->updateUser($previousUser);
}
//we connect current user
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
$this->userManager->updateUser($user);
}
/**
* {#inheritdoc}
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$username = $response->getUsername();
$email = $response->getEmail();
$name = $response->getRealName();
$user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
//when the user is registrating
if (null === $user) {
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
// create new user here
$user = $this->userManager->createUser();
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
//I have set all requested data with the user's username
//modify here with relevant data
$user->setName($name);
$user->setUsername($email);
$user->setEmail($email);
$user->setPlainPassword($username);
$user->setEnabled(true);
$this->userManager->updateUser($user);
return $user;
}
//if user exists - go with the HWIOAuth way
$user = parent::loadUserByOAuthUserResponse($response);
$serviceName = $response->getResourceOwner()->getName();
$setter = 'set' . ucfirst($serviceName) . 'AccessToken';
//update access token
$user->$setter($response->getAccessToken());
return $user;
}
}
To call facebook API i use facebook sdk and for example to get friends, I added this to my controller:
$user = $this->getUser();
if ($user && $accessToken = $user->getFacebookAccessToken())
{
$friends= [];
$userRepo = $this->getUserRepository();
$session = new FacebookSession($accessToken);
$session->setDefaultApplication($this->container->getParameter('facebook_client_id'), $this->container->getParameter('facebook_client_secret'));
$friendsData = (new FacebookRequest(
$session, 'GET', '/me/friends'))->execute()->getGraphObject()->asArray();
foreach ($friendsData['data'] as $friendData) {
$friend = $userRepo->findOneByFacebookId($friendData->id);
if ($friend) {
$friends[] = $userRepo->findOneByFacebookId($friendData->id);
}
}
return array(
'user' => $user,
'friends' => $friends
);
}
I have a Zend form password custom validation.
I have set the addValidator functions IInd argument to false since I need to get all errors at once. Both of my validation classes have set the self::INVLID to corresponding error messages.
But when I look in the Zend controller even though both validations fail I'm getting only one (the last) error message.
I need all the error messages at once.
/* Form validation*/
$passwordSpecialValidator = new Passwordspecialvalidationvalidator();
$passwordHistoryValidator = new Passwordhistorylvalidationvalidator(new model(), $username, $newpass);
$this->newpass->addValidator($passwordSpecialValidator, false)
->addValidator($passwordHistoryValidator, false);
/* One validation class */
class Passwordhistorylvalidationvalidator extends Zend_Validate_Abstract {
const INVLID = '';
protected $_messageTemplates = array(
self::INVLID => 'Your password doesnt meet the history requirements'
);
public function __construct($model, $username, $password) {
$this->_model = $model;
$this->_username = $username;
$this->_password = $password;
}
public function isValid($value, $context = null) {
if ($this->_username == "") {
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$arrayResult = $auth->getIdentity();
if (isset($arrayResult->username)) {
$this->_username = $arrayResult->username;
}
}
}
$passwordExists = false;
$oldPasswords = $this->_model->getHistoryPasswords($this->_username, $this->_password);
if (count($oldPasswords) > 0) {
$passwordExists = true;
}
if ($passwordExists == false) {
return true;
} else {
$this->_setValue($value);
$this->_error(self::INVLID);
return false;
}
}
}
/* Getting error messages */
foreach ($objForm->getMessages() as $messages) {
foreach ($messages as $message) {
$errMessages[] = $message;
}
}
But the array $errMessages has only the last validation message (without index) even though both special validation and history validation fails. How would I get both error messages in an array if both validations fail?
I have two fields on the form ( forgotpassword form ) username and email Id . User should enter one of them . I mean to retrieve the password user can enter user name or the email id . Could some one point me the validation rule for this ?
Is there any inbuilt rule I can use ?
( Sorry if it is already discussed or if I missed)
Thanks for your help
Regards
Kiran
I was trying to solve same problem today. What I've got is the code below.
public function rules()
{
return array(
// array('username, email', 'required'), // Remove these fields from required!!
array('email', 'email'),
array('username, email', 'my_equired'), // do it below any validation of username and email field
);
}
public function my_required($attribute_name, $params)
{
if (empty($this->username)
&& empty($this->email)
) {
$this->addError($attribute_name, Yii::t('user', 'At least 1 of the field must be filled up properly'));
return false;
}
return true;
}
General idea is to move 'required' validation to custom my_required() method which can check if any of field is filled up.
I see this post is from 2011 however I couldn't find any other solution for it. I Hope it will work for you or other in the future.
Enjoy.
Something like this is a bit more generic and can be reused.
public function rules() {
return array(
array('username','either','other'=>'email'),
);
}
public function either($attribute_name, $params)
{
$field1 = $this->getAttributeLabel($attribute_name);
$field2 = $this->getAttributeLabel($params['other']);
if (empty($this->$attribute_name) && empty($this->$params['other'])) {
$this->addError($attribute_name, Yii::t('user', "either {$field1} or {$field2} is required."));
return false;
}
return true;
}
Yii2
namespace common\components;
use yii\validators\Validator;
class EitherValidator extends Validator
{
/**
* #inheritdoc
*/
public function validateAttributes($model, $attributes = null)
{
$labels = [];
$values = [];
$attributes = $this->attributes;
foreach($attributes as $attribute) {
$labels[] = $model->getAttributeLabel($attribute);
if(!empty($model->$attribute)) {
$values[] = $model->$attribute;
}
}
if (empty($values)) {
$labels = '«' . implode('» or «', $labels) . '»';
foreach($attributes as $attribute) {
$this->addError($model, $attribute, "Fill {$labels}.");
}
return false;
}
return true;
}
}
in model:
public function rules()
{
return [
[['attribute1', 'attribute2', 'attribute3', ...], EitherValidator::className()],
];
}
I don't think there is a predefined rule that would work in that case, but it would be easy enough to define your own where for username and password fields the rule was "if empty($username . $password) { return error }" - you might want to check for a min length or other field-level requirements as well.
This works for me:
['clientGroupId', 'required', 'when' => function($model) {
return empty($model->clientId);
}, 'message' => 'Client group or client selection is required'],
You can use private property inside model class for preventing displays errors two times (do not assign error to model's attribute, but only add to model without specifying it):
class CustomModel extends CFormModel
{
public $username;
public $email;
private $_addOtherOneOfTwoValidationError = true;
public function rules()
{
return array(
array('username, email', 'requiredOneOfTwo'),
);
}
public function requiredOneOfTwo($attribute, $params)
{
if(empty($this->username) && empty($this->email))
{
// if error is not already added to model, add it!
if($this->_addOtherOneOfTwoValidationError)
{
$this->addErrors(array('Please enter your username or emailId.'));
// after first error adding, make error addition impossible
$this->_addOtherOneOfTwoValidationError = false;
}
return false;
}
return true;
}
}
don't forget "skipOnEmpty" attr. It cost me some hours.
protected function customRules()
{
return [
[['name', 'surname', 'phone'], 'compositeRequired', 'skipOnEmpty' => false,],
];
}
public function compositeRequired($attribute_name, $params)
{
if (empty($this->name)
&& empty($this->surname)
&& empty($this->phone)
) {
$this->addError($attribute_name, Yii::t('error', 'At least 1 of the field must be filled up properly'));
return false;
}
return true;
}
Yii 1
It can be optimized of course but may help someone
class OneOfThemRequiredValidator extends \CValidator
{
public function validateAttribute($object, $attribute)
{
$all_empty = true;
foreach($this->attributes as $_attribute) {
if (!$this->isEmpty($object->{$_attribute})) {
$all_empty = false;
break;
}
}
if ($all_empty) {
$message = "Either of the following attributes are required: ";
$attributes_labels = array_map(function($a) use ($object) {
return $object->getAttributeLabel($a);
}, $this->attributes);
$this->addError($object, $_attribute, $message . implode(',',
$attributes_labels));
}
}
}
yii1
public function rules(): array
{
return [
[
'id', // attribute for error
'requiredOneOf', // validator func
'id', // to params array
'name', // to params array
],
];
}
public function requiredOneOf($attribute, $params): void
{
$arr = array_filter($params, function ($key) {
return isset($this->$key);
});
if (empty($arr)) {
$this->addError(
$attribute,
Yii::t('yii', 'Required one of: [{attributes}]', [
'{attributes}' => implode(', ', $params),
])
);
}
}
I want to make redirection after login action to previous URL. Please tell me how to do that?
Store the page before Login into Session, After login , read the previous page url from the session and redirect the use to that page.
You can pass the "return" URL as a parameter to the login page. i.e http://yourserver.com/login/?return=http%3a%2f%2fyourserver.com%2fsomedir%2fsomething%2f. After a successful login you then use the get parameter to redirect by using a simple HTTP header location:http://yourserver.com/somedir/something/.
This is, for example, practiced in different Google and Microsoft services where there is a single page for signing in and different services that require the user to be loogged in.
You may this use Action helper I wrote some time ago. Cheers!
class Your_Controller_Action_Helper_GoBack
extends Zend_Controller_Action_Helper_Abstract
{
/**
* #todo Check if redirecting to the same domain
* #param bool $required Throw exception?
* #param bool $validateDomain
* #param bool $allowSubdomain
* #param string $alternative URL to redirect to when validation fails and required = true
* #param string $anchorParam Request parameter name which holds anchor name (#). Redirect to page fragment is not allowed according to HTTP protocol specification, but browsers do support it
* #throws Zend_Controller_Action_Exception if no referer is specified and $required == false or $checkdomain is true and domains do not match
*/
public function direct($required = true, $anchorParam = null, $validateDomain = true, $allowSubdomain = false, $alternative = null)
{
$front = Zend_Controller_Front::getInstance();
$request = $front->getRequest();
$referer = $request->getPost('http_referer');
if (empty($referer)) {
$referer = $request->getServer('HTTP_REFERER');
if (empty($referer)) {
$referer = $request->getParam('http_referer');
}
}
if (null === $alternative) {
$alternative = $request->getPost('http_referer');
if (null === $alternative) {
$alternative = $request->getParam('http_referer');
}
}
if ($referer) {
if ($validateDomain) {
if (!$this->validateDomain($referer, $allowSubdomain)) {
$this->_exception($alternative);
}
}
if (null != $anchorParam) {
$referer .= '#' . $request->getParam($anchorParam);
}
$redirector = new Zend_Controller_Action_Helper_Redirector();
$redirector->gotoUrl($referer);
} elseif($required) {
$this->_exception($alternative);
}
}
/**
* #throws Zend_Controller_Action_Exception With specified message
* #param string $message Exception message
* #param string $alternative
*/
private function _exception($alternative = null, $message = 'HTTP_REFERER is required.')
{
if ($alternative) {
if (Zend_Uri::check($alternative)) {
$redirector = new Zend_Controller_Action_Helper_Redirector();
$redirector->gotoUrl($alternative);
}
}
throw new Zend_Controller_Action_Exception($message);
}
/**
* Check if domain from current url and domain from specified url are the same
* #param string $url Target url
* #param string $allowSubdomain false
*/
public function validateDomain($url, $allowSubdomain = false)
{
if (!Zend_Uri::check($url)) {
return false;
}
$currentUri = $this->getCurrentUri();
$uri = Zend_Uri_Http::fromString($currentUri);
$currentDomain = $uri->getHost();
$uri = Zend_Uri_Http::fromString($url);
$target = $uri->getHost();
if ($allowSubdomain) {
// Find second dot from the end
$pos = strrpos($target, '.');
if (false !== $pos) {
$pos = strrpos(substr($target, 0, $pos), '.');
if (false !== $pos) {
$target = substr($target, $pos+1);
}
}
}
if ($target === $currentDomain) {
return true;
}
return false;
}
/**
* #return string Current URL
*/
public function getCurrentUri()
{
$request = $this->getRequest();
$path = $request->getRequestUri();
$server = $request->getServer();
$host = $request->getServer('HTTP_HOST');
$protocol = $request->getServer('SERVER_PROTOCOL');
if (!empty($protocol)) {
$protocol = explode('/', $protocol);
$protocol = strtolower($protocol[0]);
}
if (empty($protocol)) {
$protocol = 'http';
}
$baseUrl = $protocol . '://' . $host . '/';
$path = trim($path, '/\\');
$url = $baseUrl . $path;
return $url;
}
/**
* Like str_replace, but only once
* #param string $search
* #param string $replace
* #param string $subject
*/
public function replaceOnce($search, $replace, $subject)
{
$firstChar = strpos($subject, $search);
if($firstChar !== false) {
$beforeStr = substr($subject, 0, $firstChar);
$afterStr = substr($subject, $firstChar + strlen($search));
return $beforeStr . $replace . $afterStr;
} else {
return $subject;
}
}
}