How to get a widget to run with multiple actions from typoscript? - widget

In creating a new uncached widget for login/logout/registering users in the Frontend, am unable to get it to work. How can I call two different controllers from typoscript (see code below)?
Am using TYPO3 9.5. Knowing how to create one is important because I'll need that info in creating many others for various uses. I have previously created a complex login system without widget/controller/action in TYPO3.
In ext_localconf.php, there is;
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
VendorName.ExtensionName,
PluginName,
[
'Frontend' => 'index',
'Account' => 'index,login,logout,register'
], [
'Account' => 'login,logout,register'
]);
Under folder structure Classes/Controller there is class VendorName\ExtensionName\Controller\AccountController which has;
class AccountController extends AbstractWidgetController {
/**
* #var array
*/
protected $supportedRequestTypes = [
Request::class,
WidgetRequest::class
];
public function initializeAction() {
}
public function indexAction() {
}
public function loginAction() {
return $this->view->assign('raw', 'Hello World');
}
public function logoutAction() {
}
public function registerAction() {
}
/**
* Handles a request. The result output is returned by altering the given response.
*
* #param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request object
* #param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, modified by this handler
*
* #return void
* #api
*/
public function processRequest(RequestInterface $request, ResponseInterface $response) {
#ActionController::processRequest($request, $response);
}
}
And in the ts file there is;
page = PAGE
page {
...
10 = USER
10 {
...
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
vendorName = VendorName
extensionName = ExtensionName
pluginName = PluginName
}
}
...
5 = USER_INT
5 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
vendorName = VendorName
extensionName = ExtensionName
pluginName = PluginName
controller = Account
action = login
}
When running this code, the PAGE ts produces the page using the Frontend controller index action which returns raw html through a fluid template. But when I add the USER_INT part, TYPO3 runs out of memory and displays a blank page.

Widgets are a type of ViewHelper used in Fluid templates. From what you describe, I think you want a plugin. Your Controller class needs to extend TYPO3\CMS\Extbase\Mvc\Controller\ActionController, not TYPO3\CMS\Fluid\ViewHelpers\Widget\Controller\AbstractWidgetController for that.

Related

Yii2 property mapping to tablename

I use Yii2 2.0.9 basic template and I try to set up my class.
I my class I use references of other classes in my property.
/**
*
*#property Contact contact
*/
class User extends ActiveRecord {
public static function tableName() {
return "user";
}
/**
* This is want I need
*/
public function databaseMapping(){
return [
"contact" => "contact_id"
];
}
}
Is there in Yii2 a solution for my problem?
Thanks Marvin Thör
In Grails I can write this:
class User {
Contact contact
Boolean passwordExpired
static mapping = {
contact(column: 'contact_id')
passwordExpired(column: 'password_expired')
}
}
User user = new User();
user.passwordExpired = true
user.contact = new Contact();
and I want the same
You might want to use the method attributeLabels() inside your model class to define label names to show to the end user.
public function attributeLabels() {
return [
'contact_id' => 'Contact',
];
}
However, there are times like when creating a RESTful API using Yii2 that you need to return a json with fields with specific field names. For these ocasions, you can use the fields() method:
public function fields() {
return [
'contact' => 'contact_id',
];
}
This method returns the list of fields that should be returned by default by toArray(). You can check more about it HERE.
Change your labels and db column remain unchanged.
public function attributeLabels()
{
return [
'contact_id' => Yii::t('app', 'Use your name here'),
];
}

Making a Zend Framework 3 MVC app return a simple string

I have a ZF MVC app I created with composer create-project -sdev zendframework/skeleton-application my-application
I made a controller like the following.
class SomeController extends AbstractRestfulController
{
public function someAction()
{
$key = $this->params()->fromQuery('key');
if (empty($key)) {
$this->response->setStatusCode(Response::STATUS_CODE_400);
return new JsonModel([
'status'=> 'Error',
'messages'=> [
'key required'
],
]);
}
return $this->someService->getStringByKey($key));
}
}
I want it to return a content type of text/plain with a body of the results of SomeService::getStringByKey($key). Instead I get the error:
Zend\View\Renderer\PhpRenderer::render: Unable to render template "XXXXXXXXXX"; resolver could not resolve to a file
`
How do I make the controller actions just return plain strings?
Well, you are very close :)
class SomeController extends AbstractRestfulController
{
/**
* #return \Zend\Http\PhpEnvironment\Response
*/
public function someAction()
{
$string = $this->someService->getStringByKey($key));
$this->response->getHeaders()->addHeaderLine('Content-Type: text/plain');
return $this->response->setContent($string);
}
}

Restricting controller action to creator of post in Yii2

Is there an easy way to restrict a controller action to the owner/creator of the post without using full blown RBAC?
Right now I'm doing this for every controller:
public function actionUpdate( $id ) {
$model = $this->findModel( $id );
if ( $model->user_id != Yii::$app->user->identity->id ) {
throw new NotFoundHttpException( 'The requested page does not exist.' );
}
}
But I think there must be a better way to restrict certain controllers to the users who created the $model thats being edited.
1) The recommended way is to use RBAC and rules. It's covered well in official docs in according dedicated section.
Example of rule that checks if author id matches current user id passed via params:
namespace app\rbac;
use yii\rbac\Rule;
/**
* Checks if authorID matches user passed via params
*/
class AuthorRule extends Rule
{
public $name = 'isAuthor';
/**
* #param string|integer $user the user ID.
* #param Item $item the role or permission that this rule is associated with
* #param array $params parameters passed to ManagerInterface::checkAccess().
* #return boolean a value indicating whether the rule permits the role or permission it is associated with.
*/
public function execute($user, $item, $params)
{
return isset($params['post']) ? $params['post']->createdBy == $user : false;
}
}
Then you need to tie it with existing permission (can be done in migration or with extensions):
$auth = Yii::$app->authManager;
// add the rule
$rule = new \app\rbac\AuthorRule;
$auth->add($rule);
// add the "updateOwnPost" permission and associate the rule with it.
$updateOwnPost = $auth->createPermission('updateOwnPost');
$updateOwnPost->description = 'Update own post';
$updateOwnPost->ruleName = $rule->name;
$auth->add($updateOwnPost);
// "updateOwnPost" will be used from "updatePost"
$auth->addChild($updateOwnPost, $updatePost);
// allow "author" to update their own posts
$auth->addChild($author, $updateOwnPost);
Then you can check if you user can update post like this:
use yii\web\ForbiddenHttpException;
use Yii;
public function actionUpdate($id)
{
$model = $this->findModel($id);
if (!Yii::$app->user->can('updatePost', ['post' => $model])) {
throw new ForbiddenHttpException('You are not allowed to edit this post');
}
...
}
Also note that in case you found model first and user has no access to edit it, logically it's better to throw 403 Forbidden exception rather than 404, since it's found, but not allowed for editing.
Don't forget to include rule like that in AccessControl behavior:
[
'allow' => true,
'actions' => ['update'],
'roles' => ['#'],
],
It means that update action of this controller can be only accessed by authorized users excluding guests.
2) If for some reason you don't want to use RBAC, you can use your approach:
use yii\web\ForbiddenHttpException;
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->user_id != Yii::$app->user->id ) {
throw new ForbiddenHttpException('You are not allowed to edit this post.');
}
...
}
To improve this you can abstract from this check by moving this logic to helper method:
namespace app\posts\components;
use Yii;
class PostPermission
{
/**
* #param $model Post
* #return boolean
*/
public static function allowedToUpdate($model)
{
return $model->user_id = Yii:$app->user->id;
}
}
Then call it like that:
use app\posts\components\PostPermission;
use yii\web\ForbiddenHttpException;
if (!PostPermission::allowedToUpdate($model) {
throw new ForbiddenHttpException('You are not allowed to edit this post.');
}
It's just an example, method doesn't have to be static, you can construct instance using $model.
You can just directly create method in Post model, but it's better to not pollute model with such logic.
3) Another alternative that I can advise is to restrict scope initially to current user when finding model:
use yii\web\NotFoundHttpException;
/**
* #param integer $id
* #return Post
* #throws NotFoundHttpException
*/
protected function findModel($id)
{
$model = Post::find(['id'=> $id, 'user_id' => Yii::$app->user->id])->one();
if ($model) {
return $model;
} else {
throw new NotFoundHttpException('This post does not exist.');
}
}
This can be improved for site administrators:
use yii\web\NotFoundHttpException;
/**
* #param integer $id
* #return Post
* #throws NotFoundHttpException
*/
protected function findModel($id)
{
$query = Post::find()->where(['id' => $id]);
if (!Yii::$app->user->is_admin) { // replace with your own check
$query->andWhere(['user_id' => Yii::$app->user->id]);
}
$model = $query->one();
if ($model) {
return $model;
} else {
throw new NotFoundHttpException('This post does not exist.');
}
}
Then you only write:
public function actionUpdate($id)
{
$model = $this->findModel($id);
...
}
That way in both cases (model not found and not allowed for editing by current user), 404 Not Found exception will be raised. From other side, nothing is wrong with that, because technically for this user this model does not exist (since he is not author of it).
We can use
AccessControlFilter
for restricting controller action instead of RBAC. This below code will give access to the actionUpdate if it is only pass the denyCallback.
use yii\filters\AccessControl;
class SiteController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['update','delete'],
'rules' => [
[
'actions' => ['update'],
'allow' => false,
'denyCallback' => function ($rule, $action) { //PHP callable that should be called when this rule will deny the access.
//Write your logic here to deny the action
throw new \Exception('You are not allowed to access this page');
}
],
],
],
];
}
public function actionUpdate()
{
return $this->render('update');
}
}
For your reference https://github.com/yiisoft/yii2/blob/master/docs/guide/security-authorization.md

PHPStorm generate phpdoc

I have method like this:
public function connect (Application $app)
{
$controller = $app['controllers_factory'];
$controller->get('/login', function () {
return 'test';
});
return $controller;
}
Everything works fine, but I would like to save $app in private field, like this
private $app;
public function connect (Application $app)
{
$this->app = $app;
$controller = $this->app['controllers_factory'];
$controller->get('/login', function () {
return 'test';
});
return $controller;
}
In this case PHPStrom throws error "method get not found in class". I tried phpdoc but it didn't work (As you see i use SILEX micro-framework)
The autocomplete gets stuck at this step, because it's unclear whats the value coming from array (even if it's an object that acts like an array).
$controller = $this->app['controllers_factory'];
There are two possibilities. First, if you have an array that consist of elements that share a single type, you can specify the type like this:
/**
* #var Application[]
*/
private $app;
An alternate method is to specify the type of a variable inline:
/** #var Application $controller */
$controller = $this->app['controllers_factory'];
Both options are supported by PHPStorm.

Zend Framework 1.9.2+ Zend_Rest_Route Examples

With the introduction of Zend_Rest_Route in Zend Framework 1.9 (and its update in 1.9.2) we now have a standardized RESTful solution for routing requests. As of August 2009 there are no examples of its usage, only the basic documentation found in the reference guide.
While it is perhaps far more simple than I assume, I was hoping those more competent than I might provide some examples illustrating the use of the Zend_Rest_Controller in a scenario where:
Some controllers (such as indexController.php) operate normally
Others operate as rest-based services (returning json)
It appears the JSON Action Helper now fully automates and optimizes the json response to a request, making its use along with Zend_Rest_Route an ideal combination.
Appears it was rather simple. I've put together a Restful Controller template using the Zend_Rest_Controller Abstract. Simply replace the no_results return values with a native php object containing the data you want returned. Comments welcome.
<?php
/**
* Restful Controller
*
* #copyright Copyright (c) 2009 ? (http://www.?.com)
*/
class RestfulController extends Zend_Rest_Controller
{
public function init()
{
$config = Zend_Registry::get('config');
$this->db = Zend_Db::factory($config->resources->db);
$this->no_results = array('status' => 'NO_RESULTS');
}
/**
* List
*
* The index action handles index/list requests; it responds with a
* list of the requested resources.
*
* #return json
*/
public function indexAction()
{
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
// 1.9.2 fix
public function listAction() { return $this->_forward('index'); }
/**
* View
*
* The get action handles GET requests and receives an 'id' parameter; it
* responds with the server resource state of the resource identified
* by the 'id' value.
*
* #param integer $id
* #return json
*/
public function getAction()
{
$id = $this->_getParam('id', 0);
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
/**
* Create
*
* The post action handles POST requests; it accepts and digests a
* POSTed resource representation and persists the resource state.
*
* #param integer $id
* #return json
*/
public function postAction()
{
$id = $this->_getParam('id', 0);
$my = $this->_getAllParams();
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
/**
* Update
*
* The put action handles PUT requests and receives an 'id' parameter; it
* updates the server resource state of the resource identified by
* the 'id' value.
*
* #param integer $id
* #return json
*/
public function putAction()
{
$id = $this->_getParam('id', 0);
$my = $this->_getAllParams();
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
/**
* Delete
*
* The delete action handles DELETE requests and receives an 'id'
* parameter; it updates the server resource state of the resource
* identified by the 'id' value.
*
* #param integer $id
* #return json
*/
public function deleteAction()
{
$id = $this->_getParam('id', 0);
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
}
great post, but I would have thought the Zend_Rest_Controller would route the request to the right action with respect to the HTTP method used. It'd be neat if a POST request to http://<app URL>/Restful would automatically _forward to postAction for example.
I'll go ahead and provide another strategy below, but maybe I'm missing the point behind Zend_Rest_Controller ... please comment.
My strategy:
class RestfulController extends Zend_Rest_Controller
{
public function init()
{
$this->_helper->viewRenderer->setNoRender();
$this->_helper->layout->disableLayout();
}
public function indexAction()
{
if($this->getRequest()->getMethod() === 'POST')
{return $this->_forward('post');}
if($this->getRequest()->getMethod() === 'GET')
{return $this->_forward('get');}
if($this->getRequest()->getMethod() === 'PUT')
{return $this->_forward('put');}
if($this->getRequest()->getMethod() === 'DELETE')
{return $this->_forward('delete');}
$this->_helper->json($listMyCustomObjects);
}
// 1.9.2 fix
public function listAction() { return $this->_forward('index'); }
[the rest of the code with action functions]