ZF2 - BjyAuthorize - How to Get Rules and Guards from a Database - zend-framework2

I'm using BjyAuthorize with Zend Framework2 to implement authorization and was able to successfully integrate roles from database. Now I want to get my Rules and Guards also from data base tables. How can I do this?

The easiest method and "the trick" here is really to:
Get your rules and guards into the same array format as it is shown in example configuration. So after reading records from the database, in whatever format your raw database data is, process it to match the same guard format as in the configuration. (My answer goes into detail on how to do that with Doctrine ORM, but also should give you an idea with other DB engines. Just substitute "DB read" operation with your fave database engine)
Inject the rules that are already in the proper format BjyAuthorize expects (because you made them so), into BjyAuthorize\Guard\Controller, from within YOUR_MODULE_NAME\Factory\DoctrineControllerGuardAdapterFactory, which you will write. Bjy's Controller will treat the rules as if those rules came from configuration*, and not suspect any difference.
Step back and enjoy!
This is the construct that you need to write in your own module:
namespace YOUR_MODULE_NAME\Factory;
/**
* See "How and where exactly to register the factory" in ZF2 config
* below in my answer.
*/
class [Custom]ControllerGuardAdapterFactory
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
/**
* Retrieve your rules from favorive DB engine (or anything)
*
* (You may use $serviceLocator to get config for you DB engine)
* (You may use $serviceLocator to get your DB engine)
* (You may use $serviceLocator to get ORM Entity for your DB engine)
* (Or you may hack your DB connection and retrieval in some other way)
*
* Hell, you may read them from a text file using PHP's file() method
* and not use $serviceLocator at all
*
* You may hardcode the rules yourself right here for all that matters
*/
$rules = ... //array(...);
/**
* Inject them into Bjy's Controller
*
* Rules must be in the same format as in Bjy config, or it will puke.
* See how ['guards'][\BjyAuthorize\Guard\Controller::class] is constructed
* in Bjy configuration for an example
*/
return new \BjyAuthorize\Guard\Controller($rules, $serviceLocator);
}
}
Now watch and observe how mind-numbingly complicated this can be made! (modeled after Bjy's own mechanisms)
This is mostly just ZF2, OO & Bjy "Configuration Hell", folks, nothing special otherwise. Welcome to ZF2 and Bjy and ORM Configuration Hell. You are welcome.
Detailed Answer - How to Implement?
Write an adapter factory, which reads rules from database, and then injects them into BjyAuthorize's Controller Guard. The effect will be the same as if the rules were being read from ['guards'][\BjyAuthorize\Guard\Controller::class]
What?
The way BjyAuthorize's Controller Guard works is it takes rules in a certain format (format specified for ['guards']['BjyAuthorize\Guard\Controller']), and then it uses the rules to populate the ACL. It also computes Resources from rules for you and loads those into ACL as well. If it didn't, you would have to write your own Resource Provider to do so.
So the task becomes:
Load rules from database and Transform the rules to format BjyAuthorize expects. This can be done in your own Rule Provider, much like this one.
You can use a factory to load your particular DB and storage class configuration arrays from module.config.php file. I put mine under ['guards']['YOUR_MODULE_NAME_controller_guard_adapter'].
'guards' => array(
'YOUR_MODULE_NAME_controller_guard_adapter' => array(
'object_manager' => 'doctrine.entity_manager.orm_default',
'rule_entity_class' => 'YOUR_MODULE_NAME\Entity\ObjectRepositoryProvider'
)
)
(cont) I put it under guards as opposed to rule_providers, because what we are dealing with here is not a pure rule provider. It is a guard provider, or "an adapter that gets rules out of your ObjectRepositoryProvider, and injects them into controller guard". This factory should look similar to this, except that you will be loading rules, not roles. You will then be injecting the rules into Controller, as in the next step.
Inject the rules into Controller, very much like it is done here
Example Implementation Details (from Q/A in comments)
More on the last point of "Injecting rules into Controller". Basically two steps: 1) make sure you already have (or will) generate your rules somehow (that's the hard step ). 2) inject those rules into controller (that's the easier step). The actual injection is done like this
$rules = __MAGIC__; //get rules out of somewhere, somehow.
return new Controller($rules, $serviceLocator); //$rules injection point
See code block below for my own implementation, where the last line in the block is the line I gave just above here.
namespace YOUR_MODULE_NAME\Factory;
use BjyAuthorize\Exception\InvalidArgumentException;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use YOUR_MODULE_NAME\Provider\Rule\DoctrineRuleProvider; //this one's your own
use BjyAuthorize\Guard\Controller;
class DoctrineControllerGuardAdapterFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
//just setting up our config, move along move along...
$config = $serviceLocator->get('Config');
$config = $config['bjyauthorize'];
//making sure we have proper entries in our config...
//move along "nothing to see" here....
if (! isset($config['guards']['YOUR_MODULE_NAME_controller_guard_adapter'])) {
throw new InvalidArgumentException(
'Config for "YOUR_MODULE_NAME_controller_guard_adapter" not set'
);
}
//yep all is well we load our own module config here
$providerConfig = $config['guards']['YOUR_MODULE_NAME_controller_guard_adapter'];
//more specific checks on config
if (! isset($providerConfig['rule_entity_class'])) {
throw new InvalidArgumentException('rule_entity_class not set in the YOUR_MODULE_NAME guards config.');
}
if (! isset($providerConfig['object_manager'])) {
throw new InvalidArgumentException('object_manager not set in the YOUR_MODULE_NAME guards config.');
}
/* #var $objectManager \Doctrine\Common\Persistence\ObjectManager */
$objectManager = $serviceLocator->get($providerConfig['object_manager']);
//orp -- object repository provider
//here we get our class that preps the object repository for us
$orp=new DoctrineRuleProvider($objectManager->getRepository($providerConfig['rule_entity_class']));
//here we pull the rules out of that object we've created above
//rules are in the same format BjyAuthorize expects
$rules=$orp->getRules();
//here pass our rules to BjyAuthorize's own Guard Controller.
//It will not know the difference if we got the rules from Config or from Doctrine or elsewhere,
//as long as $rules are in the form it expects.
return new Controller($rules, $serviceLocator);
}
}
DoctrineRuleProvider
namespace YOUR_MODULE_NAME\Provider\Rule;
use Doctrine\Common\Persistence\ObjectRepository;
use BjyAuthorize\Provider\Rule\ProviderInterface;
/**
* Guard provider based on a {#see \Doctrine\Common\Persistence\ObjectRepository}
*/
class DoctrineRuleProvider implements ProviderInterface
{
/**
* #var \Doctrine\Common\Persistence\ObjectRepository
*/
protected $objectRepository;
/**
* #param \Doctrine\Common\Persistence\ObjectRepository $objectRepository
*/
public function __construct(ObjectRepository $objectRepository)
{
$this->objectRepository = $objectRepository;
}
/**
* Here we read rules from DB and put them into an a form that BjyAuthorize's Controller.php understands
*/
public function getRules()
{
//read from object store a set of (role, controller, action)
$result = $this->objectRepository->findAll();
//transform to object BjyAuthorize will understand
$rules = array();
foreach ($result as $key => $rule)
{
$role=$rule->getRole();
$controller=$rule->getController();
$action=$rule->getAction();
if ($action==='all') //action is ommitted
{
$rules[$controller]['roles'][] = $role;
$rules[$controller]['controller'] = array($controller);
}
else
{
$rules[$controller.':'.$action]['roles'][]=$role;
$rules[$controller.':'.$action]['controller']=array($controller);
$rules[$controller.':'.$action]['action']=array($action);
}
}
return array_values($rules);
}
}
Q: How and where exactly to register the factory DoctrineControllerGuardAdapterFactory
A: Try this path: module\YOUR_MODULE_NAME\config\module.config.php and have
'service_manager' => array(
'factories' => array(
'YOUR_MODULE_NAME_controller_guard_adapter' => \YOUR_MODULE_NAME\Factory\DoctrineControllerGuardAdapterFactory::class
)
)
Note: YOUR_MODULE_NAME. The thing on the left of => sign is "the key", and can be anything you want it to be. Convention in Bjy is that it is similar to the actual class names and paths. And the thing on the right of the => is the actual fully qualified namespace to the class that you want to call with with this key.

Basically you have to write your own Provider.
Check out the different RoleProvider. Every RoleProvider implements the Provider\Role\ProviderInterface. The same thing has to be done when you want to implement Guards and Rules. You go into the specific directories Provider\Rule and Provider\Resource and check for the specific ProviderInterface.
That way you can write your own class implementing the Interface and then via configuration you tell BjyAuthorize to use your provider-classes.
As far as Guards are concerned, i do believe it is not yet possible to create those from Database. You would have to modify / PR the Module itself to make that happen.

Related

Provide new instances of model class for dependency injection in Angular 2

I have a class that serves as a model for some data I get from a server. This data starts as an unwieldy xml object where text nodes have attributes so the json format I convert it into does not have simple string values. Instead I have:
#Injectable()
export class FooString {
_attr: string;
value: string;
isReadOnly(): boolean {
return this._attr && this._attr === 'ReadOnly';
}
isHidden(): boolean {
return this._attr && this._attr === 'Hid';
}
}
Then my model is like:
#Injectable()
export class Payment {
constructor(
public FooId: FooString,
public FooStat: FooString,
public FooName: FooString ) { }
}
Everything ends up with the same instance of FooString. How do I get discrete instances for each of them?
I have tried a factory, but it still only creates a single instance:
export let fooStringProvider = provide(FooString, {
useFactory: (): FooString => {
console.log('in foostring factory');
return new FooString();
}
});
new FooString();
new Payment();
;-)
Why using DI when they don't have dependencies and you don't want to maintain single instances per provider. Therefore, just use new.
When to use DI
There are a few criterias when using DI instead of new the right thing:
If you want Angular to maintain and share instances
If you want to work with an interface or base class but then you want to configure from the outside what implementation should actually be used at runtime - like the MockBackend for Http during testing.
If you class has dependencies to instances and/or values provided by DI
If you want to be able to easily test classes in isolation (https://en.wikipedia.org/wiki/Inversion_of_control)
probably others ...
If there are good arguments to use DI, but you also want new instances then you can just provide a factory.
This answer https://stackoverflow.com/a/36046754/217408 contains a concrete example how to do that.
Using DI is usually a good idea. There are IMHO no strong arguments against using DI. Only when none of the above arguments apply and providing factories is too cumbersome, use new Xxx() instead.

Inject ServiceLocator in Validator

How can I inject the "normal" ServiceManger into a custom validator used for REST calls (Use without Form). ZF 2.2.7 Used to inject an instance of external library into an validator.
I have tried the following, and nothing works:
Inject it with the ValidationPluginManager, service not found
Inject it via factory, factory will not be loaded in validator chain
Inject it via validator options, not possible because the "ServiceManager" is an instance of ValidationPluginManager with the asme result as mentioned in #1
Is there any concept how to solve this problem, or do i have to give up and link all libraries statically?
Not tested this and have never done with with ValidationPluginManager but works with ControllerManager, FormElementManager etc
// GetServiceLocator call should return Instance of ServiceManager
// Then retrieve the service, Yay!
$validationPluginManager->getServiceLocator()->get('SomeService')
There has been a discussion on github about a somewhat similar problem here. They suggested to use Zend\Form\FormAbstractServiceFactory and tinker with dependencies there (weierophinney before closing the topic).
In your post you mention you are not using a form did you mean you are not using the form in a classic kind of way or are you bypassing the whole form in particular?
It simply seems off to me to use a validator if there isn't a form present. Could you elaborate more on that?
EDIT: To my understanding zf2 requires that your input filters have form elements like 'inputs' etc. You did not post any code and I simply do not know if/or your able to bypass this somehow. I still do not understand why you'd still want to use validators in combination of input filters. I would simply skip the input filters and write the custom validator.
My personal preferences is to write factories instead of anonymous functions within module.php files. But this also could work the anonymous function way.
I would then simply resolve the dependencies within the customValidatorFactory and get the factory within my controller or whatever place I would need it.
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use CustomValidator;
class CustomValidatorFactory implements FactoryInterface
{
/**
* Create Service Factory
*
* #param ServiceLocatorInterface $serviceLocator
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$sm = $serviceLocator->getServiceLocator();
$customService = $sm->get('Application\Service\Geocoding');
$validator= new CustomValidator();
$validator->setCustomService($service);
return $validator;
}
}
// CustomValidator.php
class CustomValidator extends Zend\Validator\AbstractValidator
{
public function setCustomService($service)
{
$this->service = $service;
}
public function isValid($value)
{
$customService = $this->service;
if ($customService->customMethod() == true) {
return true;
}
return false;
}
}
//module-config.php
'service_manager' => array(
'factories' => array(
'custom\ValidatorFactory' => 'Namespace\To\CustomValidatorFactory',
),
),
//yourController or whatever.php will require access to the service manager
$customValidation = $sm->get('custom\ValidatorFactory');
// should return true or false now
$state = $customValidation->isValid($someValue);

Routing nested controllers using IoC for dependency injection in laravel 3

update: if i can achieve same result using a different approach, please enlighten me.
I'm using/learning laravel 3 while building my project. Before coding any page-content at all, I'm verifying if i can deploy everything as planned, since this project is an actual rewrite of a rather huge app which is seriously outdated in the techniques it uses.
I'm struggling at this last part, which is quite possibly the hardest challenge i'll face to setup my project.
URL:
site.com/shops/__identifier__/controller/action/params
The above is the uri i'm trying to code atm.
The _identifier_ part should become a model (eloquent based)
the shops is the base for nested controllers
ie:
controllers/
- shops/
- home.php
- contact.php
- products.php
- etc ....
Each existing uri shops/identifier is a real site on its own. (though it has a different domain offcourse)
I want all my nested shops controllers to know what shop they're working with. In fact, the identifier will be used to load the correct layouts, to render the correct images, contact details etc...
From what i've read, i'll need to use the IoC functionality to inject the dependency of my shop-model into the constructor of my controller.
this is what i have atm:
file:application/start.php
/**
* Register IoC container for my nested shop controllers
*/
IoC::register('controller: shop', function($controller, $identifier)
{
//also tried using same line without the \\
$class = '\\Shops_' . ucfirst($controller) . '_Controller';
return new $class($identifier);
});
file:application/routes.php
/**
* Register all shop routes
*/
Route::any('/shops/(:any)/(:any?)/(:any?)', function($identifier, $controller = "home", $method = "index", $params = array()){
if($controller === "index")
$controller = "home";
$controller = IoC::resolve('controller: shop', array($controller, $identifier));
return $controller;
});
shop base-controller located at application/libraries/controllers/shop.php
<?php
namespace Controllers;
use Base_Controller;
/**
* Shop controller
*/
class Shop extends Base_Controller
{
public function __construct($identifier){
/**
* #todo: load the shop model using the identifier
* possibly move this after the parent::__construct()
*/
parent::__construct();
}
}
file: applications/controllers/shops/home.php
<?php
/**
* #heads up: Shop_Controller is aliased in application/config/application.php
*/
class Shops_Home_Controller extends Shop_Controller
{
public function get_index(){
return ('test');
}
}
Problems:
when defining my routes for these nested shops controllers. Do i simply return the controller laravel should use to resolve the request, or do i trigger the action myself in the callback function in that route definition?
controllers aren't autoloading (when trying the implementation above), yet i'm using the correct conventions for those controllers (unless i'm missing something :-) ). I'm guessing this is because i'm using IoC, how do i cleanly implement this or what is my mistake?
how do i trigger the correct action? It should, as expected, trigger the corresponding HTTP-verb action, since my nested controllers are also RESTFUL-controllers.
extra question to keep things as clean as possible: 'index' defaults to home controller when not using IoC functionality. Is my solution (if-condition in routes.php) to mimic this functionality a clean one? or is there any better approach?
By all means:
If my approach is way off, please tell me, i'm a newbie at laravel, and it's the first framework i'm using, so i'm a newbie at frameworks in general.
I'd also like to apologize if my question isn't explained to well so feel free to ask extra info.
I tried my best at googling this problem, but couldn't find anything similar, which is a first, since all my other laravel problems were easily solved using google.
I'd kindly thank anyone taking the time to read this and even better send me in the right direction!
Ok, final solution, this is far from clean if you ask me, but it seems to work, at least as far as i've checked.
I'm also not to sure if there is an alternative, but due to lack of response and timepressure, i decided to go with this and keep fingers crossed :(.
//start.php
IoC::register('controller: shop', function($id, $controllerName){
//controller name is the name of the controller located in the shops map
$class = "Shops_" . ucfirst($controllerName) . "_Controller";
include(path('app') . 'controllers/shops/' . strtolower($controllerName) . '.php');
return new $class($id);
});
//routes.php
Route::any("shops/(:any)/(:any?)/(:any?)/(:all?)", function($id, $controller = "index", $action = "index", $params = ""){
if($controller === "index")
$controller = "home";
$params = explode('/', $params);
$controller = IoC::resolve("controller: shop", array($id, $controller));
$http_verb = Request::method();
/**
* Need to return this, and i now need to manually return every response in every action in every shop controller
*/
return call_user_func_array(array($controller, $http_verb . '_' . $action), $params);
});
so example given
class Shops_Home_Controller extends Shop_Controller
{
public function get_index(){
/**
* this works when doing things the usual way, but will not return any output
* when working with nested dependency injection
*/
$this->layout->nest('content', 'shops.index');
}
public function get_test(){
/**
* this needs to return layout object if it is to work with the nested dependency injection
*/
$this->layout->nest('content', 'shops.index');
}
}

How do I include or autoload external libraries in a TYPO3 Extbase Extension? + Dependecy Injection?

I'm developing a TYPO3 4.6 Extension with Extbase 1.4 and im trying to include an external library. The library, in my case the facebook PHP SDK, is under $_EXTKEY/Resources/PHP/facebook-php-sdk/facebook.php. I would like the library to autoload and automatically inject (Dependecy Injection) where I need it.
Some comments I found online suggest that one should include libraries with require_once():
http://forge.typo3.org/issues/33142
if it's just a tiny helper library, it's intended to be stored in {PackageRoot}/Resources/PHP/{libraryName} and just included via require. is this suspected by the problem however?
if the FLOW3 package mainly represents the foreing library at all, like it's the case in Imagine or Swift package, the library code is put below {PackageRoot}/Classes directly."
http://lists.typo3.org/pipermail/typo3-project-typo3v4mvc/2011-July/009946.html
"I would include the class (using require_once) from within a specific action to handle this. That way you have access over those functions and the class becomes your library."
I tried this and it works like this:
<?php
require_once( t3lib_extMgm::extPath('extkey') . 'Resources/PHP/facebook-php-sdk/facebook.php');
class Tx_WsLogin_Domain_Repository_FacebookUserRepository extends Tx_WsLogin_Domain_Repository_UserRepository {
protected $facebook;
public function __construct() {
$this->setFacebook(new Facebook(array(
'appId' =>'',
'secret' => '')
));
parent::__construct();
}
public function setFacebook(Facebook $facebook) {
$this->facebook = $facebook;
}
public function sampleFunction() {
$userId = $this->facebook->getUser();
}
}
?>
But how can I get it to autoload and automatically inject the library with the injectFacebook function?
edit:
Like #alex_schnitzler and #sorenmalling mentioned about autoloading:
#PeterTheOne Put all the files inside ext_autoload.php and then use DI or the object manager.
#PeterTheOne put the class definition into ext_autoload.php in your extension?
I tried it like this (file: ext_autoload.php):
<?php
$extPath = t3lib_extMgm::extPath('extKey');
return array(
'facebook' => $extPath . 'Resources/PHP/facebook-php-sdk/facebook.php',
);
?>
It seems to find and include the right file. But when I try to user Dependency Injection (like peter answered) I get an error:
not a correct info array of constructor dependencies was passed!
InvalidArgumentException thrown in file /var/syscp/webs/web1/dev/typo3_src-4.5.15/typo3/sysext/extbase/Classes/Object/Container/Container.php in line 247.
I think this is because the constructor of the Facebook class has a required $config argument.
edit2:
I did what peter said in his answer and with the help of #alex_schnitzler and #sorenmalling, who pointed me to the ObjectManager, my FacebookService looks like this now:
class Tx_Extkey_Service_FacebookService implements t3lib_Singleton {
/**
* #var Tx_Extbase_Object_ObjectManagerInterface
*/
protected $objectManager;
/**
* Facebook from #link https://github.com/facebook/facebook-php-sdk facebook-php-sdk
*
* #var Facebook
*/
protected $facebook;
/**
* #param Tx_Extbase_Object_ObjectManagerInterface $objectManager
*/
public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
$this->objectManager = $objectManager;
}
/**
*
*/
public function initializeObject() {
$this->facebook = $this->objectManager->create(
'Facebook',
array(
'appId' =>'input appId here',
'secret' => 'input app secret here'
)
);
}
/**
* #return Facebook
*/
public function getFacebook() {
return $this->facebook;
}
}
For more help read: http://forge.typo3.org/projects/typo3v4-mvc/wiki/Dependency_Injection_(DI) the parts about initializeObject() and Creating Prototype Objects through the Object Manager
First create ext_autoload.php in extension root folder
and add your code,it contain single dimension array with key as class name(class name must be prefix with extension key) and value as path to file.
make sure clear your site
<?php
$extensionPath = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('rent_system');
return array(
'rent_system_TCPDF' => $extensionPath.'Resources/Private/PHP/tcpdf/tcpdf.php',
);
?>
In controller file
$pdf = $this->objectManager->create('rent_system_TCPDF');
Extbase injection is pretty simple. Here's the actual implementation. Using external libraries, however, is not.
Once you figure out how to load the library, have you tried just injecting it? Like so:
/**
* #var Facebook
*/
protected $facebook;
/**
* inject the facebook
*
* #param Facebook facebook
* #return void
*/
public function injectFacebook(Facebook $facebook) {
$this->facebook = $facebook;
}
NOTE: You need the #param in the comment and you also need to clear your configuration cache after adding this code.
I don't know about the Facebook SDK API, but hopefully you can instantiate the Facebook object with the default constructor and then add the arguments later with setter methods. You might want to create a FacebookService class (singleton) that loads the Facebook PHP and sets the essential arguments. Then you can inject a FacebookService to get the actual Facebook object whenever you need it.

Symfony: Sharing a partial between two component actions

I have a component that has been happily building and rendering menus for a while now. Now I have to provide for a special case that shares all of the same logic, but requires a little bit of work in front of what already exists. What I'd like to do is create a new component action that will do the necessary preprocessing, punt to shared logic to complete the computational side and then render through the existing template partial (when all is said and done, it's still a menu like any other--it just take a little more work to build it).
Unfortunately, I can't find any way of doing this.
Here's the high level file/code breakdown that I have right now:
#
# navigation/actions/components.class.php
#
public function executeMenu() {
/**
* This method runs most of the menus and does most of the work
* that's required of the special case.
*
* Once complete, of course, it renders through navigation/templates/_menu.php
*/
}
public function executeSpecialMenu() {
/**
* Do some preparatory work and delegate to executeMenu()
* to finish up and render the menu. I'd like this action
* to render through the _menu.php partial as well.
*/
}
#
# templates/layout.php
#
<?php include_component( 'navigation', 'menu', array( 'menu' => 'Entity Type' ) ) ?>
/** SNIP */
<?php include_component( 'navigation', 'SpecialMenu' ) ?>
Any input would be much appreciated.
A simple if non-optimal way would be to create the _SpecialMenu.php partial and just place an include inside it:
<?php include_partial('navigation/menu', array('menu' => 'Entity Type', 'other_var' => $other_var) ?>
Where each of your variables will need to be passed to the partial as in $other_var. Does this at least solve the problem?
A more elegant solution is to use the get_partial inside the "second" component's execute function, like so:
public function executeSpecialMenu() {
//forces SpecialMenu to render _menu.php
echo get_partial('menu', $this->varHolder->getAll());
return sfView::NONE;
}
The call to varHolder->getAll gets all the variables that were going to be passed to the "normal" partial, since get_partial requires that.
Or, as a new method:
public function executeSpecialMenu() {
return $this->renderAlternatePartial('menu');
}
protected function renderAlternatePartial($partial) {
echo get_partial($partial, $this->varHolder->getAll());
return sfView::NONE;
}
Also there exists a renderPartial('xxx') method in the action class which is useful when it is needed to generate a part without template in cases such as XmlHttpRequest s:
if ($request->isXmlHttpRequest())
{
return $this->renderPartial('module/action', array('param' => 'value'));
}
I haven't tested if this works in the component execute methods. If this does not work it is a good idea to add such a functionality to symfony sfComponent class.
In the action/template mode, there exists a $this->setTemplate('xxx') method (in the action class) which can use a same template for different actions. (e.g same template for new or edit actions). Would that there was such a method in the component classes.
I wouldn't recommend to use different actions to render the same entity. Try to combine them and call a component with different parameters, and if it is heavy, move all the logic to a separate class.

Resources