How to render twig templates into a service. Is it Best practice? - twig

I have the following Symfony 3 controller:
public function register(Request $request)
{
$username=$request->get('username');
$password=$request->get('password');
$email=$request->get('email');
$captchaResponse=$request->get('g-recaptcha-response');
$session =$request->getSession();
$res1 = new Response();
$response_data=array('status'=>0);
if($session->get('captcha')===$captchaResponse)
{
$en = $this->container->get('user_model');
$data=$en->register($username,$password,$email);
$res1->headers->set('Content-Type','text/json');
if($data['status']===false)
{
$response_data['data']="An Internal error Happened";
error_log($data['data']);
}
else if($data['status']===-1)
{
$response_data['data']=$data['data'];
}
else
{
$response_data['status']=1;
$response_data['data']="Please check your mail to confirm your registration.";
/*Send Email*/
$message = \Swift_Message::newInstance()
->setSubject('Please confirm your registration')
->setFrom('symphotest#openmailbox.org')
->setTo($email)
->setBody($this->renderView('emails/confirm.html.twig',array('token'=>$data['data'])))
->addPart(
$this->renderView('emails/registration.txt.twig',array('token'=>$data['data'])),
'text/plain'
);
$this->get('mailer')->send($message);
}
}
else
{
$response_data['data']="You have not given a correct captcha";
}
$res1->setContent(json_encode($response_data));
$session->set('captcha',uniqid());//Generate gibberish in order not to reuse the very same captcha again
return $res1;
}
And I have made the following service:
namespace AppBundle\Models;
use Doctrine\ORM\EntityManager;
use AppBundle\Util\ModelStatus;
use AppBundle\Exceptions\InvalidArgumentException;
use \SwiftMessage;
class UserModel
{
/** #var EntityManager */
private $em;
/** #var \Swift_Mailer */
private $mailer;
/** #var \Twig_Environment */
private $twig;
/**
*
* #param EntityManager $em
* #param \Swift_Mailer $mailer
* #param \Twig_Environment $twig
*/
public function construct(EntityManager $em, \Swift_Mailer $mailer,\Twig_Environment $twig)
{
$this->em=$em;
$this->$mailer=$mailer;
}
/**
* Performs the actions needed for Registration
*
* #param unknown $username
* #param unknown $password
* #param unknown $email
* #param \Swift_Message $registrationMessage
*
* #return ModelStatus
*/
public function register($username,$password,$email)
{
$modelStatus=new ModelStatus();
try
{
/** #var \AppBundle\Entity\UserRepository */
$repository=$this->em->getRepository('AppBundle::Users');
$token=$repository->register($username,$password,$email);
$modelStatus->setData($token);
$modelStatus->setStatus(ModelStatus::STATUS_SUCCESS);
$this->mailer->send($registrationMessage);
$message = Swift_Message::newInstance()
->setSubject('Please confirm your registration')
->setFrom('symphotest#openmailbox.org')
->setTo($email)
->setBody($this->twig->//->renderView('emails/confirm.html.twig',array('token'=>$data['data'])))
->addPart(
$this->renderView('emails/registration.txt.twig',array('token'=>$data['data'])),
'text/plain'
);
$this->get('mailer')->send($message);
}
catch(InvalidArgumentException $arg)
{
$modelStatus->setStatus(ModelStatus::STATUS_FAILURE);
$modelStatus->setMessage($arg->getMessage());
}
catch (\Exception $e)
{
$modelStatus->setStatus(ModelStatus::STATUS_FAILURE);
$modelStatus->setMessage($e->getMessage());
}
return $modelStatus;
}
}
And I am refactoring the following section:
$message = \Swift_Message::newInstance()
->setSubject('Please confirm your registration')
->setFrom('symphotest#openmailbox.org')
->setTo($email)
->setBody($this->renderView('emails/confirm.html.twig',array('token'=>$data['data'])))
->addPart(
$this->renderView('emails/registration.txt.twig',array('token'=>$data['data'])),
'text/plain'
);
$this->get('mailer')->send($message);
Into the Model method register.
But As you can see I render some twig templates and I do know the best Option on how to do it. So far I thought the following options:
To render the templates as string and pass them to the the register method, create and send the email there.
Load the twig rendering service into the model and the render into the model. If not exists create one.
In the second bullet I may need to load the Twig rendering engine into a service. How can I do that?

In the end having the constructor like this:
public function __construct(EntityManager $em, \Swift_Mailer $mailer,\Twig_Environment $twig)
{
$this->em=$em;
$this->mailer=$mailer;
$this->twig=$twig;
}
And loading the service like this:
user_model:
class: AppBundle\Models\UserModel
arguments: ['#doctrine.orm.entity_manager','#mailer','#twig']
Seems that solved the problem.

Related

Laravel Echo listener is not listening

this is my first project with vue and nodejs so please let me know if I there is a missing information.
I'm trying to develop a group chat with Laravel, Vue js and Pusher.
Database Tables and Relations
I want to create a private Channel for each team which is available.
As soon as you click on the group chat, the existing messages get loaded and shown.
When you send a message, the message gets added to the messages table and is also sent successfully to pusher as you can see here:
Pusher message
The message is also added to the message list on the sender but not on the other team members.
Sender
Other team members
The new message is only shown on the other team members when they reload the page. That means that the echo listener doesn't seem to work. What can I do to fix it? What is wrong?
Here is my code:
ChatApp.vue (root component)
<template>
<div class="chat-container row">
<i class="far fa-comments fa-3x"></i>
<div id="chat-app" class="chat-app">
<div class="row mx-0 h-100 overflow-hidden">
<TeamList :teams="teamList" #selected="startConversationWith"/>
<Conversation :team="selectedTeam" :messages="messages" #new="saveNewMessage"/>
</div>
</div>
</div>
</template>
<script>
import MessageList from './MessageList';
import TeamList from './TeamList';
import Conversation from './Conversation';
import MessageTextBox from './MessageTextBox';
export default {
props: {
user: {
type: Object,
required: true
}
},
data() {
return {
messages: [],
teamList: [],
selectedTeam: null,
}
},
mounted() {
Echo.private('messages.1')
.listen('NewMessage', (e) => {
this.handleIncoming(e.message);
});
axios.get('/teams')
.then((response) => {
this.teamList = response.data;
});
},
methods: {
startConversationWith(team) {
axios.get('/conversation/' + team.id)
.then((response) => {
this.messages = response.data;
this.selectedTeam = team;
});
},
saveNewMessage(text) {
this.messages.push(text);
},
handleIncoming(message) {
this.saveNewMessage(message);
return;
}
},
components: {TeamList, MessageList, MessageTextBox, Conversation}
}
</script>
App/Events/NewMessage.php
<?php
namespace App\Events;
use App\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class NewMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #param Message $message
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('messages.' . $this->message->team_id);
}
public function broadcastWith()
{
$this->message->load('team');
return ["message" => $this->message];
}
}
routes/channels.php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('messages.{id}', function ($team_id, $message) {
return true;
// return (int) $team->id === (int) $id;
});
Message model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Message extends Model
{
protected $guarded = [];
public function team()
{
return $this->belongsTo('App\Team');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
ContactsController
namespace App\Http\Controllers;
use App\Events\NewMessage;
use App\Message;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
class ContactsController extends Controller
{
public function getTeams() {
$teams = Auth::user()->teams;
return response()->json($teams);
}
public function getMessagesFor($id)
{
$messages = Message::where('team_id', $id)->get();
return response()->json($messages);
}
public function send(Request $request) {
$message = Message::create([
'team_id' => $request->team_id,
'user_id' => Auth::user()->id,
'message' => $request->text
]);
broadcast(new NewMessage($message));
return response()->json($message);
}
}
bootstrap.js
window._ = require('lodash');
/**
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
* for JavaScript based Bootstrap features such as modals and tabs. This
* code may be modified to fit the specific needs of your application.
*/
try {
window.Popper = require('popper.js').default;
window.$ = window.jQuery = require('jquery');
require('bootstrap');
} catch (e) {}
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
encrypted is set to true for SSL config. Try setting it to false when configuring laravel echo in bootstrap.js
As you can see in the comments, setting encrypted to false in bootstrap.js solved the problem

Logout doesn't logout in laravel socialite

I am unable to logout the google user in my application,when i logout it was redirecting login page saying it is successfully logged out but when i click login with google button it is redirecting to previous logged in user i.e., it is not logged out
my controller code:
class LoginController extends Controller {
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct() {
$this->middleware('guest')->except('logout','getLogout');
}
/**
* Redirect the user to the GitHub authentication page.
*
* #return \Illuminate\Http\Response
*/
public function redirectToProvider() {
return Socialite::driver('google')->redirect();
}
/**
* Obtain the user information from GitHub.
*
* #return \Illuminate\Http\Response
*/
public function handleProviderCallback() {
$user = Socialite::driver('google')->stateless()->user();
if($user) {
$authUser = $this->findOrCreateUser($user);
Auth::login($authUser, true);
}
return view ( 'home' )->withDetails ( $user )->withService ( 'google' );
// $user->token;
}
/**
* Return user if exists; create and return if doesn't
*
* #param $githubUser
* #return User
*/
private function findOrCreateUser($googleUser) {
if ($authUser = User::where('email', $googleUser->email)->first()) {
return $authUser;
}
return User::create([
'name' => $googleUser->name,
'email' => $googleUser->email,
]);
}}
I have followed the laravel documentation steps for this social login but i am unable to logout from my application..can anyone explain why this is going to happen??
Well, finally i found solution to my question.Actually, there is nothing to worry about it.Logout code is working pretty good.Google account ask for permission for first time login after getting grant access it won't ask for permission it directly continues to login.If we logout the google account then it will ask for permission otherwise it won't

Automatically merge session user in Symfony2

I have written my own User-class extending Symfony's UserInterface and EquatableInterface which gets authenticated nice on logins and is correctly retrievable using $this->getUser(); in a controller.
Now, my question is, if it is possible to write something (dunno, a listener for example) that can automatically merge the user coming from the open session (so the one you retrieve with $user = $this->getUser();), so I dont have to call stuff like:
/**
* #Route("/url/to/route")
*/
public function myAction()
{
$user = $this->getUser();
$mergedUser = $this->getDoctrine()->getManager()->merge($user);
return array('user' => $mergedUser);
}
But instead:
/**
* #Route("/url/to/route")
*/
public function myAction()
{
/* User gets merged automatically! */
$mergedUser = $this->getUser();
return array('user' => $mergedUser);
}

What is log4J's equivalent of java.util.logging.Handler

I like to intercept some (the most important) log messages and display them inside the GUI or check if any errors where logged. Normally I use java.util.logging and here the java.util.logging.Handler with and java.util.logging.Formatter.
However the current project uses Log4J (2.x) and there every feature has different names and seems to be at least four times as complex.
Can anybody give me some hints on how to archive something like this with Log4J:
/**
* <p>
* logs error so they can be returned to the server (and tested in unit tests)
* </p>
*
* #author "Martin Krischik" <martin.krischik#noser.com>
* #version 1.0 $Revision: 2229 $
* #see java.util.logging.Handler
* #since 1.0
*/
#SuppressWarnings ("synthetic-access")
protected final class LogHandler
extends
java.util.logging.Handler
{
/**
* <p>
* A very simple formatter which displays only what is relevant to end users. Developer
* should look at the log file
* </p>
*
* #author "Martin Krischik" <martin.krischik#noser.com>
* #version 1.0 $Revision: 2229 $
* #see java.util.logging.Formatter
* #since 1.0
*/
private class LogFormatter
extends
java.util.logging.Formatter
{
/**
* <p>
* line separator
* </p>
*/
private final String lineSeparator = System.getProperty ("line.separator");
/**
* <p>
* Format the given LogRecord.
* </p>
*
* #param record
* the log record to be formatted.
* #return a formatted log record
* #see java.util.logging.Formatter#format(java.util.logging.LogRecord)
*/
#Override
public synchronized String format (final java.util.logging.LogRecord record)
{
final StringBuilder retval = new StringBuilder (4096);
final String message = this.formatMessage (record);
final java.util.logging.Level level = record.getLevel ();
retval.append (level.getLocalizedName ());
retval.append (": ");
retval.append (message);
retval.append (this.lineSeparator);
return retval.toString ();
} // format
} // LogFormatter
/**
* <p>
* A very simple formatter which displays only what is relevant to end users. Developer
* should look at the log file
* </p>
*/
private final DBUpdate.LogHandler.LogFormatter formatter =
new DBUpdate.LogHandler.LogFormatter ();
/**
* #throws SecurityException
* some severity error
* #see java.util.logging.Handler#close()
*/
#Override
public void close ()
throws SecurityException
{
return;
} // close
/**
* #see java.util.logging.Handler#flush()
*/
#Override
public void flush ()
{
return;
} // flush
/**
* #param record
* record to log.
* #see java.util.logging.Handler#publish(java.util.logging.LogRecord)
*/
#Override
public void publish (final java.util.logging.LogRecord record)
{
if (record.getLevel ().intValue () >= this.getLevel ().intValue ())
{
REST_Responce.this.errorMessages.add (this.formatter.format (record));
} // if
return;
} // publish
} // LogHandler
You could try to subclass AbstractAppender.
Appender maps to Handler
Layout maps to Formatter
ErrorHandler maps to ErrorManager

GWT cross-domain rpc

I need to call a GWT application service from javascript which is running on different domain.
How could this be done? How do I point from my applicaton to the javascript url?
Thank you.
The idea behind a cross domain request is the your java script creats a script tag which loads a generated java script from the forgein url. When loaded the generated java script is evaluated and calls a callback function you created.
The following code ist not testet and shows the idea:
public class CrossSiteDomainRequest {
/** Counter to create unique ids for callback function. */
private static int idCounter = 0;
/** Url to load the javascript from. */
private String url;
/**
* Creates a new loader with the given <code>url</code>.
* #param url to load the java script from {#link #url}.
*/
public CrossSiteDomainRequest(String url) {
this.url = url;
}
/**
* Uses the {#link #url} to load the data from another url.
*/
public void load() {
String callbackId = "callbackId" + idCounter++;
String prepend = url.indexOf("?") != -1 ? "&" : "?";
String u = url + prepend + "callback=" + callbackId// Add more Parameters
createCallback(this, transId);
Element script = DOM.createElement("script");
script.setAttribute("src", u);
script.setAttribute("id", callbackId);
script.setAttribute("type", "text/javascript");
script.setAttribute("language", "JavaScript");
getHead().appendChild(script);
}
/**
* Destroys the callback with the given <code>id</code>.
* #param id of the script tag and native javascript callback function which should be destroyed.
*/
protected void destroyCallbackmethod(String id) {
getHead().removeChild(DOM.getElementById(id));
removeCallback(id);
}
/**
* This method is invoked by the callback to handel the loaded data.
* #param callbackId DOM-Id of the callback whick invoked this method.
* #param jso Object that encapsultes the loaded data.
*/
#SuppressWarnings("unchecked")
protected void onReceivedData(String callbackId, JavaScriptObject jso) {
try {
// Read data
} catch (Exception e) {
// Handle Error
}
destroyCallbackmethod(callbackId);
}
/**
* Creates a native javascript callback.
* #param cscr to invoke the {#link #onReceivedData(String, com.google.gwt.core.client.JavaScriptObject)} on when the data has been loaded.
* #param callbackId DOM-Id to create the callback back.
*/
private native void createCallback(CrossSiteDomainRequest cscr, String callbackId) /*-{
$wnd[callbackId] = function(j) {
proxy.#com.test.package.client.CrossSiteDomainRequest::onReceivedData(Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)(callbackId, j);
};
}-*/;
private native void removeCallback(String callbackId) /*-{
$wnd[callbackId] = null;
}-*/;
public static native Element getHead() /*-{
return $doc.getElementsByTagName('head')[0];
}-*/;
}
If you create a CrossSiteDomainRequest Object for the URL http://www.test.com/loadXDR.js
you have to evaluate the callbackId parameter and generate a java script which may looks like this:
callbackId({"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}});
The callbackId has to be replaced accordingly.

Resources