Undefined property - Symfony2 - php

I'm using Symfony2. My controller finds some values - like categories, created by the and gives them to the template. The problem is that if the user hasn't any created categories yet, I want to display a massage to invite him to create categories.
Here is the code:
if($number_of_categories == 0){
$newcommer = true;
//Here the template doesn't need any variables, because it only displays
// "Please first add some categories"
} else {
$newcommer = false;
//Here the variables, which I give to the template
//are filled with meaningfull values
}
return $this->render('AcmeBudgetTrackerBundle:Home:index.html.twig', array(
'newcommer' => $newcommer,
'expenses' => $expenses_for_current_month,
'first_category' => $first_category,
'sum_for_current_month' => $sum_for_current_month,
'budget_for_current_month' => $budget_for_current_month
));
The problem is that if the user doesn't have categories I don't have with what to fill the variables, so I have to write something like this:
//What I want to avoid is this:
$expenses_for_current_month = null;
$first_category = null;
$sum_for_current_month = null;
$budget_for_current_month = null;
just to avoid Notice: Undefined variable ...
Is there a cleaner solution to achieve this? There isn't a way to dynamically generate the count of variables, given to the template, is there? Thanks in advance!

Here a simple solution (if I understood your problem) :
$template = 'AcmeBudgetTrackerBundle:Home:index.html.twig';
if ($number_of_categories == 0){
//Here the template doesn't need any variables, because it only displays
// "Please first add some categories"
return $this->render($template, array(
'newcommer' => true,
));
} else {
//Here the variables, which I give to the template
//are filled with meaningfull values
return $this->render($template, array(
'newcommer' => false,
'expenses' => $expenses_for_current_month,
'first_category' => $first_category,
'sum_for_current_month' => $sum_for_current_month,
'budget_for_current_month' => $budget_for_current_month
));
}
And if you want a cleaner solution to manage your Template, you cna use the annotation #Template() (You just have to return an array to pass to the view) :
// ...
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class MyController extends Controller
{
/**
* #Route("/my_route.html")
* #Template("AcmeBudgetTrackerBundle:Home:index.html.twig")
*/
public function indexAction()
{
// ...
if ($number_of_categories == 0){
return array(
'newcommer' => true,
);
} else {
//Here the variables, which I give to the template
//are filled with meaningfull values
return array(
'newcommer' => false,
'expenses' => $expenses_for_current_month,
'first_category' => $first_category,
'sum_for_current_month' => $sum_for_current_month,
'budget_for_current_month' => $budget_for_current_month
);
}
}
}

Related

Yii Url Manager change integer parameter to equivalent string

Im trying to make url parameter string to it's integer equivalent
I want user/admins to route on index.php?r=user/admin&lvl=2, user/employees on index.php?r=user/admin&lvl=3 etc but it seems that it is not possible in yii?
I made the following rule but it's not working
'rules' => array(
'user/admins' => 'user/admin/<lvl:2>',
'user/employees' => 'user/admin/<lvl:3>'
);
I think this how I made it on CodeIgniter:
$route['user/admins'] = "user/admin/lvl/2";
$route['user/employees'] = "user/admin/lvl/3";
but I'm not sure in yii
I don't think that you can do that with the default rules provided by CUrlManager. But it's possible by using custom rules. For more information about their implementation see here.
In this case you should insert the following line in rules array in your config file:
array('class' => 'application.components.CustomRule'),
And you CustomRule file should look like:
class CustomRule extends CBaseUrlRule {
public function createUrl($manager, $route, $params, $ampersand) {
if ($route === 'user/admin') {
if ($params['lvl'] == 2) {
return 'user/admin';
} else if ($params['lvl'] == 3) {
return 'user/employees';
}
}
return FALSE;
}
public function parseUrl($manager, $request, $pathInfo, $rawPathInfo) {
if ('user/admins' == $pathInfo) {
$_GET['lvl'] = 2;
return 'user/admin';
} else if ('user/employees' == $pathInfo) {
$_GET['lvl'] = 3;
return 'user/admin';
}
return FALSE;
}
}
Variables are simply mapped after the action definition and separated with a slash:
'rules' => array(
'user/admins' => 'user/admin/lvl/2',
'user/employees' => 'user/admin/lvl/3'
);
You can now acces url user/admins which will be routed to user controller and action admin with a $_GET variable "lvl" and value 2. Note that the value then will be a string instead of an integer, but you can easily cast it.

Remove tags in field on form submit in cakephp

I want to perform strip_tags on a field called description before data is saved in the database during form submission. I thought of creating a custom rule and doing it over there:
'description' => array(
'stripTags' =>array(
'rule' => array('StripTags'),
'message' => ''
),
),
public function StripTags($user = array()) {
return !empty($user['description'])?strip_tags($user['description']):"";
}
However this doesn't work since cakephp expects true/false to be returned instead of an updated value. How should I do this?
Use the Model::beforeSave() callback, that's were all automatic pre-save data modification logic should go. It is invoked before save, but after validation.
Untested example:
public function beforeSave($options = array())
{
if(!parent::beforeSave($options))
{
return false;
}
if(!empty($this->data[$this->alias]['description']))
{
$this->data[$this->alias]['description'] = strip_tags($this->data[$this->alias]['description']);
}
return true;
}

Custom Widget doesn't display the same amount of choices

I try to create a customWidget with a special tablemethod to only display the pre selected choices of the user, this is the form :
$this->widgetSchema['Books_list'] = new MyWidgetFormThematicSelector(array(
'multiple' => true,
'model' => 'Books',
'table_method' => array('method' => 'getOnlySelected', 'parameters' => array($this->getObject()->getId())),
'expanded' => true,
));
this is the method getOnlySelected:
$q = Doctrine::getTable('BooksAuthors')
->createQuery('ba')
->select('ba.position,ba.name')
->leftJoin('ba.Books b')
->where('ba.BooksAuthors_id = ?', $id);
echo count($q); //return 4
return $q;
this method return 4 elements which is normal then if i try to echo the values of the getChoices method from the widget I get only 1 in return !?
class MyWidgetFormThematicSelector extends sfWidgetFormDoctrineChoiceWithParams {
public function configure($options = array(), $attributes = array())
{
parent::configure($options, $attributes);
}
public function getChoices() {
$choices = parent::getChoices();
echo count($choices); // return 1
return $choices;
}
public function render($name, $value = null, $attributes = array(), $errors = array()) {
return parent::render($name, $value, $attributes, $errors);
}
}
What's going on here ?
I create a similar widget in the same form where the probleme does not occurs, and it s quite the same code...
thx
I solve this problem by setting the attribute 'key_method' => 'myUniqueId', in the form where the widget is called...
Cause Ive got two primary keys in my table and the sfWidgetFormDoctrineChoiceWithParams widget use the one which was identic for all the results as the key for the array choices, so the size of the array was always one...By setting the other primary key as the main key of the getChoices method I get the correct result.

Saving data on GET request in CakePHP

I am building a simple mechanism where a user can like a post by clicking on a link. I'm using GET rather than POST as I want to allow the method to fire via the URL.
That been said how do I save data using GET? As the request data doesn't exist in this scenario... My model looks like:
class Like extends AppModel
{
public $name = 'Like';
public $belongsTo = array('User','Post');
}
and the method for adding looks like:
public function add( $id )
{
$post = $this->Post->find('first', array(
'conditions' => array('Post.id'=>Tiny::reverseTiny($id))
));
if (!$post)
{
throw new NotFoundException('404');
}
if($post['Post']['user_id'] == $this->Auth->user('id'))
{
$this->Session->setFlash('You can\'t like your own post... That\'s just silly!');
}
if ($this->Like->create())
{
$liked = $this->Like->find('first', array(
'conditions' => array('Like.id'=>Tiny::reverseTiny($id), 'Like.user_id'=>$this->Auth->user('id') )
));
if(!$liked){
$this->Like->saveField('user_id', $this->Auth->user('id'));
$this->Like->saveField('post_id', $post['Post']['id']);
$this->redirect(array('controller'=>'posts','action'=>'view','id'=>Tiny::toTiny($post['Post']['id']),'slug'=>$post['Post']['slug']));
} else {
$this->Session->setFlash('You already like this post!');
}
else
{
$this->Session->setFlash('Server broke!');
}
}
Can anyone help?
<?php echo $this->Html->link('1', array('controller'=>'followers','action'=>'add','id'=>Tiny::toTiny($post['Post']['id'])),
array('title'=>'Follow','class'=>'follow')); ?>
This part all works fine. It's saving a new row in the DB on GET that I'm struggling with.
Hi you just need to make a link to your controller action and pass you variable in the url.
to be clear the link on the post to like is in your post view :
$this->Html->link('like this post', array('controller' => 'like', 'action' => 'add', $postId))
It should render a link like this :
www.yourWebSite/likes/add/1 to like the postId 1,
variables after your action (add) are interpreted as variable for your controller action
if your fonction add had been
public function add($postId, $wathever){
}
the url should look like www.yourWebSite/likes/add/1/blabla
where 1 is the first var for the add action and blabla the second one and so on.
this is the equivalent of a non rewriting url : ?postId=1&whatever=blabla
EDIT :
if(!$liked){
//simulate the post behaviour
$this->request->data['Like']['user_id'] = $this->Auth->user('id');
$this->request->data['Like']['post_id'] = $post['Post']['id'];
//save the data
if ($this->Like->save($this->request->data)) {
$this->Session->setFlash(__('Thanks for your support !'));
$this->redirect(array('controller'=>'posts','action'=>'view','id'=>Tiny::toTiny($post['Post']['id']),'slug'=>$post['Post']['slug']));
} else {
$this->Session->setFlash('Server broke!');
}
}
How about using save with id=0 instead of create?
<?php
$like = array(
"Like" => array
(
"id" => 0,
"user_id" => $this->Auth->user("id"),
"post_id" => $post['Post']['id']
)
);
$result = $this->Like->save($like);
if(!$result){$this->Session->setFlash('Server broke!');}
$this->redirect(array('controller'=>'posts','action'=>'view','id'=>Tiny::toTiny($post['Post']['id']),'slug'=>$post['Post']['slug']));
?>

Require 1 of 2 arguments in a method / function (one of two arguments optional)

I have a method / function (in a class) that I am calling and I want to pass either and id or a url. The method then uses one of these arguments in a mysql WHERE query. It can only use one or the other.
How can I require one of two arguments? Or in other words how can I only make one of two arguments optional?
Is there a better way than to just make both arguments optional and use several if else statements?
If you want to literally require an argument:
public function fetchRow($where)
{
if (empty($where['id']) && empty($where['url'])) {
throw new Exception('WHERE clause must be supplied');
}
// proxy to specific method
if (!empty($where['id'])) {
return $this->fetchById((int) $where['id']);
} elseif (!empty($url)) {
return $this->fetchByUrl((string) $where['url']);
}
}
public function fetchById($id)
{
if ($stmt = $mysqli->prepare('SELECT * FROM table WHERE id = ?')) {
$stmt->bind_param('i', $id);
// ...
}
}
// ...
$object = new MyClass();
try {
$object->fetchRow(); // would throw exception
$object->fetchRow(array('id' => 10)); // would work
} catch (Exception $ex) {
// do something, for example:
echo $ex->getMessage(); // echoes 'at least one argument must be supplied'
}
In the end I used a very simple method which resulted in no code duplication and actually will allow for many more arguments to be passed in the future if needed without changes to the method.
public function getMovie($argType, $arg) {
$movieQuery = "SELECT
id, rt_id, imdb_id, url, rt_url, type, adult,
DATE_FORMAT(release_date, '%Y') AS year, date_added,
title, runtime, budget, revenue, homepage, rating,
tagline, overview, popularity, image, backdrop, trailer
FROM movies
WHERE " . $argType . " = ?";
$movieResult = $this->_query($movieQuery, $arg);
$movies = array();
if ($movieResult->fetch_array(MYSQLI_ASSOC)) {
while ($m = $movieResult->fetch_array(MYSQLI_ASSOC)) {
$movies[] = array(
'title' => $m['title'],
'duplicate' => $m['duplicate'],
'url' => $m['url'],
'rt_url' => $m['rt_url'],
'release_date' => $m['release_date'],
'date_added' => $m['date_added'],
'type' => 'movie',
'adult' => $m['adult'],
'id' => $id,
'rt_id' => $m['rt_id'],
'imdb_id' => $m['imdb_id'],
'rating' => $m['rating'],
'tagline' => $m['tagline'],
'overview' => $m['overview'],
'popularity' => $m['popularity'],
'runtime' => $m['runtime'],
'budget' => $m['budget'],
'revenue' => $m['revenue'],
'homepage' => $m['homepage'],
'image' => $m['image'],
'backdrop' => $m['backdrop'],
'trailer' => $m['trailer']
);
}
return $movies;
} else {
return false;
}
}
If it can only use one or the other, then you have state. If you have state, you need polymorphism, or in this very small use-case, two different methods.
public function getById($id) {}
public function getByUrl($url) {}
That's the end of it. That's the best you can do for yourself.
if and only if you don't know in advance which is being passed in, (like the case of user input), you can make a third method, to parse and validate the input string, determine which type it is, and call the appropriate method.

Categories