Trying to build upvote system in cakephp - php

I am trying to build an upvote system in cakephp but I am having some trouble and am ending up with unidentified index errors and array to string conversion.
This is my function in my PostsController:
public function like ($id=null, $like=NULL) {
if(!$id) {throw new NotFoundException(__('Invalid post'));
}
$post = $this -> Post-> findById($id);
$like = $this->Like->find('all', array(
'conditions' => array('username' =>
array($this->Auth->user('username')))
));
if(!$post) {throw new NotFoundException(__('Invalid post'));
}
$this -> set('post',$post);
$this -> set('like', $like);
if ($like['Like']['username'] == $post['Post']['username'] && $like['Like']['article_id'] == $post['Post']['id']){
$this->redirect(array('action'=>'index'));
}
else{
$this->Like->saveField('username', $this->Auth->user('username'));
$this->Like->saveField('article_id', $post);
$this->redirect(array('action'=>'index'));
}
}
At the top of my controller I do var $uses = array('Post','Like'); So my PostsController knows to use the Like model too. Now I know what problem is, I just don't know how to fix it. When I set the fields, username gets set in the DB, but $post returns an array of all posts. What I want to happen is for it to only return the current post I am on. This is what I am doing in my view:
<?php echo $this->Html->link(
'Like',
array('action'=>'Like',$post['Post']['id']));
?>
And this is the action that goes with that view:
public function view ($id=null) {
if(!$id) {throw new NotFoundException(__('Invalid post'));
}
$post = $this -> Post-> findById($id);
if(!$post) {
throw new NotFoundException(__('Invalid post'));
}
$this -> set('post',$post);
}
How can I get my link function to only return the current post I want to like and not an array of all the posts?
EDIT - Forgot to mention I'm getting an Undefined index: Like error on the 13th line of my posts controller.

You have
$like = $this->Like->find('all', array(
'conditions' => array('username' =>
array($this->Auth->user('username')))
));
This will give an array with more items, so you cannot use $like['Like']. This is why you are getting the warning.
You could use $like[0]['Like'].
If you need to go through each of the likes, you can do
foreach ($like as $currentLike) {
if ($currentLike['Like']['username'] == $post['Post']['username'] ....
}
Please include more details about why you are making these comparisons and redirects, and maybe more of the code can be refactored.

Related

Check if update happened in put request

I am new at PHP. We are creating REST API in Phalcon and I've created a put request. It already works, but I would like to check if update has really happened before sending a success response. So I've created a conditional for that ( if (!$product->update()) ), but it always returns 'true'. How can I check if any field has changed in a record?
public function put()
{
$id = $this->getParam('id');
$input = $this->getRawData();
$product = Product::findFirst([
'conditions' => 'id = :id:',
'bind' => ['id' => $id]
]);
if ($product === null){
throw new NotFoundException();
}
$product->assign($input);
$product->update();
if (!$product->update()) {
$this->errorResponse($product->getMessages());
} else {
$this->successResponse($product->toArray($product->update()));
}
}
You can use Model Events, i.e. afterUpdate and notSaved, like:
use Phalcon\Mvc\Model;
use Phalcon\Http\Response;
class ModelBase extends Model
{
public function afterUpdate()
{
$response = new Response();
$response->setJsonContent([
'success' => true,
'message' => "Record updated"
])->send();
}
public function notSaved()
{
$response = new Response();
$response->setJsonContent([
'success' => false,
'message' => 'Record not saved'
])->send();
}
}
The Product and all other models will extend ModelBase. Then your code could be:
public function put()
{
$id = $this->getParam('id');
$input = $this->getRawData();
$product = Product::findFirst([
'conditions' => 'id = :id:',
'bind' => ['id' => $id]
]);
if ($product === null){
throw new NotFoundException();
}
$product->assign($input);
$product->update();
}
And Phalcon event will respond if the model was updated or not. If you prefer, you can also use custom http response codes for update or notSaved. More information about Model Events in the documentation
You are calling $product->update() three times. You do it once after the assign, then again for your if test, which is why it's always returning TRUE there I believe, and once inside the toArray() which may not actually return anything since the second and third updates don't have any data to update (not sure about that though).
I would code this as follows:
$product->assign($input);
$results = $product->update();
if (!results) {
$this->errorResponse($product->getMessages());
} else {
$this->successResponse($results->toArray());
}
I am assuming that the $product->assign($input); statement is working as expected to update the $product data for you. I don't use that. I prefer to do direct assignments for updates so nothing is left to chance, ie. $product->whatever = $input['whatever'];.
Give this a try and hopefully it will work as expected for you.

Add favorite with symfony

I am learning symfony.
I try to save favorite when I click on a link and when I click again on the link, I wish I could remove the favorite in DB.
When clicking, I do have a new row in my database.
If I click again, it add a new one and don't erase the row.
This is what i have done in my controller:
public function addFavorite(EntityManagerInterface $manager, PostRepository $postRepository, Post $post)
{
$favorite = $postRepository->findOneBy(['content' => $post,'author' => $this->getUser()
]);
if (is_null($favorite)) {
$favorite = new Favorite();
$favorite
->setPost($post)
->setUser($this->getUser());
$manager->persist($favorite);
$manager->flush();
return $this->render('favorite/index.html.twig');
} else {
$manager->remove($favorite);
$manager->flush();
return $this->render('favorite/index.html.twig');
}
}
From what i understand, the problem is that $favorite is still NULL and i don't understand why...
If someone could help me, thanks !
I think it's because you don't request the good entity. I don't really know your entities, but I think this could be more logical :
public function addFavorite(EntityManagerInterface $manager, FavoriteRepository $favoriteRepository, Post $post)
{
$favorite = $favoriteRepository->findOneBy([
'post' => $post,
'user' => $this->getUser()
]);
if (!$favorite) {
$favorite = new Favorite();
$favorite
->setPost($post)
->setUser($this->getUser());
$manager->persist($favorite);
} else {
$manager->remove($favorite);
}
$manager->flush();
return $this->render('favorite/index.html.twig');
}

Yii2; code running in "else" block first, and then running code before "if" block?

I'm completely lost as to why this is happening, and it happens about 50% of the time.
I have a check to see if a user exists by email and last name, and if they do, run some code. If the user doesn't exist, then create the user, and then run some code.
I've done various testing with dummy data, and even if a user doesn't exist, it first creates them, but then runs the code in the "if" block.
Here's what I have.
if (User::existsByEmailAndLastName($params->email, $params->lastName)) {
var_dump('user already exists');
} else {
User::createNew($params);
var_dump("Creating a new user...");
}
And here are the respective methods:
public static function existsByEmailAndLastName($email, $lastName) {
return User::find()->where([
'email' => $email,
])->andWhere([
'last_name' => $lastName
])->one();
}
public static function createNew($params) {
$user = new User;
$user->first_name = $params->firstName;
$user->last_name = $params->lastName;
$user->email = $params->email;
$user->address = $params->address;
$user->address_2 = $params->address_2;
$user->city = $params->city;
$user->province = $params->province;
$user->country = $params->country;
$user->phone = $params->phone;
$user->postal_code = $params->postal_code;
return $user->insert();
}
I've tried flushing the cache. I've tried it with raw SQL queries using Yii::$app->db->createCommand(), but nothing seems to be working. I'm totally stumped.
Does anyone know why it would first create the user, and then do the check in the if statement?
Editing with controller code:
public function actionComplete()
{
if (Yii::$app->basket->isEmpty()) {
return $this->redirect('basket', 302);
}
$guest = Yii::$app->request->get('guest');
$params = new CompletePaymentForm;
$post = Yii::$app->request->post();
if ($this->userInfo || $guest) {
if ($params->load($post) && $params->validate()) {
if (!User::isEmailValid($params->email)) {
throw new UserException('Please provide a valid email.');
}
if (!User::existsByEmailAndLastName($params->email, $params->lastName)) {
User::createNew($params);
echo "creating new user";
} else {
echo "user already exists";
}
}
return $this->render('complete', [
'model' => $completeDonationForm
]);
}
return $this->render('complete-login-or-guest');
}
Here's the answer after multiple tries:
Passing an 'ajaxParam' parameters with the ActiveForm widget to define the name of the GET parameter that will be sent if the request is an ajax request. I named my parameter "ajax".
Here's what the beginning of the ActiveForm looks like:
$form = ActiveForm::begin([
'id' => 'complete-form',
'ajaxParam' => 'ajax'
])
And then I added this check in my controller:
if (Yii::$app->request->get('ajax') || Yii::$app->request->isAjax) {
return false;
}
It was an ajax issue, so thanks a bunch to Yupik for pointing me towards it (accepting his answer since it lead me here).
You can put validation like below in your model:
public function rules() { return [ [['email'], 'functionName'], [['lastname'], 'functionforlastName'], ];}
public function functionName($attribute, $params) {
$usercheck=User::find()->where(['email' => $email])->one();
if($usercheck)
{
$this->addError($attribute, 'Email already exists!');
}
}
and create/apply same function for lastname.
put in form fields email and lastname => ['enableAjaxValidation' => true]
In Create function in controller
use yii\web\Response;
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
else if ($model->load(Yii::$app->request->post()))
{
//place your code here
}
Add 'enableAjaxValidation' => false to your ActiveForm params in view. It happens because yii sends request to your action to validate this model, but it's not handled before your if statement.

Populate form from multiple tables yii2 mysql

I just learned how to create a complex form using multiple models.
public function actionCreate()
{
$model = new Company();
$contact = new Contact();
$address = new Address();
$company_contact = new CompanyContact();
$company_address = new CompanyAddress();
if ($model->load(Yii::$app->request->post()) && $contact->load(Yii::$app->request->post()) && $address->load(Yii::$app->request->post())) {
$model->save();
$address->save();
$contact->save();
// we need to insert the index from each key to the table Company_Contact to associate them
$company_contact->id_company = $model->id_company;
$company_contact->id_contact = $contact->id_contact;
// same procedure for Company_Address
$company_address->id_company = $model->id_company;
$company_address->id_address = $address->id_address;
$company_address->save();
$company_contact->save();
return $this->redirect(['index']);
} else {
return $this->render('create', [
'model' => $model,
'contact' => $contact,
'address' => $address
]);
}
}
The problem now is that I don't know how to call back every table data so i can populate my form and afterwards save the changes. I had the idea of using JOIN, but I don't have necessery knoledge to make this work on yii2 framework.
First of all, you need to make sure the methods declaring the relationship Company has to both Contact and Address are correct.
public function getContact() {
return $this->hasOne(Contact::className(), ['id_contact' => 'id_contact'])
->viaTable('Company_Contact', ['id_company' => 'id_company']);
}
public function getAddress() {
return $this->hasOne(Address::className(), ['id_address' => 'id_address'])
->viaTable('Company_Address', ['id_company' => 'id_company']);
}
Now that we know our relationships are correct, we can make some modifications to actionCreate() inside our controller:
public function actionCreate() {
$model = new Company();
$contact = new Contact();
$address = new Address();
// Check if the request was made using post, otherwise skip and render 'create' view
if(Yii::$app->request->isPost) {
// Begin a transaction, so we only make changes to the Database when we can save all the needed records.
$transaction = Company::getDb()->beginTransaction();
try {
$post = Yii::$app->request->post();
// We try to load $model, $contact and $address. If we can't then we throw an Exception that will be caught.
if(!($model->load(Yii::$app->request->post()) && $contact->load(Yii::$app->request->post()) && $address->load(Yii::$app->request->post()))) {
throw new \Exception('Could not load post data to models');
}
// Now we try to save them, each by itself. If any of them fail to save then we throw an Exception.
if(!$model->save()) {
throw new \Exception('Could not save $model');
}
if(!$address->save()) {
throw new \Exception('Could not save $address');
}
if(!$contact->save()) {
throw new \Exception('Could not save $contact');
}
// Now we populate the relationships.
// First parametter is the name of the relationship, Second is the model we want to link to.
$model->link('address', $address);
$model->link('contact', $contact);
// With the relationships correctly declared, we don't need to populate the juncture table ourselves, just link both models.
// If the 'link' method cannot link the models, then it will throw an Exception that will be caught.
// If we managed to save all the records and link them, now we commit the transaction so the changes made in the database are not reverted.
$transaction->commit();
return $this->redirect(['index']);
}
catch(\Exception $e) {
// If there are any problems then we will do a rollBack to the transaction, reverting the changes made during the transaction.
$transaction->rollBack();
}
}
return $this->render('create', [
'model' => $model,
'contact' => $contact,
'address' => $address,
]);
}
And now for actionUpdate we just need to get $id which will be used as PK to search for the Company.
public function actionUpdate(&id) {
$model = Company::findOne($id);
// If $model is null, then throw a NotFoundHttpException.
if($model === null) {
throw new \yii\web\NotFoundHttpException('The requested page does not exist.');
}
// We can get the $contact and $address models by using the relationships we already declared.
$contact = $model->contact;
$address = $model->address;
// Now we don't need to change much from actionCreate,
// except we don't need to link $model with $contact or $address because they are already linked,
// we just need to save changes made to them.
if(Yii::$app->request->isPost) {
$transaction = Company::getDb()->beginTransaction();
try {
$post = Yii::$app->request->post();
if(!($model->load(Yii::$app->request->post()) && $contact->load(Yii::$app->request->post()) && $address->load(Yii::$app->request->post()))) {
throw new \Exception('Could not load post data to models');
}
if(!$model->save()) {
throw new \Exception('Could not save $model');
}
if(!$address->save()) {
throw new \Exception('Could not save $address');
}
if(!$contact->save()) {
throw new \Exception('Could not save $contact');
}
$transaction->commit();
return $this->redirect(['index']);
}
catch(\Exception $e) {
$transaction->rollBack();
}
}
return $this->render('update', [
'model' => $model,
'contact' => $contact,
'address' => $address,
]);
}

zend framework 3 tutorial

I am trying a Zend framework 3 tutorial and am getting stuck in "editing" a function in the in-depth part (Blog case).
When trying to edit a blog message, the editing form doesn't show the original message. It seems that the original message couldn't be bound to the form.
I copied all the sample code. I don't know what is wrong with it. By the way, my add and delete function work fine.
can anyone help me with it?
The editAction method from the tutorial:
public function editAction()
{
$id = $this->params()->fromRoute('id');
if (! $id) {
return $this->redirect()->toRoute('blog');
}
try {
$post = $this->repository->findPost($id);
} catch (InvalidArgumentException $ex) {
return $this->redirect()->toRoute('blog');
}
$this->form->bind($post);
$viewModel = new ViewModel(['form' => $this->form]);
$request = $this->getRequest();
if (! $request->isPost()) {
return $viewModel;
}
$this->form->setData($request->getPost());
if (! $this->form->isValid()) {
return $viewModel;
}
$post = $this->command->updatePost($post);
return $this->redirect()->toRoute(
'blog/detail',
['id' => $post->getId()]
);
}
Edit this code:
if (! $request->isPost()) {
foreach($this->form->getMessages() as $message){
$this->flashMessenger()->addErrorMessage($message['message']);
}
}
In your view:
<?php echo $this->flashMessenger()->renderCurrent('error', ['options go here...']); ?>

Categories