Styling/Theming Drupal 7 Content Type Record - drupal-7

I developed a Content type of "Car Sales" with following fields:
Manufacturer
Model
Make
Fuel Type
Transmission (Manual/Automatic)
Color
Registered? (Yes/No)
Mileage
Engine Power
Condition (New/Reconditioned/Used)
Price
Pictures (Multiple uploads)
I have developed View of this Content Type to display list of cars. Now I want to develop a screen/view for individual Car Sale Record like this:
Apart from arranging fields, please note that I want to embed a Picture Gallery in between. Can this be achieved through Drupal 7 Admin UI or do I need to create custom CSS and template files? If I need to edit certain template files/css, what are those? I'm using Zen Sub Theme.

I would accomplish this by creating a page, and then creating a node template to accompany it. Start by creating a new node, and then record the NID for the name of the template.
Then, in your template, create a new file, and name it in the following manner: node--[node id].tpl.php
Then, in that file, paste in the following helper function (or you can put it in template.php if you're going to use it elsewhere in your site):
/**
* Gets the resulting output of a view as an array of rows,
* each containing the rendered fields of the view
*/
function views_get_rendered_fields($name, $display_id = NULL) {
$args = func_get_args();
array_shift($args); // remove $name
if (count($args)) {
array_shift($args); // remove $display_id
}
$view = views_get_view($name);
if (is_object($view)) {
if (is_array($args)) {
$view->set_arguments($args);
}
if (is_string($display_id)) {
$view->set_display($display_id);
}
else {
$view->init_display();
}
$view->pre_execute();
$view->execute();
$view->render();
//dd($view->style_plugin);
return $view->style_plugin->rendered_fields;
} else {
return array();
}
}
Then add the following code to your template:
<?php
$cars = views_get_rendered_fields('view name', 'default', [...any arguments to be passed to the view]);
foreach ($cars as $car): ?>
<div>Put your mockup in here. It might be helpful to run <?php die('<pre>'.print_r($car, 1).'</pre>'); ?> to see what the $car array looks like.</div>
<?php endforeach;
?>
Just change the placeholders in the code to whatever you want the markup to be, and you should be set!
As I mentioned above, it's always helpful to do <?php die('<pre>'.print_r($car,1).'</pre>'); ?> to have a visual representation of what the array looks like printed.
I use views_get_rendered_fields all the time in my code because it allows me to completely customize the output of the view.
As a Reminder: Always clear your caches every time you create a new template.
Best of luck!

Related

View link if depended on user rights

I am working with CakePhp 2.x. I have three Columns:
User | Course | UserCourseRole
Each user can edit multiple courses and one course can be edited by multiple users. So far so good.
If a user wants to see an index of all the courses i want to show a 'edit'-link only next to the courses which he can in fact edit.
How can i realize this? I figured i would have to set some sort of extra field inside the CourseController and check for this field inside the view. Is this the right way to go?
My current Code is
CourseController.php
...
public function index() {
$courses = $this->Course->find('all', array('recursive' => 2));
$this->set('courses', $courses);
}
...
Courses/index.ctp
<!-- File: /app/View/Courses/index.ctp -->
...
<?php foreach ($courses as $course):?>
...
<?php
echo $this->Html->link('edit', array('action' => 'edit', $course['Course']['id']));
?>
...
In beforeRender() or beforeFilter() set $this->Auth->user() as a variable to the view, for example as userData.
$this->set('userData', $this->Auth->user());
Implement a (auth)helper that uses that variable (you can make it configurable as a helper setting) and do your checks like:
if ($this->Auth->hasRole($course['Course']['role']) { /* ... */ }
if ($this->Auth->isLoggedIn() { /* ... */ }
if ($this->Auth->isMe($course['Course']['user_id']) { /* ... */ }
Implement the hasRole() method according to whatever your specific requirements are.
Doing this as helper as a bunch of advantages, it is easy to reuse, overload and adapt to whatever your checks are and you don't use a component in a view plus that you should avoid calling statics and singletons a lot in your app. Also it is pretty easy to read and understand what the code does.
I think the good idea is set some variable or constans after logged (if user has privileges) and uses if statement for check.
if($allow === true) {
echo $html->link('Edit',...
}
or use AuthComponent::user() in Views.
This idea it's not good if we can many kind of admins (admin, moderator, reviewier, etc.)
Maybe someone will have a better solution

Agile Toolkit manipulating Grid column content

Just started using ATK4 and appreciating it very much so far, but not sure how to do this...
What I am trying to accomplish:
I am outputting a query's results to a grid, one of the fields is 'status', the data will either be '-1' or '1'.
Instead of outputting -1 or 1 to the column, how do I output an HTML snippet (or whatever I need to to get what I want) instead that shows a different icon for each value?
In short:
In column 'status':
if the value is -1, display iconDown.gif;
if the value is 1, display iconUp.gif
Code so far:
class page_showlist extends Page {
function init(){
parent::init();
$q=$this->api->db->dsql();
$q->table('remote_system')
->join('customers.id','customer_id')
->field('customer_id')
->field('ip')
->field('nickname')
->field('name','customers')
->field('status')
;
$grid = $this->add('Grid');
$grid->addColumn('text','status')->makeSortable();
$grid->addColumn('text','name')->makeSortable();
$grid->addColumn('text','ip');
$grid->addColumn('text','nickname');
$grid->addButton('Reload Grid')->js('click',$grid->js()->reload());
$grid->addQuickSearch(array('name'));
$grid->setSource( $q );
}
}
Any pointers/tips?
To add column with icons in Grid you can use custom template.
In one of my projects I do like this:
$url = $this->api->pm->base_url . $this->api->locateURL('template', 'images/');
$grid->addColumn('template', 'type', false)
->setTemplate('<img src="' . $url . 'icon_object_<?$type?>.png">');
It'll use model field named type (in your case use status) and show icons in that column. Icon source URL is generated dynamically and it'll search for image files in your template/images directory named icon_object_XXX.png where XXX value will be taken from field type value.
In my case type is like this: array('building','apartment','land','garage') etc.
And one more thing - you should start using Models whenever possible! That way you'll ease your life later when your project becomes bigger. Also can have extra security (conditions, etc.) with them.

Multiple models and uploading files

At first - I'm new to the Yii Framework. I did some research on my own but I couldn't find a precise solution to my issue.
Assume there are two related models - Product and Image. A single Product may have multiple Images assigned. What is the best approach at creating the create / update forms that would be able to manage this kind of scheme?
The Image model consists of various fields, along with a path to the image file, so it's not just a "container" for the path itself. What's more - I need to have a thumbnail generated for every uploaded image and its path stored within the same model.
What I need to achieve is pretty much similar to the admin inline functionality known from Django - there should be a section in the Product create / update form which would allow users to add / modify / delete Images.
I tried the multimodelform extension but I couldn't get file uploading to work. What's the best way of getting it done and not having to build the whole file-upload-enabled-multiple-model-form structure manually?
The detailed solution depends on if you are using CActiveForm or CHtml form. Since you have 2 related models I assume you are using CActiveForm and will point out some thing you need to keep in mind.
For this example i am gonna assume some definitions
Product with fields id, name
Product with ONE to MANY relation to 'images' on ProductImage
ProductImage with fields id, productId, path
I also assume there gonna be 1 upload / edit, but multi delete
Here's the view:
$form = $this->beginWidget(
'CActiveForm',
array(
'id' => 'upload-form',
'enableAjaxValidation' => false,
'htmlOptions' => array('enctype' => 'multipart/form-data'),
)
);
echo $form->labelEx($product, 'name');
echo $form->fileField($product, 'name');
echo $form->error($product, 'name');
echo $form->checkBoxList($product, 'path', $product->images);
echo $form->labelEx($productImage, 'path');
echo $form->fileField($productImage, 'path');
echo $form->error($productImage, 'path');
$this->endWidget();
And your action
public function actionUpdate($productId) {
$product = Product::model()->findByPk($productId)->with('images');
$productImage = new ProductImage();
if(isset($_POST['Item']))
{
$product->attributes=$_POST['Product'];
foreach($product->images as $im) {
if(in_array($im->path, $_POST['Item']['Image']))
$im->delete();
}
$productImage->image=CUploadedFile::getInstance($productImage,'path');
if($productImage->save())
{
$productImage->image->saveAs('some/new/path');
// redirect to success page
}
}
$this->render('update', array(
'product'=>$product,
'productImage'=>$productImage,
));
}
Now note that this solution is not tested so there will be bugs, but it should give you an idea on how to write your own form.
Resources:
http://www.yiiframework.com/wiki/2/how-to-upload-a-file-using-a-model/
http://www.yiiframework.com/wiki/384/creating-and-updating-model-and-its-related-models-in-one-form-inc-image

Using existing field name as different name

i have existing website.
and i write the new back-end (in cakephp) without changing front-end programm
the discomfort that
db table has field names as
id
news_date
news_title
news_content
is it possiable to do something in cakephp model file (reindentify the field names)
so i can use model in controller as
News.date
News.title
News.content
What you need to do is setup some very basic virtual fields in your news model. Something like this should suit your needs.
public $virtualFields = array(
'title' => 'news_title',
'date' => 'news_date',
'content' => 'news_content'
);
Also do yourself a favour by checking out the other model attributes that could help you out, you'll want to set displayType as new_title I'd imagine.
Is said by Dunhamzz, virtualFields are a good solution until you want to work with these new field-names.
Since I assume your frontend needs to use the old names from the database I would go with the afterFind-callback in your model.
Let's say you've got the model news.php:
# /app/model/news.php
function afterFind($results) {
foreach ($results as $key => $val) {
if (isset($val['News']['title'])) {
$results[$key]['News']['news_title'] = $val['News']['title']);
# unset($results[$key]['News']['title']); //use this if you don't want the "new" fields in your array
}
if (isset($val['News']['date'])) {
$results[$key]['News']['news_date'] = $val['News']['date']);
# unset($results[$key]['News']['date']); //use this if you don't want the "new" fields in your array
}
if (isset($val['News']['content'])) {
$results[$key]['News']['news_content'] = $val['News']['content']);
# unset($results[$key]['News']['content']); //use this if you don't want the "new" fields in your array
}
}
return $results;
}
You need to rename the database-fields to your new wanted value. You then can use these within conditions like every other field.
Only difference is, that you get back an array where all your fields have been renamed to your frontend-fields.
For more information about the available callback-methods have a look here: Callback Methods

How to reduce form code duplication in CakePHP

I have a form in CakePHP with a few dozen fields in it. From all the examples I have seen, there is duplicate form code for an add view and an edit view.
Is there any tricks to keep the duplication out? What is best method in CakePHP for this?
What I do, is to put all form fields in an element, and then insert the element in the add.ctp and edit.ctp
Don't forget to add the hidden field with the id in the edit.ctp
This way all visible elements are in one file, easier to maintain.
View/MyModel/add.ctp
echo $this->Form->create('MyModel');
echo $this->element('my_form');
echo $this->Form->end();
View/MyModel/edit.ctp
echo $this->Form->create('MyModel');
echo $this->Form->input('id');
echo $this->element('my_form');
echo $this->Form->end();
View/Elements/my_form.ctp
// your form inputs
// whatever they are
You should NOT merge those views, because add/edit are different actions and deserve separate view files. As your application grows you will realize that its good to have separate views to reduce complexity of if else conditions.
If you still want to avoid the separate files, Use
function add() {
.....
$this->render('edit')
}
I've done this before, but reverted back to having separate views, mainly for my own sanity.
It's easy enough to do. The edit requires an input for the record id. This is usually hidden. Any default form values for the add form will have to be contained in conditionals so that the stored values are not overwritten with defaults when you are editing a record
On the controller side of things, you'll need a conditional statement to decide whether to act as an add or edit depending on whether the $this->data['MyModel']['id'] is set.
I think that covers it - if I think of anything else I'll add it in.
My work pattern tends to be to build the edit view, then copy and paste to create the basis for the add view.
this code will check if you have admin_form.ctp or form.ctp which will make it use the same code for add / edit
https://github.com/infinitas/infinitas/blob/dev/app_controller.php#L389
1.3 submits the forms automatically to where the are from so when you go to /edit/1 it will post to there, and /add will post to add.
that is all you need to do. if you have a edit that is vastly different to the add, then you just create the 2 files. when you want them the same, just make the one.
in your app controller
public function render($view = null, $layout = null) {
$viewPaths = App::path('View', $this->plugin);
$rootPath = $viewPaths[0] . DS . $this->viewPath . DS;
$requested = $rootPath . $view . '.ctp';
if (in_array($this->request->action, array('admin_edit', 'admin_add', 'edit', 'add'))) {
$viewPath = $rootPath . $this->request->action . '.ctp';
if (!file_exists($requested) && !file_exists($viewPath)) {
if (strpos($this->request->action, 'admin_') === false) {
$view = 'form';
} else {
$view = 'admin_form';
}
}
}
return parent::render($view, $layout);
}
and in your view you can always check whether its edit or add
if ($this->request->params['action'] == 'admin_edit') {
//do something
}
if ($this->request->params['action'] == 'admin_add') {
//do something
}
in edit.ctp
if($this->data[ModelName]['id']) {
$this->Form->input('id');
}
// create rest of the fields
in Controller::add()
$this->autoRender=false; // at the start of function
$this->render('edit.ctp'); // at the point where you actually want to render
no need to create add.ctp

Resources