在我的项目(BtoB 项目)中,我有一个全局应用程序,里面有很多模块。 每个模块都为我的所有客户提供通用功能。
我还在根目录中有一个客户文件夹,在其中,我在他们的文件夹中有所有客户的特殊性。 这些文件夹不是模块。所以他们没有加载 Zf2。我通常使用 abstractFactories 加载这些特性。
这个架构遵循的是我目前拥有的:
- clients
- clientOne
- Invoice
- Cart
- Orders
- clientTwo
- Invoice
- Orders
- clientThree
- Reporting
- module
- Application
- CartModule
- InvoiceModule
- OrdersModule
- Reporting
我的客户想要一些自定义 View ,有时,他们要求我们提供这些 View 。但是我的应用程序为所有这些提供了一个共同的观点。我必须修改此架构以加载客户端 View (如果存在)或加载公共(public) View 。
为了处理这种情况,我想象在每个客户文件夹中都有这个:
- client
- clientOne
- Invoice
- Cart
- View
- cartView.phtml
- Orders
编辑:
在一些好的答案(@AlexP 和@Wilt)之后,我尝试实现这个解决方案:
所以我有一个 ClientStrategy;它的工厂是这样的:
<?php
namespace Application\View\Strategy;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\View\Resolver\TemplateMapResolver;
use Zend\View\Resolver;
class ClientStrategyFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$viewRenderer = $serviceLocator->get('ViewRenderer');
$session = new \Zend\Session\Container('Session');
$map = $serviceLocator->get('config')['view_manager']['template_map'];
$resolver = new Resolver\AggregateResolver();
$map = new TemplateMapResolver($map, $this->clientMap($session->offsetGet('cod_entprim')));
$resolver
->attach($map)
->attach(new Resolver\RelativeFallbackResolver($map));
$viewRenderer->setResolver($resolver);
return new ClientStrategy($viewRenderer);
}
/**
* permet de retourner le namespace du client selectionné avec la relation codpriml / nom de dossier
* @return array
*/
public function clientMap($codprim)
{
$clients = array(
21500 => 'clientOne',
32000 => 'clientTwo',
// ..
);
return (isset($clients[$codprim])) ? $clients[$codprim]: false;
}
}
我的 clientMap 方法允许我加载我的客户端文件夹,并且它可能包含这样的 View :
class ClientOne
{
/**
* get The main Code
* @return integer
*/
public function getCodEntPrim()
{
return 21500;
}
/**
* Load all customs views
* @return array
*/
public function customViews()
{
return array(
'addDotations' => __DIR__ . '/Dotations/view/dotations/dotations/add-dotations.phtml',
);
}
/**
* GetName
* @return string
*/
public function getName()
{
return get_class();
}
}
因此,当涉及到我的 TemplateMapResolver 来完成他的工作时,我会这样做:
<?php
namespace Application\View\Resolver;
class TemplateMapResolver extends \Zend\View\Resolver\TemplateMapResolver
{
/**
* Client name to use when retrieving view.
*
* @param string $clientName
*/
protected $clientName;
/**
* Merge nos vues avec celle clients avant de repeupler l'arrayMap global
* @param array $map [description]
*/
public function __construct(array $map, $client)
{
$this->setClientName($client);
if ($this->getCLientName()) {
$map = $this->mergeMap($map);
}
parent::__construct($map);
}
/**
* Merge les map normales avec les map clients, pas propre ?
* @param array $map
* @return array
*/
public function mergeMap($map)
{
$name = $this->getClientName() . '\\' . $this->getClientName() ;
$class = new $name;
$clientMap = $class->customViews();
return array_replace_recursive($map, $clientMap);
}
/**
* Retrieve a template path by name
*
* @param string $name
* @return false|string
* @throws Exception\DomainException if no entry exists
*/
public function get($name)
{
return parent::get($name);
}
/**
* Gets the Client name to use when retrieving view.
*
* @return string
*/
public function getClientName()
{
return $this->clientName;
}
/**
* Sets the Client name to use when retrieving view.
*
* @param mixed $clientName the client name
*
* @return self
*/
public function setClientName($clientName)
{
$this->clientName = $clientName;
return $this;
}
}
我尝试了很多东西,这很有效,但出现了一些问题:
- My template_path_stack not works anymore, so a lot of my views are broken.
- I think this is a complete mess, to do this, that way.
- Hard to maintain.
- I understand a bit better, how it works, but i'm still unable to implements it the good way.
最佳答案
如果你真的想这样做(我不太确定这是否是最好的方法)那么你可以用你的自定义逻辑扩展 TemplateMapResolver 并将它设置在你的 Renderer 实例。
创建自定义类:
<?php
Application\View\Resolver
class TemplateMapResolver extends \Zend\View\Resolver\TemplateMapResolver
{
/**
* Client name to use when retrieving template.
*
* @param string $clientName
*/
protected $clientName;
/**
* Retrieve a template path by name
*
* @param string $name
* @return false|string
* @throws Exception\DomainException if no entry exists
*/
public function get($name)
{
if ($this->has($clientName . '_' . $name)) {
return $this->map[$clientName . '_' . $name];
}
if (!$this->has($name)) {
return false;
}
return $this->map[$name];
}
}
现在是这样的:
$resolver = new TemplateMapResolver();
$resolver->setClientName($clientName);
// Get the renderer instance
$renderer->setResolver($resolver);
您可能仍然需要注意在解析器中设置 map 。也许您可以从旧的解析器中获取它?我不确定……那是你要找出来的。这只是为了让您走上正确的道路。
因此,如果您将 cart_view 设置为模板,它将首先尝试获取 client_name_cart_view,如果未找到,则设置 cart_view。
如果您想将其提升到一个新的水平,那么您可以做一个自定义 View 模型,例如扩展普通 ViewModel 类的 ClientViewModel。< br/="">
此 ClientViewModel 的构造函数同时采用客户端名称和模板名称:
new ClientViewModel($client, $template, $variables, $options);
$variables 和 $options 是可选的,可以传递给 parent::__construct(普通 ViewModel 的构造函数)
下一步是创建一个 Application\View\ClientStrategy。
此策略与渲染事件相关联,在此策略中,您添加了一个带有自定义 TemplateMapResolver 集的 ViewRenderer 实例。在呈现期间,您可以从 ViewModel 获取客户端,并使用此客户端在 TemplateMapResolver 中找到正确的模板。
更多的细节可以在网上找到,有例子。例如检查 here .
优点是其他带有 ViewModel 或 JsonModel 的 View 将正常呈现,只有您的 ClientViewModel 得到特殊处理。因此,您不会破坏应用程序的默认逻辑。
关于php - 在默认 View 之前加载客户端 View (如果存在),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34224353/
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat