associated data in Mailer in CakePHP 3 - cakephp

I'm working on CakePHP 3.4
I have a contact_messages table to save message via form on website.
I want to send user an email whenever a new message is saved.
For that, I have created mailer class like
<?php
namespace App\Mailer;
use Cake\Mailer\Mailer;
use Cake\Event\Event;
use Cake\Datasource\EntityInterface;
class ContactMessageMailer extends Mailer
{
public function newMessage($message)
{
$this
->setProfile('no-reply')
->setTemplate('new_message')
->setLayout('message')
->setEmailFormat('html')
->setTo($user->email) // user email
->setSubject('Verify Account')
->setViewVars(['name' => $user->first_name, 'email' => $user->email, 'message' => $message->body]);
}
public function implementedEvents()
{
return [
'Model.afterSave' => 'alertMessage'
];
}
public function alertMessage(Event $event, EntityInterface $entity, \ArrayObject $options)
{
if ($entity->isNew()) {
$this->send('newMessage', [$entity]);
}
}
}
and registering event in ContactMessagesTable.php
$mailer = new UserMailer(); //use App\Mailer\UserMailer;
$this->eventManager()->on($mailer);
ContactMessages belongsTo Users and Users is having email of user whom to send the email.
How can I get users information in Mailer?

Will probably do this;
In the User table;
public function processUser($user)
{
if($this->save($user)){
$event = new Event('Model.afterSave', $this, [$entity = $user])
$this->eventManager()->dispatch($event);
return true;
}else{
return false;
}
}
In ContactMessage Table ;
public function initialize()
{
parent::intialize();
$mailer = new UserMailer(); //use App\Mailer\UserMailer;
$this->Users->eventManager()->on($mailer); //ContactMessage has to be related to User table
}
Hope I was able to communicate.

Related

Codeigniter autocheck db depending on session value

I'm trying to force my app to check every time it loads a model or controller depending on which is my session value.
This is actually running, but just when I get throw this model.
class News_model extends CI_Model {
public function __construct()
{
parent::__construct();
if($this->session->dbname=='db1'){
$this->db=$this->load->database('db1', TRUE);
}
else{
$this->db=$this->load->database('db2', TRUE);
}
}
public function get_news($slug = FALSE)
{
if ($slug === FALSE)
{
$query = $this->db->get('news');
return $query->result_array();
}
$query = $this->db->get_where('news', array('slug' => $slug));
return $query->row_array();
}
}
But I do not war to include that __construct code to all my models or controllers.
I've tried to add on my autoload.php
$autoload['model'] = array('General');
Where my General code is something like this.
class General extends CI_Model {
function __construct()
{
parent::__construct();
if($this->session->dbname=='db1'){
$this->db=$this->load->database('db1', TRUE);
}
else{
$this->db=$this->load->database('db2', TRUE);
}
}
}
How can I do it?
You can do it by creating a base model which will be extended by your models that require the database check.
I have simplified the checking and loading code. A simple ternary determines the string to use and stores it in the variable $dbname. That variable is used to load the database, i.e. $this->load->database($dbname);.
I don't believe you need the second argument to load::database() which means you don't need to set $this->db explicitly. If I'm wrong, use
$this->db = $this->load->database($dbname, TRUE);
Below is the "base" model. The prefix of the file name is determined in config.php with the setting $config['subclass_prefix'] = 'MY_'; Adjust your base model's file and class name to match the 'subclass_prefix' you use.
/application/core/MY_Model.php
<?php
class MY_Model extends CI_Model
{
public function __construct()
{
parent::__construct();
$dbname = $this->session->dbname == 'db1' ? 'db1' : 'db2';
$this->load->database($dbname);
}
}
Use the above to create other models like so...
class News_model extends MY_Model
{
public function get_news($slug = FALSE)
{
if ($slug === FALSE)
{
$query = $this->db->get('news');
return $query->result_array();
}
$query = $this->db->get_where('news', array('slug' => $slug));
return $query->row_array();
}
}

Symfony3 FOS UserBundle how to load choice as entity

I am using Symfony3.1 with FOS UsersBundle and I want some added fields to be loaded as specific Entity.
In RegistrationType I have
->add('country', ChoiceType::class, array(
'label' => 'label.country',
'required' => false,
'placeholder' => 'label.select_country',
'choices' => array(
'France' => '7v8tqr',
),
))
In my Entity User I have
/**
* #ORM\OneToOne(targetEntity="Country")
* #ORM\JoinColumn(name="country", referencedColumnName="short")
*/
protected $country;
I can't use the EntityType as it loads every available entity and I use the same kind of field for provinces and cities which are quite huge (I manage their content with javascript).
When I load a registered user, the country field is served as a Country Entity but when I register a new user or modify an existing one, I only have the string "short" which causes an error Expected value of type "AppBundle\Entity\Country" for association field "AppBundle\Entity\User#$country", got "string" instead..
Is there a solution ?
Thanks to #mcriecken who led me in the right direction, I have implemented the following solution, using an EventListener
in services.yml
app_user.registration:
class: AppBundle\EventListener\UserRegistrationListener
arguments: ['#doctrine.orm.entity_manager']
tags:
- { name: kernel.event_subscriber }
and the EventListener UserRegistrationListener.php
<?php
namespace AppBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Doctrine\ORM\EntityManager;
class UserRegistrationListener implements EventSubscriberInterface
{
protected $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* {#inheritDoc}
*/
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_SUCCESS => 'onRegistrationSuccess',
);
}
public function onRegistrationSuccess(FormEvent $event)
{
$form = $event->getForm()->getData();
//Gets the locations
$form->setCountry($this->getCountry($form->getCountry()));
$form->setProvince($this->getProvince($form->getProvince()));
$form->setCity($this->getCity($form->getCity()));
}
//Loads the country as an entity
public function getCountry($short)
{
if ($short == null) return null;
$repository = $this->em->getRepository('AppBundle:Country');
return $repository->findOneByShort($short);
}
//Loads the province as an entity
public function getProvince($short)
{
if ($short == null) return null;
$repository = $this->em->getRepository('AppBundle:Province');
return $repository->findOneByShort($short);
}
//Loads the city as an entity
public function getCity($short)
{
if ($short == null) return null;
$repository = $this->em->getRepository('AppBundle:City');
return $repository->findOneByShort($short);
}
}
Then at the end my FOS User object contains COuntry, Province and City as Objects and it can be saved to DB :-)

CakePHP 3 : display data from other model and pass parameter in url from action

I'm working on a project using CakePHP 3.x.
I have UserAddress, ServiceRequests, Service models.
There is a button on service/view/$id which when clicked will ask user to select address from service-requests/serviceArea which has a list of addresses added by user. service-requests/serviceArea view will contain a select button which when clicked will call add action in ServiceRequests controller with passing two parameters serviceId and userAddressId
This is the serviceArea function created by me.
public function serviceArea($id = null)
{
public $uses = array('UserAddress');
$service = $id;
$query = $userAddresses->find('all')
->where(['UserAddresses.user_id =' => $this->Auth->user('id')]);
$this->set(compact('userAddresses'));
$this->set('_serialize', ['userAddresses']);
}
How to display the address and also pass the $service parameter to the serviceArea view.
I am new to CakePHP, so if you think question is incomplete any edit to it will be appreciated instead of down-voting.
Thank You.
Edit 2
Thank for your answer #jazzcat
After changing my code according to yours and visiting http://domain.com/service-requests/service-area/$id. It is showing error as
Record not found in table "service_requests"
and pointing to the ServiceRequestsController on line no 33
The ServiceRequestController as containing line no 33 is
<?php
namespace App\Controller;
use App\Controller\AppController;
/**
* ServiceRequests Controller
*
* #property \App\Model\Table\ServiceRequestsTable $ServiceRequests
*/
class ServiceRequestsController extends AppController
{
/**
* isAuthorized method
*
*/
public function isAuthorized($user)
{
$action = $this->request->params['action'];
// The add and index actions are always allowed.
if(in_array($action, ['index', 'add', 'serviceRequests'])) {
return true;
}
// All other actions require an id.
if (empty($this->request->params['pass'][0])) {
return false;
}
// Check that the service request belongs to the current user.
$id = $this->request->params['pass'][0];
$serviceRequest = $this->ServiceRequests->get($id); // line : 33
if($serviceRequest->user_id == $user['id']) {
return true;
}
return parent::isAuthorized($user);
}
/* Other actions */
}
?>
This worked for me.
Just added the serviceArea action name in the isAuthorized method
if(in_array($action, ['index', 'add', 'serviceArea'])) {
return true;
}
and it's working fine as expected.
There is alot wrong with your code. Please read the docs
Is the table named user_addresses or user_address ?
You seem to mix the both.
The following would be the correct way to do it assuming your table is named user_addresses
public function serviceArea($id = null)
{
$this->loadModel('UserAddresses');
$userAddresses = $this->UserAddresses->find('all')
->where(['UserAddresses.user_id =' => $this->Auth->user('id')]);
// If you want to filter on the serviceArea ID aswell
if($id)
$userAddresses->andWhere(['id' => $id]);
// Setting SerivceArea ID to compact makes it available in view.
$serviceAreaId = $id;
$this->set(compact('userAddresses', 'serviceAreaId'));
$this->set('_serialize', ['userAddresses']);
}
This snippet:
$id = $this->request->params['pass'][0];
$serviceRequest = $this->ServiceRequests->get($id); // line : 33
Just checks if the first parameter passed to the method exists in ServiceRequests.
(That parameter could be anything, you have to keep that in mind when creating all your methods in that controller, that is to say the least.. bad)
I'm assuming that the service_requests table is associated with the users table and an user_id column exists in the service_requests table.
If that is the case this should work:
public function isAuthorized($user)
{
$action = $this->request->params['action'];
// The add and index actions are always allowed.
if(in_array($action, ['index', 'add'])) {
return true;
}
// Is not authorized if an argument is not passed to the method.
// Don't know why you'd want this , but sure.
if (empty($this->request->params['pass'][0])) {
return false;
}
// Check that the service request belongs to the current user.
$user_id = $this->Auth->user('id');
$serviceRequest = $this->ServiceRequests->find()->where(['ServiceRequests.user_id' => $user_id])->first();
if(!empty($serviceRequest)) {
return true;
}
return parent::isAuthorized($user);
}

Symfony 2 how to call the renderView method in FormHandler?

I try to do a contact form with Symfony 2.4.1. My form is a simple contact one without an entity.
The following error happens in my handler :
FatalErrorException: Error: Call to undefined method Symfony\Component\Form\Form::render() in C:\Program Files\wamp\www\sf2\src\Open\OpcBundle\Form\Handler\ContactHandler.php line 75
And the form handler code :
<?php
// src/Open/OpcBundle/Form/Handler/Handler.php
namespace Open\OpcBundle\Form\Handler;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
class ContactHandler {
protected $request;
protected $form;
protected $mailer;
public function __construct(Form $form, Request $request, $mailer) {
$this->form = $form;
$this->request = $request;
$this->mailer = $mailer;
}
public function process() {
if ('POST' == $this->request->getMethod()) {
$this->form->handleRequest($this->request);
$data = $this->form->getData();
$this->onSuccess($data);
return true;
}
return false;
}
protected function onSuccess($data) {
$message = \Swift_Message::newInstance()
->setContentType('text/html')
->setSubject($data['sujet'])
->setFrom($data['courriel'])
->setTo('me#gmail.com')
->setBody($this->render('OpcOpenBundle:Opc:Mails/contact.html.twig',
array('ip' => $request->getClientIp(),
'nom' => $data['nom'],
'msg' => $data['msg'])
)
);
$this->get('mailer')->send($message);
$request->getSession()->getFlash()->add('success', 'Your email has been sent! Thanks!');
return $this->redirect($this->generateUrl('contact'));
}
}
So the problem is that I don't have an object/instance for the renderView() method to call the template mail with setBody in the function onSuccess()
Which object/instance should I use for ?
Thanks
PS: sorry for my english, i'm French!
It's Symfony\Bundle\TwigBundle\TwigEngine class. service name is 'templating'.
BTW, why is you handler is not service?

Image doesn't uploading cakephp 2.0

I have used a component for uploading image,there is no problem in controller after add component.Here the code
class OesUsersController extends AppController {
var $helpers = array('Html', 'Form');
var $components = array('upload');
public function index() {
}
public function upload()
{
if (empty($this->data))
{
$this->render();
}
else
{
$this->cleanUpFields();
// set the upload destination folder
$destination = realpath('../../app/webroot/img/uploads/') . '/';
// grab the file
$file = $this->data['Image']['filedata'];
// upload the image using the upload component
$result = $this->Upload->upload($file, $destination, null, array('type' => 'resizecrop', 'size' => array('400', '300'), 'output' => 'jpg'));
if (!$result){
$this->data['Image']['filedata'] = $this->Upload->result;
} else {
// display error
$errors = $this->Upload->errors;
// piece together errors
if(is_array($errors)){ $errors = implode("<br />",$errors); }
$this->Session->setFlash($errors);
$this->redirect('/images/upload');
exit();
}
if ($this->Image->save($this->data)) {
$this->Session->setFlash('Image has been added.');
$this->redirect('/images/index');
} else {
$this->Session->setFlash('Please correct errors below.');
unlink($destination.$this->Upload->result);
}
}
}
The problem is image doesn't come from add.ctp
here the add.ctp code
<label for="Image">Image:</label>
<input type="file" name="data[Image][filedata]" id="ImageFiledata" />
add function code
public function add() {
$clint_ip=$this->request->clientIp();
if ($this->request->is('post')) {
$this->OesUser->create();
pr($this->request->data);
$this->request->data['OesUser']['user_otpkey']=String::uuid();
$this->request->data['OesUser']['user_regdate']=date("Y-m-d H:i:s");
$this->request->data['OesUser']['user_ip']=$clint_ip;
$this->barcode($this->request->data['OesUser']['user_otpkey']);
if ($this->OesUser->save($this->request->data)) {
$this->Session->setFlash(__('The oes user has been saved'), 'flash_success');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The oes user could not be saved. Please, try again.'), 'flash_fail');
}
}
$this->set('ip',$clint_ip);
}
here, database field name: image
controller name :OesUsers
Model name :OesUser
for full work I have taken help from this link
http://labs.iamkoa.net/2007/10/23/image-upload-component-cakephp/
How is your entire form looks like in add.ctp?
It sounds to me that you did not add
enctype="multipart/form-data"
to the form. That will cause the form not to post the file.
And also, it is recommended to use Form helper to create form.
When using Form helper, specify the form type to file
$this->Form->create('model',array('type'=>'file'));

Resources