Adding interactions to admin pages generated by the admin generator - php

I am using Symfony 1.2.9 (with Propel ORM) to create a website. I have started using the admin generator to implement the admin functionality.
I have come accross a slight 'problem' however. My models are related (e.g. one table may have several 1:N relations and N:N relations). I have not found a way to address this satisfactorily yet. As a tactical solution (for list views), I have decided to simply show the parent object, and then add interactions to show the related objects.
I'll use a Blog model to illustrate this.
Here are the relationships for a blog model:
N:M relationship with Blogroll (models a blog roll)
1:N relationship with Blogpost (models a post submitted to a blog)
I had originally intended on displaying the (paged) blogpost list for a blog,, when it was selected, using AJAX, but I am struggling enough with the admin generator as it is, so I have shelved that idea - unless someone is kind enough to shed some light on how to do this.
Instead, what I am now doing (as a tactical/interim soln), is I have added interactions to the list view which allow a user to:
View a list of the blog roll for the
blog on that row
View a list of the posts for the blog on that row
Add a post for the blog on tha row
In all of the above, I have written actions that will basically forward the request to the approriate action (admin generated). However, I need to pass some parameters (like the blog id etc), so that the correct blog roll or blog post list etc is returned.
I am sure there is a better way of doing what I want to do, but in case there isn't here are my questions:
How may I obtain the object that relates to a specific row (of the
clicked link) in the list view (e.g. the blog object in this example)
Once I have the object, I may choose to extract various fields: id etc.
How can I pass these arguments to the admin generated action ?
Regarding the second question, my guess is that this may be the way to do it (I may be wrong)
public function executeMyAddedBlogRollInteractionLink(sfWebRequest $request)
{
// get the object *somehow* (I'm guessing this may work)
$object = $this->getRoute()->getObject();
// retrieve the required parameters from the object, and build a query string
$query_str=$object->getId();
//forward the request to the generated code (action to display blogroll list in this case)
$this->forward('backendmodulename',"getblogrolllistaction?params=$query_string");
}
This feels like a bit of a hack, but I'm not sure how else to go about it. I'm also not to keen on sending params (which may include user_id etc via a GET, even a POST is not that much safer, since it is fairly sraightforward to see what requests a browser is making). if there is a better way than what I suggest above to implement this kind of administration that is required for objects with 1 or more M:N relationships, I will be very glad to hear the "recommended" way of going about it.
I remember reading about marking certain actions as internal. i.e. callable from only within the app. I wonder if that would be useful in this instance?

I'm assuming your application is called backend. Suppose there are two models, BlogPost and BlogPostComment. These are managed using admin generated modules called blog_post and blog_post_comment.
I believe you want a link against each BlogPost displayed on the list page at backend.php/blog_post. The links take you to backend.php/blog_post_comment, which should only show comments related to the relevant BlogPost.
Under apps/backend/blog_post/templates, create a file called _commentslink.php and put this in it:
View Comments
Then in apps/backend/blog_post/config/generator.yml, you need to include this partial in the fields for the list view:
....
param:
config:
list:
display: [ id, title, _commentslink ]
Note the _commentslink - the _ tells it to use a partial instead of looking for the field in the model. Your object is available in this partial as $<name of model> - $blog_post in this case.
Essentially, all this method does is links to the same action as the filter on the comments list normally goes to, passing the relevant condition to it to make it filter by blogpost_id.
If you've got CSRF protection enabled in the backend, you'll need to disable it, or this method won't work. This is set in apps/backend/config/settings.yml. There will be a setting in there called csrf_secret - it should be set to false to disable csrf.
You should try symfony 1.3/1.4 out if you need support for 1:N relationships in forms. 1.3 is in my experience a relatively hassle free upgrade from 1.2.x - 1.4 is the same, but with deprecated features removed.

Related

Doctrine / ExtJS: Use model to create another model

I'm having difficulties implementing some of the features my client would like to have.
We're building a shopware shop, which is almost done. I've developed some plugins and customizations to have the shop fit my client, but I'm not the best at backend development using ExtJS and Doctrine.
The situation is: The shop sells car parts. We've bought a third-party plugin that allows us to enter ktype numbers for each product, so that the client can search for his/her car in the frontend and get all fitting products.
The plugin has it's own window in the backend, which isn't very comfortable.
So I created an extra tab in the article details, which displays all entries from the database using the third-party model.
That wasn't so hard since the model and database were created by the third-party plugin and I just had to query the data and display it.
What I'm trying to accomplish is: I added an extra column (selected) with a checkbox, where the admin can choose the cars the article fits to.
The plan was to read the textfield "ktypes" of the article on load, check all corresponding checkboxes and then when a checkbox is altered just save the new ktypes array to the article.
Problem is, that this way I can't sort by that column since it's not in the ExtJS store/model.
So now I'm thinking I'll create my own Model with all the columns from the third-party model, add a article_id column and a selected column and reference everything there.
What I don't know is: How to I get the contents of the third-party model into my own database?
The third-party plugin doesn't reference the article. The table only holds all car data imported from a csv list. The reference between an article and the data is just a textfield in the article details.
I thought about Doctrine associations, but I don't really have a reference point or foreign key...
Has anyone got an idea how to solve this?
Can share code if that helps...
Thanks!
I went in a different direction but still need help. Will post a new question though since it's a different topic.
Thanks for trying to help!

Render custom list of related entities as form using SonataAdmin bundle

I am using Sonata Admin bundle in my Symfony app with doctrine. Now I am facing to some specific requirement whose solution or good/best practice I could not find anywhere.
To explain my issue I will use three simple entities as below.
So every news can have title and description different for every language.
Now what I need. In form view (detail) of news I want to:
have inputs of news attributes. (like code or created_date in this case)
then I want to see titles and descriptions for all languages related to current news. And in case, that news has not translation for some language, it means that there is no relation in News_Translation, I want to see empty inputs.
So everything in one view (maybe split it into more tabs). And here is a simple example of news detail (form view) for better understanding
Is it possible to attain something like this? I am open to any other ideas how to solve it using sonata-admin.
KunstmaanTranslatorBundle is a bundle which enables editing translations in the admin interface without need for editing the translations files. Translations will be stored in a (default) database and retrieved on the most efficient way possible.
KunstmaanTranslatorBundle
Doc

Structuring classes and objects in CodeIgniter for future upgrades?

I'm new to Codeigniter and pretty new to OOP as of the last month or so. I've been playing around and have been trying to make a blog page with a list of 10 posts and have different functions and possibilities for each.
For example, in the future I want to be able to show different buttons below posts depending on whether they are a logged in user, or if they are the post creator, etc.
Would I be best off making a new class 'blog_posts' and making an instance of it for every post I show on the page? like:
$this->load->library('blog_posts'); // in library or models, I'm not too sure?
$new_inst = new blog_posts;
$new_inst->show_post();
My end goal is to get it all as easily updated, changed, or modified in future if needed, I've seen simple tutorials online:
http://blog.pisyek.com/2011/03/create-a-simple-blog-using-codeigniter-2-0-part-1/
But I can't see them being easily updated and modified in future. I haven't seen a lot of other CI apps using new instances of classes, so I'm thinking there may be a different way in CI? Are new instances used in CI a lot?
Start with the controller. With Codeigniter -- anything you can do in a model, you can do in the controller. The easiest way to start -- just put your methods in the controller and set up a simple view file.
Always do a simple sanity check to make sure the basics are proper. Set up a controller and echo out some text.
In the controller try:
Get blog posts from your database using active record commands
Pass the blog posts result to $Data
With each step, Echo out something in the controller to confirm that its working
Next -- try using $Data to pass the blog results to the view.
After its working and you understand the basics -- then start pushing your methods to a Model. As you refactor and clean, your controller will get 'thinner'.
typically for blog posts you would have one model, that would return the blog posts and might also have your insert / update / delete methods. i say might because it usually makes more sense to have a public blog controller, that just shows blog posts. and then a separate blog admin controller -- that is only available to users who are logged in.
These two controllers - can share the same blog model. So for example to show blog posts on an admin screen - you could use the same method as showing the posts on a public page. Whereas you might have an admin blog model -- which has the create / update / delete methods.
That way you enforce a very clear separation of User Roles from the start -- people who are viewing the public blog should not be able to delete posts. The public show blog class is not "responsible" for editing.
This is something that i'm grappling with -- like the normal way to demonstrate a blog is to have all the methods together. Which makes sense in terms of "what can we do with a blog post" -- but it doesn't make any sense in terms of user roles.
ok Next - work on your create and update and delete methods.
Next try creating your log in methods. Make the Login process separate controller / model / view.
Eventually you could have one method call in the constructor of your blog admin class that checks to make sure that the user is logged in - otherwise it redirects them to a login page. That way you dont have to check over and over again in the view files etc to make sure they are authorized.
( highly recommend the free codeigniter tutorial series on net tuts website )
more rambling:
looking at the process from the point of view of the actor (user,role) -- for me helps to clarify what the chain of control should be. really critical roles - like an admin that has the power to delete all blog posts - the system should know that role at the top of the class.
best 'worst example' is when there are "is this a super admin?" checks in the view code. the view should not know anything about admin roles. BUT MUCH WORSE when you put a reference to an admin role in some view file -- what happens when you want to change that admin role in some way? now you have to go into all your view files!
class and method names - i'm moving towards not revealing any business or crud or field or any other type of business information in the URL. no nouns no verbs no ids. as simple as possible, with very few public url 'doors' into the app.
whats wonderful is that codeigniter makes it really easy to make your methods private. for critical pages: only use the public index method in the class for redirecting and make all other methods private.
use routes that directly to private methods. or public methods with broad names, that if successful -- like you have confirmed their credentials - go to private methods in the class like $this->_showAdminPage()
this is where defining a role like - blog editor - makes things very clear from a functionality point of view, AND keeps the valuable business knowledge private.

Symfony 1.3: Need to override backend filter field's set of data

My project is using Symfony 1.3.11, PHP version is 5.3.3.
Let me explain my case and my problem:
We wanted to add another kind of user, not just "user" and "admin" (using sfGuardPlugin). I did add "business" and I did give him permissions to only ONE admin module -- "purchases" (accessing own and under some conditions -- other people's purchases made on the site).
The "business" user can be associated to one or more Partners (firms) registered in the site, effectively allowing us to handle business owners or representatives a wee bit differently.
When the "business" user accesses the admin section, the list of purchases he sees must be this: All Purchases for all Products of all Partners he has associated with him. (Not exactly a trivial query).
I did that, in my opinion, in a stupid manner, but it does work -- namely overriding the "apps/backend/modules/purchase/actions/actions.class.php#executeIndex". I had to first copy-paste some code from the version of that method in the cache.
In short, I did hook myself to the "executeIndex" and added a code to do the proper Criteria, and the code works.
The problem now is this:
The filter field above the list (the one containing the Product list) does contain all possible Products. We want it to only contain all Products for all Partners the current user is associated with.
Thing is, it's my first time having to override the admin's filters and I am lost as to where should I plug my code.
Any help is appreciated. Thanks for your time.
UPDATE: Strangely very unpopular question. Nobody ever had to do this? Wow.
You have to unset the product_list and set another widget with the filtered choices.
Check this post where I explain something like that but using doctrine. In your case the sfGuardUserForm is your somthingFilterForm.
You could also filter data using this method. This is a little more elegant but both would work.

One-To-Many member-to-articles relationship

We are new to Expression Engine and could maybe use some help from anyone who has built a few sites using this CMS.
We have a small dashboard system where users log in and read articles that are submitted from other authors. We are wanting to have a form which allows a member to chose which categories of articles he would like to be on his home page when he logs in. Then we'd like to figure out how to actually create that home page so that only the categories of articles that the user has chosen are visible.
From a DB standpoint this seems to be a one to many relationship between a member and categories, but we don't have a clear idea how to accomplish this inside of EE (without raw PHP/queries), especially using the Member module, since it isn't a channel and doesn't seem to allow creating relationships in the member custom fields.
We looked at creating a custom field for every category type, but there are about 95, and as we add or remove them, it would be extremely cumbersome to try to keep up with them all. Even if we did we still aren't sure how to connect 1 member to many categories or many entries via a category.
We'll update the question later to add some of the code we (if any) that we've come up with
In short, there isn't going to be a built in way to handle this. That isn't to say however that this can't be handled with some modules that are already out there. Let me ask you this. When you have users logging in, are they logging in to Expression Engine itself's backend, or the login system that you have created on a public facing website.

Categories