YIMP - Panel de control para Yii 2 en Bootstrap 4

Estoy seguro de que muchos desarrolladores que prefieren frameworks a CMS ya preparados tienen en stock una solución en Bootstrap o sus análogos, que se utiliza para crear interfaces de administración y otras interfaces de back-office. Y lo tengo Ha funcionado con éxito durante muchos años, pero está desactualizado irremediablemente. Es hora de reescribir.


Mientras trabajaba en la nueva versión, traté de resumir toda mi experiencia en este tema, y ​​como resultado obtuve YIMP, una bicicleta que no me da vergüenza compartir: GitHub , LiveDemo , Documentación API .


YIMP es muy simple. Pero detrás de esta simplicidad hay un pensamiento largo, que también quiero compartir. Entonces este artículo no es una instrucción. Aquí hablamos sobre arquitectura, gestión de dependencias, el paradigma MVC y la interfaz de usuario, por supuesto.


Entonces, YIMP es un tablero de instrumentos. Este no es un panel de administración listo, ni un CMS o incluso un CMF. El código de representación debe escribirse de forma independiente o usar Gii (se adjuntan plantillas). YIMP proporciona un diseño que define dónde deben ubicarse los controles, así como la interfaz a través de la cual la aplicación transfiere datos al diseño. Así es como se ve en los escritorios:



Diseño adaptativo. A medida que la pantalla se encoge, los elementos comienzan a desaparecer o moverse sobre los botones en la barra de navegación. Como resultado , la misma página en el teléfono se ve así:


Mejor déjalo estar debajo del spoiler

¿Qué vemos en el diseño? El título de la aplicación, migas de pan, tres menús (izquierdo, derecho y superior), widgets en las barras laterales, título de la página. En mi práctica, este conjunto de elementos fue suficiente para desarrollar cualquier interfaz, desde las páginas de administración de las páginas de destino hasta los sistemas de información corporativos. Traté de organizarlos para que el espacio se utilizara de la manera más eficiente posible. Que dices


El marcado está escrito en Bootstrap puro, sin extensiones y personalización. Siempre que fue posible, se usaron las clases de Bootstrap, por lo que si decide utilizar la personalización, no debería haber problemas.


Como dije, YIMP incluye una interfaz a través de la cual la aplicación transfiere datos al diseño. Veamos cómo sucede esto. ¡Abre el capó!


Diseño


Creo que el desarrollador debe tener un control total sobre el diseño, por lo que al instalar YIMP, recomiendo copiar su código en su aplicación. En mi opinión, esto es mucho mejor que dejar un diseño en el paquete y bloquear un montón de configuraciones para ello. Veamos el código de diseño:


77 líneas de código. ¡No es necesario profundizar!
<?php use dmitrybtn\yimp\widgets\Alert; use dmitrybtn\yimp\Yimp; use yii\bootstrap4\Html; $yimp = new Yimp(); $yimp->register($this); /** @var string $content Content came from view */ ?> <?php $this->beginPage() ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="<?= Yii::$app->charset ?>"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <?php echo Html::csrfMetaTags() ?> <title><?php echo Html::encode($yimp->nav->getTitle()) ?></title> <?php $this->head() ?> </head> <body> <?php $this->beginBody() ?> <?php echo $yimp->navbar() ?> <?php echo $yimp->beginSidebars() ?> <?php echo $yimp->beginLeftSidebar() ?> <?php echo $yimp->beginLeftSidebarMenu() ?> <?php echo $yimp->menuLeft([ 'options' => ['class' => 'nav-pills flex-column border rounded py-2'] ]) ?> <?php echo $yimp->endLeftSidebarMenu() ?> <?php if (isset($this->blocks[$yimp::SIDEBAR_LEFT])): ?> <?php echo $this->blocks[$yimp::SIDEBAR_LEFT] ?> <?php endif ?> <?php echo $yimp->endLeftSidebar() ?> <?php echo $yimp->beginRightSidebar() ?> <?php echo $yimp->beginRightSidebarMenu() ?> <?php echo $yimp->menuRight([ 'options' => ['class' => 'nav-pills flex-column border rounded py-2'] ]) ?> <?php echo $yimp->endRightSidebarMenu() ?> <?php if (isset($this->blocks[$yimp::SIDEBAR_RIGHT])): ?> <?php echo $this->blocks[$yimp::SIDEBAR_RIGHT] ?> <?php endif ?> <?php echo $yimp->endRightSidebar() ?> <?php echo $yimp->endSidebars() ?> <?php echo $yimp->beginContent() ?> <?php echo $yimp->headerDesktop() ?> <?php echo Alert::widget() ?> <?php echo $content ?> <?php echo $yimp->endContent() ?> <?php if (isset($this->blocks[$yimp::FOOTER])): ?> <?php echo $this->blocks[$yimp::FOOTER] ?> <?php endif ?> <?php $this->endBody() ?> </body> </html> <?php $this->endPage() ?> 

Como puede ver, todo el marcado YIMP está envuelto en métodos. La mayoría de estos métodos simplemente imprimen las líneas que se toman de esta matriz . Sí, el principio KISS es nuestro todo.


Tenga en cuenta que los bloques se utilizan en el diseño. Son necesarios para mostrar widgets definidos en vistas (así es como se representan los controles de formulario). Bueno, si el widget se cuelga en todas las páginas, es mejor determinarlo directamente en el diseño.


Entonces, el área principal y los widgets se definen en las vistas. ¿Y dónde se determinan los títulos, los menús y las migas de pan? En mi opinión, se definen mejor en los controladores. Este es un punto importante, ya que tal decisión contradice el paradigma MVC. Veamos este problema con más detalle.


Controladores


Entonces, permita que haya un ProfileController que pueda mostrar información sobre el perfil del usuario actual y cambiar la contraseña. Lógicamente, la acción de profile/view se llamará "Mi perfil". También es lógico que en el menú principal debe haber un elemento "Mi perfil". Finalmente, "Mi perfil" debe estar en migas de pan: "Inicio / Mi perfil / Cambiar contraseña". Creo que el deseo de definir una constante con las palabras "Mi perfil" está bastante justificado. No puede hacer esto en la vista. Seleccionar una capa separada para encabezados es engorroso. Razonando así, llegué a los controladores.


El siguiente paso fue la decisión de definir no solo encabezados de acción en los controladores, sino también migas de pan y menús. Y hazlo para que YIMP pueda leerlos. Y aquí necesitamos un ejemplo. Veamos una posible implementación de la clase ProfileController .


52 líneas de código simple. ¡Mejor mirar con cuidado!
 class ProfileController extends \yii\web\Controller { public $nav; public function init() { parent::init(); $this->nav = new \dmitrybtn\yimp\Navigator; } public static function titleView() { return ' '; } public static function titlePassword() { return ' '; } public static function crumbsToView() { return [ ['label' => static::titleView(), 'url' => ['/profile/view']] ]; } public function actionView() { $this->nav->title = static::titleView(); $this->nav->menuRight = [ ['label' => ''], ['label' => static::titlePassword(), ['password']], ]; ... return $this->render('view'); } public function actionPassword() { $this->nav->title = static::titlePassword(); $this->nav->crumbs = static::crumbsToView(); ... return $this->render('password'); } } 

Los encabezados y las migas de pan se definen utilizando métodos estáticos, lo que significa que se pueden usar en cualquier lugar. Por ejemplo, en el menú principal de la aplicación puedes escribir:


 ['label' => ProfileController::titleView(), 'url' => ['/profile/view']], 

¿Por qué exactamente los métodos? Porque mañana se le pedirá en lugar de las palabras "Mi perfil" que muestre el inicio de sesión del usuario actual.


Con pan rallado lo mismo. Supongamos que nuestro usuario tiene una lista de imágenes de las cuales ImageController es responsable. Luego, en la image/create acción de image/create , puede escribir:


  $this->nav->crumbs = ProfileController::crumbsToView(), 

y obtener migas de pan como "Inicio / Mi perfil / Agregar una foto". Por cierto, dado que la acción de image/create se llama "Agregar una imagen", el menú de acción de profile/view deberá corregirse:


  $this->nav->menuRight = [ ['label' => ''], ['label' => static::titlePassword(), ['password']], ['label' => ImageController::titleCreate(), 'url' => ['/image/create']] ]; 

Creo que la idea es comprensible. En mi opinión, esta es una solución simple y efectiva para la cual puedes alejarte del paradigma MVC. Sí, el código del controlador se está haciendo más grande, pero hay un lugar para él en el controlador: no escribimos lógica de negocios allí, ¿verdad? Y sí, estaría muy interesado en conocer su opinión sobre este asunto.


Vamos más lejos Como habrás adivinado, la propiedad nav , definida como \dmitrybtn\yimp\Navigator , se usa para transferir encabezados, menús y migas de pan desde el controlador al diseño. Y esta es otra característica de YIMP.



¿Cómo entran los ajustes en el diseño? Muy simple Durante su inicialización, YIMP verifica la propiedad de nav del controlador actual. Si esta propiedad es legible y es un navegador ( instanceof \dmitrybtn\yimp\Navigator ), se utiliza para mostrar la información correspondiente. El navegador incluye propiedades correspondientes a los elementos de diseño, cuya lista completa es más fácil de ver en la documentación de la API .


En la aplicación, se recomienda crear su propio navegador y definir menús que no dependan de la acción actual (arriba y a la izquierda). Después de eso, en todos los controladores, debe crear la propiedad de nav y definirla como un navegador (puede usar sus manos, puede heredar o puede rastrear). Si es necesario, puede definir varios navegadores.


Este enfoque elimina la relación directa entre YIMP y el controlador. Toda interacción se lleva a cabo a través de un objeto, cuya implementación es controlada por el desarrollador. Es decir, este es el mismo Principio de Inversión de Dependencia de SOLID o Acoplamiento Bajo de GRASP .


Sería ideológicamente correcto usar interfaces, tanto para el controlador como para el navegador. Pero aquí decidí seguir el camino más simple y no saturar el sistema. Al final, DIP no habla de interfaces, sino de abstracciones. Y en este caso, la abstracción es un acuerdo sobre la presencia de cierto tipo de propiedad en una clase particular. Que piensas


La ausencia de una relación directa entre YIMP y el controlador se vuelve importante cuando aparecen módulos en el sistema que no saben nada sobre YIMP. O viceversa: los módulos escritos bajo YIMP se instalan en un sistema que YIMP no utiliza.


En el primer caso, YIMP no verá las propiedades de nav en el controlador. No habrá ningún error, pero sus menús desaparecerán de la pantalla y la ID de acción se usará como título. Como ser Muy simple: si YIMP no puede tomar el navegador del controlador, lo creará a través del contenedor DI utilizando el alias yimp-nav . Con este alias, puede registrar su propio navegador predeterminado, por ejemplo, especificando en la configuración de la aplicación:


  'container' => [ 'definitions' => [ 'yimp-nav' => [ 'class' => '\your\own\Navigator', ] ] ], 

En el segundo caso, el navegador en el controlador estará, pero no habrá nadie para leerlo. En este caso, se recomienda escribir un contenedor para las vistas en el módulo, que adaptará el navegador del controlador actual al formato aceptado en Yii. Es decir, muestre <h1> en el área principal, <title> y las migas de pan pasan por los parámetros Yii::$app->view , y visualice el menú derecho en forma de botones.


Conclusión


YIMP ahora se publica sin una versión. No veo ninguna razón para publicar la versión preliminar, todo es demasiado simple para eso. Creo que es mejor probar un par de semanas en un proyecto real e inmediatamente cambiar a la versión 1.0.0. Así que las críticas, comentarios y ayuda sobre GitHub son bienvenidos.


Y estoy completando un módulo que implementa el control de acceso. Cómo terminar: escribiré.


Como puede ver, no hay nada complicado aquí. Estoy seguro de que muchos de ustedes tienen algo similar en stock. Y estaría muy interesado en saber cómo resuelve la tarea de interfaz de usuario en su área de administración.


Gracias a todos!

Source: https://habr.com/ru/post/466505/


All Articles