I am a beginner in php. I have a WadoService service and a StudiesRestController controller. I want to use controller data in the service.
public function getPatientAction(Request $request, $studyUID)
{
$studyRepository = new StudyRepository(
$this->get('nexus_db'),
$this->get('logger'),
$this->get('translator')
);
$study = $studyRepository->getStudy($studyUID);
if (!$study) {
throw new NotFoundHttpException("No study found with studyuid $studyUID");
}
$patientInfo = new RestResponse(
SerializerBuilder::create()
->build()
->serialize($study->getPatient(), 'json')
);
return $patientInfo;
}
Is this possible? I have tried to put this in the function getPatientAction()without result:
/* #var $wadoService WadoService */
$wadoService = $this->container->get(WadoService::SERVICE_NAME);
$wadoService = new RestResponse(
SerializerBuilder::create()
->build()
->serialize($study->getPatient(), 'json')
);
To pass a variable from your controller to your service, you do it it like that :
$wadoService = $this->container->get(WadoService::SERVICE_NAME)->yourServiceMethod($yourVari);
Related
I have build a Rest webservice that has a mvc structure, but I need some suggestion on how to make it better.
What I have right know is :
all the request come to the front controller (index.php)
$request = new Request(); //parse all the elements of the request
// spl_api_autoload takes care for loading the classes
$controller_name = ucfirst($request->url_elements[1]) . 'Controller';
if (class_exists($controller_name)) {
$controller = new $controller_name();
$action_name = strtolower($request->verb) . 'Action';
$result = $controller->$action_name($request);
} // this acts like a sort of router
The url looks like this:
index.php/tree/addnode/4/testnode
tree -> Resource
addnode -> action
4 -> parent id
testnode -> node name
What I need a suggestion is in this part down here (controller) :
if(isset($request->url_elements[2])) {
switch ($request->url_elements[2]) {
case 'addroot':
if(isset($request->url_elements[3])) {
$name = $request->url_elements[3];
$nested = new NestedSetClass();
$nested->createRootNode($name);
}
return $data;
break;
case 'addnode':
if(isset($request->url_elements[3])) {
if(isset($request->url_elements[4])) {
$parent = $request->url_elements[3];
$name = $request->url_elements[4];
$nested = new NestedSetClass();
$nested->insertChildNode($name,$parent);
}
}
break;
default:
# code...
break;
}
}
I want to skip the switch cases , Is there anyway I can do this ?
Thank you very very much for your time
When doing something like this I used the html methods like so
$app = App::init();
try{
//Pass the information here so data can be handled
//This makes it easier for other people who are new to oop, but not really correct
$app->$method($target, $data)
}catch(Exception e){ //handle error }
App Class
public function get($target, $data); get resource from db
public function post($target, $data); post resource to db
etc.
Sample of post
function post($target, $data)
{
$control = new $target();
return $control->handle($data);
}
Im trying to use VisualCaptcha with my Laravel apps. I have tried to adapt this exemple with my code. But I dont know how to adapt this following callback to my controller :
$app->get( '/audio(/:type)', function( $type = 'mp3' ) use( $app ) {
$captcha = new \visualCaptcha\Captcha( $app->session );
if ( ! $captcha->streamAudio( $app->response, $type ) ) {
$app->pass();
}
} );
Here is my controller :
class CaptchaController extends BaseController {
/**
* Start Captcha
*/
public function start($params)
{
$session = new SessionCaptcha();
$captcha = new Captcha($session);
return $captcha->generate();
}
public function audio()
{
$session = new SessionCaptcha();
$captcha = new Captcha($session);
//$response = Response::make();
$response->header('Access-Control-Allow-Origin', '*');
//return var_dump($response);
return $captcha->streamAudio($response, 'mp3');
}
}
The start function works but not the audio function... I dont know how to add the first parameter to "$captcha->streamAudio($firstParam, $extension)".
Just in case other people land here first, this has been answered at https://github.com/emotionLoop/visualCaptcha-PHP/issues/16#issuecomment-53863330
The author mentioned not returning $captcha->generate(); but also some undisclosed modifications.
Let's say I have this JS code:
var events = ['start', 'stop', 'tick']
, obj = ... // object with events
, receiver = function(event_name, event_args){ // function to receive all events
console.log(event_name, event_args);
}
;
for(var i=0; i<events.length; i++){
obj.on(events[i], (function(event){
return function(){
return receiver(event, arguments);
};
})(events[i]));
}
What I'm doing here is to route all events to function "receiver".
I'm trying to replicate this behavior in PHP, since I already have obj.on ($obj->on) functionality.
I would like to support (slightly) old PHP versions (5.1+), so I can't make use of anonymous functions (as well as passing variables to said functions).
Here's a tentative (and incomplete) version of the above code:
$events = array('start', 'stop', 'tick');
$obj = new ... ; // object with events
function receiver($event_name, $event_args){ // function to receive all events
echo $event_name.' | '.print_r($event_args, true);
}
foreach($events as $event){
$obj->on($event, ...); // ???
// ???
return receiver($event, func_get_arguments());
// ???
}
One of the possible approaches I can see is making use of __invoke:
$events = array('start', 'stop', 'tick');
$obj = new ... ; // object with events
function receiver($event_name, $event_args){ // function to receive all events
echo $event_name.' | '.print_r($event_args, true);
}
class EventRedirector {
public $event_name = '';
public $redirector = '';
public function __invoke(){
$redirector = $this->redirector;
return $redirector($this->event_name, func_get_args());
}
public function __construct($event_name, $redirector){
$this->event_name = $event_name;
$this->redirector = $redirector;
}
}
foreach($events as $event){
$obj->on($event, new EventRedirector($event, 'receiver'));
}
I have been reading a lot about how and why to use an MVC approach in an application. I have seen and understand examples of a Model, I have seen and understand examples of the View.... but I am STILL kind of fuzzy on the controller. I would really love to see a thorough enough example of a controller(s). (in PHP if possible, but any language will help)
Thank you.
PS: It would also be great if I could see an example of an index.php page, which decides which controller to use and how.
EDIT: I know what the job of the controller is, I just don't really understand how to accomplish this in OOP.
Request example
Put something like this in your index.php:
<?php
// Holds data like $baseUrl etc.
include 'config.php';
$requestUrl = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
$requestString = substr($requestUrl, strlen($baseUrl));
$urlParams = explode('/', $requestString);
// TODO: Consider security (see comments)
$controllerName = ucfirst(array_shift($urlParams)).'Controller';
$actionName = strtolower(array_shift($urlParams)).'Action';
// Here you should probably gather the rest as params
// Call the action
$controller = new $controllerName;
$controller->$actionName();
Really basic, but you get the idea... (I also didn't take care of loading the controller class, but I guess that can be done either via autoloading or you know how to do it.)
Simple controller example (controllers/login.php):
<?php
class LoginController
{
function loginAction()
{
$username = $this->request->get('username');
$password = $this->request->get('password');
$this->loadModel('users');
if ($this->users->validate($username, $password))
{
$userData = $this->users->fetch($username);
AuthStorage::save($username, $userData);
$this->redirect('secret_area');
}
else
{
$this->view->message = 'Invalid login';
$this->view->render('error');
}
}
function logoutAction()
{
if (AuthStorage::logged())
{
AuthStorage::remove();
$this->redirect('index');
}
else
{
$this->view->message = 'You are not logged in.';
$this->view->render('error');
}
}
}
As you see, the controller takes care of the "flow" of the application - the so-called application logic. It does not take care about data storage and presentation. It rather gathers all the necessary data (depending on the current request) and assigns it to the view...
Note that this would not work with any framework I know, but I'm sure you know what the functions are supposed to do.
Imagine three screens in a UI, a screen where a user enters some search criteria, a screen where a list of summaries of matching records is displayed and a screen where, once a record is selected it is displayed for editing. There will be some logic relating to the initial search on the lines of
if search criteria are matched by no records
redisplay criteria screen, with message saying "none found"
else if search criteria are matched by exactly one record
display edit screen with chosen record
else (we have lots of records)
display list screen with matching records
Where should that logic go? Not in the view or model surely? Hence this is the job of the controller. The controller would also be responsible for taking the criteria and invoking the Model method for the search.
<?php
class App {
protected static $router;
public static function getRouter() {
return self::$router;
}
public static function run($uri) {
self::$router = new Router($uri);
//get controller class
$controller_class = ucfirst(self::$router->getController()) . 'Controller';
//get method
$controller_method = strtolower((self::$router->getMethodPrefix() != "" ? self::$router->getMethodPrefix() . '_' : '') . self::$router->getAction());
if(method_exists($controller_class, $controller_method)){
$controller_obj = new $controller_class();
$view_path = $controller_obj->$controller_method();
$view_obj = new View($controller_obj->getData(), $view_path);
$content = $view_obj->render();
}else{
throw new Exception("Called method does not exists!");
}
//layout
$route_path = self::getRouter()->getRoute();
$layout = ROOT . '/views/layout/' . $route_path . '.phtml';
$layout_view_obj = new View(compact('content'), $layout);
echo $layout_view_obj->render();
}
public static function redirect($uri){
print("<script>window.location.href='{$uri}'</script>");
exit();
}
}
<?php
class Router {
protected $uri;
protected $controller;
protected $action;
protected $params;
protected $route;
protected $method_prefix;
/**
*
* #return mixed
*/
function getUri() {
return $this->uri;
}
/**
*
* #return mixed
*/
function getController() {
return $this->controller;
}
/**
*
* #return mixed
*/
function getAction() {
return $this->action;
}
/**
*
* #return mixed
*/
function getParams() {
return $this->params;
}
function getRoute() {
return $this->route;
}
function getMethodPrefix() {
return $this->method_prefix;
}
public function __construct($uri) {
$this->uri = urldecode(trim($uri, "/"));
//defaults
$routes = Config::get("routes");
$this->route = Config::get("default_route");
$this->controller = Config::get("default_controller");
$this->action = Config::get("default_action");
$this->method_prefix= isset($routes[$this->route]) ? $routes[$this->route] : '';
//get uri params
$uri_parts = explode("?", $this->uri);
$path = $uri_parts[0];
$path_parts = explode("/", $path);
if(count($path_parts)){
//get route
if(in_array(strtolower(current($path_parts)), array_keys($routes))){
$this->route = strtolower(current($path_parts));
$this->method_prefix = isset($routes[$this->route]) ? $routes[$this->route] : '';
array_shift($path_parts);
}
//get controller
if(current($path_parts)){
$this->controller = strtolower(current($path_parts));
array_shift($path_parts);
}
//get action
if(current($path_parts)){
$this->action = strtolower(current($path_parts));
array_shift($path_parts);
}
//reset is for parameters
//$this->params = $path_parts;
//processing params from url to array
$aParams = array();
if(current($path_parts)){
for($i=0; $i<count($path_parts); $i++){
$aParams[$path_parts[$i]] = isset($path_parts[$i+1]) ? $path_parts[$i+1] : null;
$i++;
}
}
$this->params = (object)$aParams;
}
}
}
Create folder structure
Setup .htaccess & virtual hosts
Create config class to build config array
Controller
Create router class with protected non static, with getters
Create init.php with config include & autoload and include paths (lib, controlelrs,models)
Create config file with routes, default values (route, controllers, action)
Set values in router - defaults
Set uri paths, explode the uri and set route, controller, action, params ,process params.
Create app class to run the application by passing uri - (protected router obj, run func)
Create controller parent class to inherit all other controllers (protected data, model, params - non static)
set data, params in constructor.
Create controller and extend with above parent class and add default method.
Call the controller class and method in run function. method has to be with prefix.
Call the method if exisist
Views
Create a parent view class to generate views. (data, path) with default path, set controller, , render funcs to
return the full tempalte path (non static)
Create render function with ob_start(), ob_get_clean to return and send the content to browser.
Change app class to parse the data to view class. if path is returned, pass to view class too.
Layouts..layout is depend on router. re parse the layout html to view and render
Please check this:
<?php
global $conn;
require_once("../config/database.php");
require_once("../config/model.php");
$conn= new Db;
$event = isset($_GET['event']) ? $_GET['event'] : '';
if ($event == 'save') {
if($conn->insert("employee", $_POST)){
$data = array(
'success' => true,
'message' => 'Saving Successful!',
);
}
echo json_encode($data);
}
if ($event == 'update') {
if($conn->update("employee", $_POST, "id=" . $_POST['id'])){
$data = array(
'success' => true,
'message' => 'Update Successful!',
);
}
echo json_encode($data);
}
if ($event == 'delete') {
if($conn->delete("employee", "id=" . $_POST['id'])){
$data = array(
'success' => true,
'message' => 'Delete Successful!',
);
}
echo json_encode($data);
}
if ($event == 'edit') {
$data = $conn->get("select * from employee where id={$_POST['id']};")[0];
echo json_encode($data);
}
?>
I am developing a Facebook app in Zend Framework. In startAction() I am getting the following error:
The URL http://apps.facebook.com/rails_across_europe/turn/move-trains-auto is not valid.
I have included the code for startAction() below. I have also included the code for moveTrainsAutoAction (these are all TurnController actions) I can't find anything wrong with my _redirect() in startAction(). I am using the same redirect in other actions and they execute flawlessly. Would you please review my code and let me know if you find a problem? I appreciate it! Thanks.
public function startAction() {
require_once 'Train.php';
$trainModel = new Train();
$config = Zend_Registry::get('config');
require_once 'Zend/Session/Namespace.php';
$userNamespace = new Zend_Session_Namespace('User');
$trainData = $trainModel->getTrain($userNamespace->gamePlayerId);
switch($trainData['type']) {
case 'STANDARD':
default:
$unitMovement = $config->train->standard->unit_movement;
break;
case 'FAST FREIGHT':
$unitMovement = $config->train->fast_freight->unit_movement;
break;
case 'SUPER FREIGHT':
$unitMovement = $config->train->superfreight->unit_movement;
break;
case 'HEAVY FREIGHT':
$unitMovement = $config->train->heavy_freight->unit_movement;
break;
}
$trainRow = array('track_units_remaining' => $unitMovement);
$where = $trainModel->getAdapter()->quoteInto('id = ?', $trainData['id']);
$trainModel->update($trainRow, $where);
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto');
}
.
.
.
public function moveTrainsAutoAction() {
$log = Zend_Registry::get('log');
$log->debug('moveTrainsAutoAction');
require_once 'Train.php';
$trainModel = new Train();
$userNamespace = new Zend_Session_Namespace('User');
$gameNamespace = new Zend_Session_Namespace('Game');
$trainData = $trainModel->getTrain($userNamespace->gamePlayerId);
$trainRow = $this->_helper->moveTrain($trainData['dest_city_id']);
if(count($trainRow) > 0) {
if($trainRow['status'] == 'ARRIVED') {
// Pass id for last city user selected so we can return user to previous map scroll postion
$this->_redirect($config->url->absolute->fb->canvas . '/turn/unload-cargo?city_id='.$gameNamespace->endTrackCity);
} else if($trainRow['track_units_remaining'] > 0) {
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto');
} else { /* Turn has ended */
$this->_redirect($config->url->absolute->fb->canvas . '/turn/end');
}
}
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto-error'); //-set-destination-error');
}
As #Jani Hartikainen points out in his comment, there is really no need to URL-encode underscores. Try to redirect with literal underscores and see if that works, since I believe redirect makes some url encoding of its own.
Not really related to your question, but in my opinion you should refactor your code a bit to get rid of the switch-case statements (or at least localize them to a single point):
controllers/TrainController.php
[...]
public function startAction() {
require_once 'Train.php';
$trainTable = new DbTable_Train();
$config = Zend_Registry::get('config');
require_once 'Zend/Session/Namespace.php';
$userNamespace = new Zend_Session_Namespace('User');
$train = $trainTable->getTrain($userNamespace->gamePlayerId);
// Add additional operations in your getTrain-method to create subclasses
// for the train
$trainTable->trackStart($train);
$this->_redirect(
$config->url->absolute->fb->canvas . '/turn/move-trains-auto'
);
}
[...]
models/dbTable/Train.php
class DbTable_Train extends Zend_Db_Table_Abstract
{
protected $_tableName = 'Train';
[...]
/**
*
*
* #return Train|false The train of $playerId, or false if the player
* does not yet have a train
*/
public function getTrain($playerId)
{
// Fetch train row
$row = [..];
return $this->trainFromDbRow($row);
}
private function trainFromDbRow(Zend_Db_Table_Row $row)
{
$data = $row->toArray();
$trainType = 'Train_Standard';
switch($row->type) {
case 'FAST FREIGHT':
$trainType = 'Train_Freight_Fast';
break;
case 'SUPER FREIGHT':
$trainType = 'Train_Freight_Super';
break;
case 'HEAVY FREIGHT':
$trainType = 'Train_Freight_Heavy';
break;
}
return new $trainType($data);
}
public function trackStart(Train $train)
{
// Since we have subclasses here, polymorphism will ensure that we
// get the correct speed etc without having to worry about the different
// types of trains.
$trainRow = array('track_units_remaining' => $train->getSpeed());
$where = $trainModel->getAdapter()->quoteInto('id = ?', $train->getId());
$this->update($trainRow, $where);
}
[...]
/models/Train.php
abstract class Train
{
public function __construct(array $data)
{
$this->setValues($data);
}
/**
* Sets multiple values on the model by calling the
* corresponding setter instead of setting the fields
* directly. This allows validation logic etc
* to be contained in the setter-methods.
*/
public function setValues(array $data)
{
foreach($data as $field => $value)
{
$methodName = 'set' . ucfirst($field);
if(method_exists($methodName, $this))
{
$this->$methodName($value);
}
}
}
/**
* Get the id of the train. The id uniquely
* identifies the train.
* #return int
*/
public final function getId ()
{
return $this->id;
}
/**
* #return int The speed of the train / turn
*/
public abstract function getSpeed ();
[..] //More common methods for trains
}
/models/Train/Standard.php
class Train_Standard extends Train
{
public function getSpeed ()
{
return 3;
}
[...]
}
/models/Train/Freight/Super.php
class Train_Freight_Super extends Train
{
public function getSpeed ()
{
return 1;
}
public function getCapacity ()
{
return A_VALUE_MUCH_LARGER_THAN_STANDARD;
}
[...]
}
By default, this will send an HTTP 302 Redirect. Since it is writing headers, if any output is written to the HTTP output, the program will stop sending headers. Try looking at the requests and response inside Firebug.
In other case, try using non default options to the _redirect() method. For example, you can try:
$ropts = { 'exit' => true, 'prependBase' => false };
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto', $ropts);
There is another interesting option for the _redirect() method, the code option, you can send for example a HTTP 301 Moved Permanently code.
$ropts = { 'exit' => true, 'prependBase' => false, 'code' => 301 };
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto', $ropts);
I think I may have found the answer. It appears that Facebook does not play nice with redirect, so it is neccessary to use Facebook's 'fb:redirect' FBML. This appears to work:
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender();
echo '<fb:redirect url="' . $config->url->absolute->fb->canvas . '/turn/move-trains-auto"/>';